netfilter: ebtables: Simplify the arguments to ebt_do_table
[deliverable/linux.git] / net / ipv6 / netfilter / ip6_tables.c
1 /*
2 * Packet matching code.
3 *
4 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
5 * Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
6 * Copyright (c) 2006-2010 Patrick McHardy <kaber@trash.net>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14
15 #include <linux/kernel.h>
16 #include <linux/capability.h>
17 #include <linux/in.h>
18 #include <linux/skbuff.h>
19 #include <linux/kmod.h>
20 #include <linux/vmalloc.h>
21 #include <linux/netdevice.h>
22 #include <linux/module.h>
23 #include <linux/poison.h>
24 #include <linux/icmpv6.h>
25 #include <net/ipv6.h>
26 #include <net/compat.h>
27 #include <asm/uaccess.h>
28 #include <linux/mutex.h>
29 #include <linux/proc_fs.h>
30 #include <linux/err.h>
31 #include <linux/cpumask.h>
32
33 #include <linux/netfilter_ipv6/ip6_tables.h>
34 #include <linux/netfilter/x_tables.h>
35 #include <net/netfilter/nf_log.h>
36 #include "../../netfilter/xt_repldata.h"
37
38 MODULE_LICENSE("GPL");
39 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
40 MODULE_DESCRIPTION("IPv6 packet filter");
41
42 /*#define DEBUG_IP_FIREWALL*/
43 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
44 /*#define DEBUG_IP_FIREWALL_USER*/
45
46 #ifdef DEBUG_IP_FIREWALL
47 #define dprintf(format, args...) pr_info(format , ## args)
48 #else
49 #define dprintf(format, args...)
50 #endif
51
52 #ifdef DEBUG_IP_FIREWALL_USER
53 #define duprintf(format, args...) pr_info(format , ## args)
54 #else
55 #define duprintf(format, args...)
56 #endif
57
58 #ifdef CONFIG_NETFILTER_DEBUG
59 #define IP_NF_ASSERT(x) WARN_ON(!(x))
60 #else
61 #define IP_NF_ASSERT(x)
62 #endif
63
64 #if 0
65 /* All the better to debug you with... */
66 #define static
67 #define inline
68 #endif
69
70 void *ip6t_alloc_initial_table(const struct xt_table *info)
71 {
72 return xt_alloc_initial_table(ip6t, IP6T);
73 }
74 EXPORT_SYMBOL_GPL(ip6t_alloc_initial_table);
75
76 /*
77 We keep a set of rules for each CPU, so we can avoid write-locking
78 them in the softirq when updating the counters and therefore
79 only need to read-lock in the softirq; doing a write_lock_bh() in user
80 context stops packets coming through and allows user context to read
81 the counters or update the rules.
82
83 Hence the start of any table is given by get_table() below. */
84
85 /* Returns whether matches rule or not. */
86 /* Performance critical - called for every packet */
87 static inline bool
88 ip6_packet_match(const struct sk_buff *skb,
89 const char *indev,
90 const char *outdev,
91 const struct ip6t_ip6 *ip6info,
92 unsigned int *protoff,
93 int *fragoff, bool *hotdrop)
94 {
95 unsigned long ret;
96 const struct ipv6hdr *ipv6 = ipv6_hdr(skb);
97
98 #define FWINV(bool, invflg) ((bool) ^ !!(ip6info->invflags & (invflg)))
99
100 if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk,
101 &ip6info->src), IP6T_INV_SRCIP) ||
102 FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk,
103 &ip6info->dst), IP6T_INV_DSTIP)) {
104 dprintf("Source or dest mismatch.\n");
105 /*
106 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
107 ipinfo->smsk.s_addr, ipinfo->src.s_addr,
108 ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
109 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
110 ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
111 ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
112 return false;
113 }
114
115 ret = ifname_compare_aligned(indev, ip6info->iniface, ip6info->iniface_mask);
116
117 if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
118 dprintf("VIA in mismatch (%s vs %s).%s\n",
119 indev, ip6info->iniface,
120 ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
121 return false;
122 }
123
124 ret = ifname_compare_aligned(outdev, ip6info->outiface, ip6info->outiface_mask);
125
126 if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
127 dprintf("VIA out mismatch (%s vs %s).%s\n",
128 outdev, ip6info->outiface,
129 ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
130 return false;
131 }
132
133 /* ... might want to do something with class and flowlabel here ... */
134
135 /* look for the desired protocol header */
136 if((ip6info->flags & IP6T_F_PROTO)) {
137 int protohdr;
138 unsigned short _frag_off;
139
140 protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off, NULL);
141 if (protohdr < 0) {
142 if (_frag_off == 0)
143 *hotdrop = true;
144 return false;
145 }
146 *fragoff = _frag_off;
147
148 dprintf("Packet protocol %hi ?= %s%hi.\n",
149 protohdr,
150 ip6info->invflags & IP6T_INV_PROTO ? "!":"",
151 ip6info->proto);
152
153 if (ip6info->proto == protohdr) {
154 if(ip6info->invflags & IP6T_INV_PROTO) {
155 return false;
156 }
157 return true;
158 }
159
160 /* We need match for the '-p all', too! */
161 if ((ip6info->proto != 0) &&
162 !(ip6info->invflags & IP6T_INV_PROTO))
163 return false;
164 }
165 return true;
166 }
167
168 /* should be ip6 safe */
169 static bool
170 ip6_checkentry(const struct ip6t_ip6 *ipv6)
171 {
172 if (ipv6->flags & ~IP6T_F_MASK) {
173 duprintf("Unknown flag bits set: %08X\n",
174 ipv6->flags & ~IP6T_F_MASK);
175 return false;
176 }
177 if (ipv6->invflags & ~IP6T_INV_MASK) {
178 duprintf("Unknown invflag bits set: %08X\n",
179 ipv6->invflags & ~IP6T_INV_MASK);
180 return false;
181 }
182 return true;
183 }
184
185 static unsigned int
186 ip6t_error(struct sk_buff *skb, const struct xt_action_param *par)
187 {
188 net_info_ratelimited("error: `%s'\n", (const char *)par->targinfo);
189
190 return NF_DROP;
191 }
192
193 static inline struct ip6t_entry *
194 get_entry(const void *base, unsigned int offset)
195 {
196 return (struct ip6t_entry *)(base + offset);
197 }
198
199 /* All zeroes == unconditional rule. */
200 /* Mildly perf critical (only if packet tracing is on) */
201 static inline bool unconditional(const struct ip6t_ip6 *ipv6)
202 {
203 static const struct ip6t_ip6 uncond;
204
205 return memcmp(ipv6, &uncond, sizeof(uncond)) == 0;
206 }
207
208 static inline const struct xt_entry_target *
209 ip6t_get_target_c(const struct ip6t_entry *e)
210 {
211 return ip6t_get_target((struct ip6t_entry *)e);
212 }
213
214 #if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
215 /* This cries for unification! */
216 static const char *const hooknames[] = {
217 [NF_INET_PRE_ROUTING] = "PREROUTING",
218 [NF_INET_LOCAL_IN] = "INPUT",
219 [NF_INET_FORWARD] = "FORWARD",
220 [NF_INET_LOCAL_OUT] = "OUTPUT",
221 [NF_INET_POST_ROUTING] = "POSTROUTING",
222 };
223
224 enum nf_ip_trace_comments {
225 NF_IP6_TRACE_COMMENT_RULE,
226 NF_IP6_TRACE_COMMENT_RETURN,
227 NF_IP6_TRACE_COMMENT_POLICY,
228 };
229
230 static const char *const comments[] = {
231 [NF_IP6_TRACE_COMMENT_RULE] = "rule",
232 [NF_IP6_TRACE_COMMENT_RETURN] = "return",
233 [NF_IP6_TRACE_COMMENT_POLICY] = "policy",
234 };
235
236 static struct nf_loginfo trace_loginfo = {
237 .type = NF_LOG_TYPE_LOG,
238 .u = {
239 .log = {
240 .level = LOGLEVEL_WARNING,
241 .logflags = NF_LOG_MASK,
242 },
243 },
244 };
245
246 /* Mildly perf critical (only if packet tracing is on) */
247 static inline int
248 get_chainname_rulenum(const struct ip6t_entry *s, const struct ip6t_entry *e,
249 const char *hookname, const char **chainname,
250 const char **comment, unsigned int *rulenum)
251 {
252 const struct xt_standard_target *t = (void *)ip6t_get_target_c(s);
253
254 if (strcmp(t->target.u.kernel.target->name, XT_ERROR_TARGET) == 0) {
255 /* Head of user chain: ERROR target with chainname */
256 *chainname = t->target.data;
257 (*rulenum) = 0;
258 } else if (s == e) {
259 (*rulenum)++;
260
261 if (s->target_offset == sizeof(struct ip6t_entry) &&
262 strcmp(t->target.u.kernel.target->name,
263 XT_STANDARD_TARGET) == 0 &&
264 t->verdict < 0 &&
265 unconditional(&s->ipv6)) {
266 /* Tail of chains: STANDARD target (return/policy) */
267 *comment = *chainname == hookname
268 ? comments[NF_IP6_TRACE_COMMENT_POLICY]
269 : comments[NF_IP6_TRACE_COMMENT_RETURN];
270 }
271 return 1;
272 } else
273 (*rulenum)++;
274
275 return 0;
276 }
277
278 static void trace_packet(struct net *net,
279 const struct sk_buff *skb,
280 unsigned int hook,
281 const struct net_device *in,
282 const struct net_device *out,
283 const char *tablename,
284 const struct xt_table_info *private,
285 const struct ip6t_entry *e)
286 {
287 const struct ip6t_entry *root;
288 const char *hookname, *chainname, *comment;
289 const struct ip6t_entry *iter;
290 unsigned int rulenum = 0;
291
292 root = get_entry(private->entries, private->hook_entry[hook]);
293
294 hookname = chainname = hooknames[hook];
295 comment = comments[NF_IP6_TRACE_COMMENT_RULE];
296
297 xt_entry_foreach(iter, root, private->size - private->hook_entry[hook])
298 if (get_chainname_rulenum(iter, e, hookname,
299 &chainname, &comment, &rulenum) != 0)
300 break;
301
302 nf_log_trace(net, AF_INET6, hook, skb, in, out, &trace_loginfo,
303 "TRACE: %s:%s:%s:%u ",
304 tablename, chainname, comment, rulenum);
305 }
306 #endif
307
308 static inline struct ip6t_entry *
309 ip6t_next_entry(const struct ip6t_entry *entry)
310 {
311 return (void *)entry + entry->next_offset;
312 }
313
314 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
315 unsigned int
316 ip6t_do_table(struct sk_buff *skb,
317 unsigned int hook,
318 const struct nf_hook_state *state,
319 struct xt_table *table)
320 {
321 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
322 /* Initializing verdict to NF_DROP keeps gcc happy. */
323 unsigned int verdict = NF_DROP;
324 const char *indev, *outdev;
325 const void *table_base;
326 struct ip6t_entry *e, **jumpstack;
327 unsigned int stackidx, cpu;
328 const struct xt_table_info *private;
329 struct xt_action_param acpar;
330 unsigned int addend;
331
332 /* Initialization */
333 stackidx = 0;
334 indev = state->in ? state->in->name : nulldevname;
335 outdev = state->out ? state->out->name : nulldevname;
336 /* We handle fragments by dealing with the first fragment as
337 * if it was a normal packet. All other fragments are treated
338 * normally, except that they will NEVER match rules that ask
339 * things we don't know, ie. tcp syn flag or ports). If the
340 * rule is also a fragment-specific rule, non-fragments won't
341 * match it. */
342 acpar.hotdrop = false;
343 acpar.in = state->in;
344 acpar.out = state->out;
345 acpar.family = NFPROTO_IPV6;
346 acpar.hooknum = hook;
347
348 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
349
350 local_bh_disable();
351 addend = xt_write_recseq_begin();
352 private = table->private;
353 /*
354 * Ensure we load private-> members after we've fetched the base
355 * pointer.
356 */
357 smp_read_barrier_depends();
358 cpu = smp_processor_id();
359 table_base = private->entries;
360 jumpstack = (struct ip6t_entry **)private->jumpstack[cpu];
361
362 /* Switch to alternate jumpstack if we're being invoked via TEE.
363 * TEE issues XT_CONTINUE verdict on original skb so we must not
364 * clobber the jumpstack.
365 *
366 * For recursion via REJECT or SYNPROXY the stack will be clobbered
367 * but it is no problem since absolute verdict is issued by these.
368 */
369 if (static_key_false(&xt_tee_enabled))
370 jumpstack += private->stacksize * __this_cpu_read(nf_skb_duplicated);
371
372 e = get_entry(table_base, private->hook_entry[hook]);
373
374 do {
375 const struct xt_entry_target *t;
376 const struct xt_entry_match *ematch;
377 struct xt_counters *counter;
378
379 IP_NF_ASSERT(e);
380 acpar.thoff = 0;
381 if (!ip6_packet_match(skb, indev, outdev, &e->ipv6,
382 &acpar.thoff, &acpar.fragoff, &acpar.hotdrop)) {
383 no_match:
384 e = ip6t_next_entry(e);
385 continue;
386 }
387
388 xt_ematch_foreach(ematch, e) {
389 acpar.match = ematch->u.kernel.match;
390 acpar.matchinfo = ematch->data;
391 if (!acpar.match->match(skb, &acpar))
392 goto no_match;
393 }
394
395 counter = xt_get_this_cpu_counter(&e->counters);
396 ADD_COUNTER(*counter, skb->len, 1);
397
398 t = ip6t_get_target_c(e);
399 IP_NF_ASSERT(t->u.kernel.target);
400
401 #if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
402 /* The packet is traced: log it */
403 if (unlikely(skb->nf_trace))
404 trace_packet(state->net, skb, hook, state->in,
405 state->out, table->name, private, e);
406 #endif
407 /* Standard target? */
408 if (!t->u.kernel.target->target) {
409 int v;
410
411 v = ((struct xt_standard_target *)t)->verdict;
412 if (v < 0) {
413 /* Pop from stack? */
414 if (v != XT_RETURN) {
415 verdict = (unsigned int)(-v) - 1;
416 break;
417 }
418 if (stackidx == 0)
419 e = get_entry(table_base,
420 private->underflow[hook]);
421 else
422 e = ip6t_next_entry(jumpstack[--stackidx]);
423 continue;
424 }
425 if (table_base + v != ip6t_next_entry(e) &&
426 !(e->ipv6.flags & IP6T_F_GOTO)) {
427 jumpstack[stackidx++] = e;
428 }
429
430 e = get_entry(table_base, v);
431 continue;
432 }
433
434 acpar.target = t->u.kernel.target;
435 acpar.targinfo = t->data;
436
437 verdict = t->u.kernel.target->target(skb, &acpar);
438 if (verdict == XT_CONTINUE)
439 e = ip6t_next_entry(e);
440 else
441 /* Verdict */
442 break;
443 } while (!acpar.hotdrop);
444
445 xt_write_recseq_end(addend);
446 local_bh_enable();
447
448 #ifdef DEBUG_ALLOW_ALL
449 return NF_ACCEPT;
450 #else
451 if (acpar.hotdrop)
452 return NF_DROP;
453 else return verdict;
454 #endif
455 }
456
457 /* Figures out from what hook each rule can be called: returns 0 if
458 there are loops. Puts hook bitmask in comefrom. */
459 static int
460 mark_source_chains(const struct xt_table_info *newinfo,
461 unsigned int valid_hooks, void *entry0)
462 {
463 unsigned int hook;
464
465 /* No recursion; use packet counter to save back ptrs (reset
466 to 0 as we leave), and comefrom to save source hook bitmask */
467 for (hook = 0; hook < NF_INET_NUMHOOKS; hook++) {
468 unsigned int pos = newinfo->hook_entry[hook];
469 struct ip6t_entry *e = (struct ip6t_entry *)(entry0 + pos);
470
471 if (!(valid_hooks & (1 << hook)))
472 continue;
473
474 /* Set initial back pointer. */
475 e->counters.pcnt = pos;
476
477 for (;;) {
478 const struct xt_standard_target *t
479 = (void *)ip6t_get_target_c(e);
480 int visited = e->comefrom & (1 << hook);
481
482 if (e->comefrom & (1 << NF_INET_NUMHOOKS)) {
483 pr_err("iptables: loop hook %u pos %u %08X.\n",
484 hook, pos, e->comefrom);
485 return 0;
486 }
487 e->comefrom |= ((1 << hook) | (1 << NF_INET_NUMHOOKS));
488
489 /* Unconditional return/END. */
490 if ((e->target_offset == sizeof(struct ip6t_entry) &&
491 (strcmp(t->target.u.user.name,
492 XT_STANDARD_TARGET) == 0) &&
493 t->verdict < 0 &&
494 unconditional(&e->ipv6)) || visited) {
495 unsigned int oldpos, size;
496
497 if ((strcmp(t->target.u.user.name,
498 XT_STANDARD_TARGET) == 0) &&
499 t->verdict < -NF_MAX_VERDICT - 1) {
500 duprintf("mark_source_chains: bad "
501 "negative verdict (%i)\n",
502 t->verdict);
503 return 0;
504 }
505
506 /* Return: backtrack through the last
507 big jump. */
508 do {
509 e->comefrom ^= (1<<NF_INET_NUMHOOKS);
510 #ifdef DEBUG_IP_FIREWALL_USER
511 if (e->comefrom
512 & (1 << NF_INET_NUMHOOKS)) {
513 duprintf("Back unset "
514 "on hook %u "
515 "rule %u\n",
516 hook, pos);
517 }
518 #endif
519 oldpos = pos;
520 pos = e->counters.pcnt;
521 e->counters.pcnt = 0;
522
523 /* We're at the start. */
524 if (pos == oldpos)
525 goto next;
526
527 e = (struct ip6t_entry *)
528 (entry0 + pos);
529 } while (oldpos == pos + e->next_offset);
530
531 /* Move along one */
532 size = e->next_offset;
533 e = (struct ip6t_entry *)
534 (entry0 + pos + size);
535 e->counters.pcnt = pos;
536 pos += size;
537 } else {
538 int newpos = t->verdict;
539
540 if (strcmp(t->target.u.user.name,
541 XT_STANDARD_TARGET) == 0 &&
542 newpos >= 0) {
543 if (newpos > newinfo->size -
544 sizeof(struct ip6t_entry)) {
545 duprintf("mark_source_chains: "
546 "bad verdict (%i)\n",
547 newpos);
548 return 0;
549 }
550 /* This a jump; chase it. */
551 duprintf("Jump rule %u -> %u\n",
552 pos, newpos);
553 } else {
554 /* ... this is a fallthru */
555 newpos = pos + e->next_offset;
556 }
557 e = (struct ip6t_entry *)
558 (entry0 + newpos);
559 e->counters.pcnt = pos;
560 pos = newpos;
561 }
562 }
563 next:
564 duprintf("Finished chain %u\n", hook);
565 }
566 return 1;
567 }
568
569 static void cleanup_match(struct xt_entry_match *m, struct net *net)
570 {
571 struct xt_mtdtor_param par;
572
573 par.net = net;
574 par.match = m->u.kernel.match;
575 par.matchinfo = m->data;
576 par.family = NFPROTO_IPV6;
577 if (par.match->destroy != NULL)
578 par.match->destroy(&par);
579 module_put(par.match->me);
580 }
581
582 static int
583 check_entry(const struct ip6t_entry *e, const char *name)
584 {
585 const struct xt_entry_target *t;
586
587 if (!ip6_checkentry(&e->ipv6)) {
588 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
589 return -EINVAL;
590 }
591
592 if (e->target_offset + sizeof(struct xt_entry_target) >
593 e->next_offset)
594 return -EINVAL;
595
596 t = ip6t_get_target_c(e);
597 if (e->target_offset + t->u.target_size > e->next_offset)
598 return -EINVAL;
599
600 return 0;
601 }
602
603 static int check_match(struct xt_entry_match *m, struct xt_mtchk_param *par)
604 {
605 const struct ip6t_ip6 *ipv6 = par->entryinfo;
606 int ret;
607
608 par->match = m->u.kernel.match;
609 par->matchinfo = m->data;
610
611 ret = xt_check_match(par, m->u.match_size - sizeof(*m),
612 ipv6->proto, ipv6->invflags & IP6T_INV_PROTO);
613 if (ret < 0) {
614 duprintf("ip_tables: check failed for `%s'.\n",
615 par.match->name);
616 return ret;
617 }
618 return 0;
619 }
620
621 static int
622 find_check_match(struct xt_entry_match *m, struct xt_mtchk_param *par)
623 {
624 struct xt_match *match;
625 int ret;
626
627 match = xt_request_find_match(NFPROTO_IPV6, m->u.user.name,
628 m->u.user.revision);
629 if (IS_ERR(match)) {
630 duprintf("find_check_match: `%s' not found\n", m->u.user.name);
631 return PTR_ERR(match);
632 }
633 m->u.kernel.match = match;
634
635 ret = check_match(m, par);
636 if (ret)
637 goto err;
638
639 return 0;
640 err:
641 module_put(m->u.kernel.match->me);
642 return ret;
643 }
644
645 static int check_target(struct ip6t_entry *e, struct net *net, const char *name)
646 {
647 struct xt_entry_target *t = ip6t_get_target(e);
648 struct xt_tgchk_param par = {
649 .net = net,
650 .table = name,
651 .entryinfo = e,
652 .target = t->u.kernel.target,
653 .targinfo = t->data,
654 .hook_mask = e->comefrom,
655 .family = NFPROTO_IPV6,
656 };
657 int ret;
658
659 t = ip6t_get_target(e);
660 ret = xt_check_target(&par, t->u.target_size - sizeof(*t),
661 e->ipv6.proto, e->ipv6.invflags & IP6T_INV_PROTO);
662 if (ret < 0) {
663 duprintf("ip_tables: check failed for `%s'.\n",
664 t->u.kernel.target->name);
665 return ret;
666 }
667 return 0;
668 }
669
670 static int
671 find_check_entry(struct ip6t_entry *e, struct net *net, const char *name,
672 unsigned int size)
673 {
674 struct xt_entry_target *t;
675 struct xt_target *target;
676 int ret;
677 unsigned int j;
678 struct xt_mtchk_param mtpar;
679 struct xt_entry_match *ematch;
680
681 ret = check_entry(e, name);
682 if (ret)
683 return ret;
684
685 e->counters.pcnt = xt_percpu_counter_alloc();
686 if (IS_ERR_VALUE(e->counters.pcnt))
687 return -ENOMEM;
688
689 j = 0;
690 mtpar.net = net;
691 mtpar.table = name;
692 mtpar.entryinfo = &e->ipv6;
693 mtpar.hook_mask = e->comefrom;
694 mtpar.family = NFPROTO_IPV6;
695 xt_ematch_foreach(ematch, e) {
696 ret = find_check_match(ematch, &mtpar);
697 if (ret != 0)
698 goto cleanup_matches;
699 ++j;
700 }
701
702 t = ip6t_get_target(e);
703 target = xt_request_find_target(NFPROTO_IPV6, t->u.user.name,
704 t->u.user.revision);
705 if (IS_ERR(target)) {
706 duprintf("find_check_entry: `%s' not found\n", t->u.user.name);
707 ret = PTR_ERR(target);
708 goto cleanup_matches;
709 }
710 t->u.kernel.target = target;
711
712 ret = check_target(e, net, name);
713 if (ret)
714 goto err;
715 return 0;
716 err:
717 module_put(t->u.kernel.target->me);
718 cleanup_matches:
719 xt_ematch_foreach(ematch, e) {
720 if (j-- == 0)
721 break;
722 cleanup_match(ematch, net);
723 }
724
725 xt_percpu_counter_free(e->counters.pcnt);
726
727 return ret;
728 }
729
730 static bool check_underflow(const struct ip6t_entry *e)
731 {
732 const struct xt_entry_target *t;
733 unsigned int verdict;
734
735 if (!unconditional(&e->ipv6))
736 return false;
737 t = ip6t_get_target_c(e);
738 if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
739 return false;
740 verdict = ((struct xt_standard_target *)t)->verdict;
741 verdict = -verdict - 1;
742 return verdict == NF_DROP || verdict == NF_ACCEPT;
743 }
744
745 static int
746 check_entry_size_and_hooks(struct ip6t_entry *e,
747 struct xt_table_info *newinfo,
748 const unsigned char *base,
749 const unsigned char *limit,
750 const unsigned int *hook_entries,
751 const unsigned int *underflows,
752 unsigned int valid_hooks)
753 {
754 unsigned int h;
755
756 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0 ||
757 (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
758 duprintf("Bad offset %p\n", e);
759 return -EINVAL;
760 }
761
762 if (e->next_offset
763 < sizeof(struct ip6t_entry) + sizeof(struct xt_entry_target)) {
764 duprintf("checking: element %p size %u\n",
765 e, e->next_offset);
766 return -EINVAL;
767 }
768
769 /* Check hooks & underflows */
770 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
771 if (!(valid_hooks & (1 << h)))
772 continue;
773 if ((unsigned char *)e - base == hook_entries[h])
774 newinfo->hook_entry[h] = hook_entries[h];
775 if ((unsigned char *)e - base == underflows[h]) {
776 if (!check_underflow(e)) {
777 pr_err("Underflows must be unconditional and "
778 "use the STANDARD target with "
779 "ACCEPT/DROP\n");
780 return -EINVAL;
781 }
782 newinfo->underflow[h] = underflows[h];
783 }
784 }
785
786 /* Clear counters and comefrom */
787 e->counters = ((struct xt_counters) { 0, 0 });
788 e->comefrom = 0;
789 return 0;
790 }
791
792 static void cleanup_entry(struct ip6t_entry *e, struct net *net)
793 {
794 struct xt_tgdtor_param par;
795 struct xt_entry_target *t;
796 struct xt_entry_match *ematch;
797
798 /* Cleanup all matches */
799 xt_ematch_foreach(ematch, e)
800 cleanup_match(ematch, net);
801 t = ip6t_get_target(e);
802
803 par.net = net;
804 par.target = t->u.kernel.target;
805 par.targinfo = t->data;
806 par.family = NFPROTO_IPV6;
807 if (par.target->destroy != NULL)
808 par.target->destroy(&par);
809 module_put(par.target->me);
810
811 xt_percpu_counter_free(e->counters.pcnt);
812 }
813
814 /* Checks and translates the user-supplied table segment (held in
815 newinfo) */
816 static int
817 translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0,
818 const struct ip6t_replace *repl)
819 {
820 struct ip6t_entry *iter;
821 unsigned int i;
822 int ret = 0;
823
824 newinfo->size = repl->size;
825 newinfo->number = repl->num_entries;
826
827 /* Init all hooks to impossible value. */
828 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
829 newinfo->hook_entry[i] = 0xFFFFFFFF;
830 newinfo->underflow[i] = 0xFFFFFFFF;
831 }
832
833 duprintf("translate_table: size %u\n", newinfo->size);
834 i = 0;
835 /* Walk through entries, checking offsets. */
836 xt_entry_foreach(iter, entry0, newinfo->size) {
837 ret = check_entry_size_and_hooks(iter, newinfo, entry0,
838 entry0 + repl->size,
839 repl->hook_entry,
840 repl->underflow,
841 repl->valid_hooks);
842 if (ret != 0)
843 return ret;
844 ++i;
845 if (strcmp(ip6t_get_target(iter)->u.user.name,
846 XT_ERROR_TARGET) == 0)
847 ++newinfo->stacksize;
848 }
849
850 if (i != repl->num_entries) {
851 duprintf("translate_table: %u not %u entries\n",
852 i, repl->num_entries);
853 return -EINVAL;
854 }
855
856 /* Check hooks all assigned */
857 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
858 /* Only hooks which are valid */
859 if (!(repl->valid_hooks & (1 << i)))
860 continue;
861 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
862 duprintf("Invalid hook entry %u %u\n",
863 i, repl->hook_entry[i]);
864 return -EINVAL;
865 }
866 if (newinfo->underflow[i] == 0xFFFFFFFF) {
867 duprintf("Invalid underflow %u %u\n",
868 i, repl->underflow[i]);
869 return -EINVAL;
870 }
871 }
872
873 if (!mark_source_chains(newinfo, repl->valid_hooks, entry0))
874 return -ELOOP;
875
876 /* Finally, each sanity check must pass */
877 i = 0;
878 xt_entry_foreach(iter, entry0, newinfo->size) {
879 ret = find_check_entry(iter, net, repl->name, repl->size);
880 if (ret != 0)
881 break;
882 ++i;
883 }
884
885 if (ret != 0) {
886 xt_entry_foreach(iter, entry0, newinfo->size) {
887 if (i-- == 0)
888 break;
889 cleanup_entry(iter, net);
890 }
891 return ret;
892 }
893
894 return ret;
895 }
896
897 static void
898 get_counters(const struct xt_table_info *t,
899 struct xt_counters counters[])
900 {
901 struct ip6t_entry *iter;
902 unsigned int cpu;
903 unsigned int i;
904
905 for_each_possible_cpu(cpu) {
906 seqcount_t *s = &per_cpu(xt_recseq, cpu);
907
908 i = 0;
909 xt_entry_foreach(iter, t->entries, t->size) {
910 struct xt_counters *tmp;
911 u64 bcnt, pcnt;
912 unsigned int start;
913
914 tmp = xt_get_per_cpu_counter(&iter->counters, cpu);
915 do {
916 start = read_seqcount_begin(s);
917 bcnt = tmp->bcnt;
918 pcnt = tmp->pcnt;
919 } while (read_seqcount_retry(s, start));
920
921 ADD_COUNTER(counters[i], bcnt, pcnt);
922 ++i;
923 }
924 }
925 }
926
927 static struct xt_counters *alloc_counters(const struct xt_table *table)
928 {
929 unsigned int countersize;
930 struct xt_counters *counters;
931 const struct xt_table_info *private = table->private;
932
933 /* We need atomic snapshot of counters: rest doesn't change
934 (other than comefrom, which userspace doesn't care
935 about). */
936 countersize = sizeof(struct xt_counters) * private->number;
937 counters = vzalloc(countersize);
938
939 if (counters == NULL)
940 return ERR_PTR(-ENOMEM);
941
942 get_counters(private, counters);
943
944 return counters;
945 }
946
947 static int
948 copy_entries_to_user(unsigned int total_size,
949 const struct xt_table *table,
950 void __user *userptr)
951 {
952 unsigned int off, num;
953 const struct ip6t_entry *e;
954 struct xt_counters *counters;
955 const struct xt_table_info *private = table->private;
956 int ret = 0;
957 const void *loc_cpu_entry;
958
959 counters = alloc_counters(table);
960 if (IS_ERR(counters))
961 return PTR_ERR(counters);
962
963 loc_cpu_entry = private->entries;
964 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
965 ret = -EFAULT;
966 goto free_counters;
967 }
968
969 /* FIXME: use iterator macros --RR */
970 /* ... then go back and fix counters and names */
971 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
972 unsigned int i;
973 const struct xt_entry_match *m;
974 const struct xt_entry_target *t;
975
976 e = (struct ip6t_entry *)(loc_cpu_entry + off);
977 if (copy_to_user(userptr + off
978 + offsetof(struct ip6t_entry, counters),
979 &counters[num],
980 sizeof(counters[num])) != 0) {
981 ret = -EFAULT;
982 goto free_counters;
983 }
984
985 for (i = sizeof(struct ip6t_entry);
986 i < e->target_offset;
987 i += m->u.match_size) {
988 m = (void *)e + i;
989
990 if (copy_to_user(userptr + off + i
991 + offsetof(struct xt_entry_match,
992 u.user.name),
993 m->u.kernel.match->name,
994 strlen(m->u.kernel.match->name)+1)
995 != 0) {
996 ret = -EFAULT;
997 goto free_counters;
998 }
999 }
1000
1001 t = ip6t_get_target_c(e);
1002 if (copy_to_user(userptr + off + e->target_offset
1003 + offsetof(struct xt_entry_target,
1004 u.user.name),
1005 t->u.kernel.target->name,
1006 strlen(t->u.kernel.target->name)+1) != 0) {
1007 ret = -EFAULT;
1008 goto free_counters;
1009 }
1010 }
1011
1012 free_counters:
1013 vfree(counters);
1014 return ret;
1015 }
1016
1017 #ifdef CONFIG_COMPAT
1018 static void compat_standard_from_user(void *dst, const void *src)
1019 {
1020 int v = *(compat_int_t *)src;
1021
1022 if (v > 0)
1023 v += xt_compat_calc_jump(AF_INET6, v);
1024 memcpy(dst, &v, sizeof(v));
1025 }
1026
1027 static int compat_standard_to_user(void __user *dst, const void *src)
1028 {
1029 compat_int_t cv = *(int *)src;
1030
1031 if (cv > 0)
1032 cv -= xt_compat_calc_jump(AF_INET6, cv);
1033 return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
1034 }
1035
1036 static int compat_calc_entry(const struct ip6t_entry *e,
1037 const struct xt_table_info *info,
1038 const void *base, struct xt_table_info *newinfo)
1039 {
1040 const struct xt_entry_match *ematch;
1041 const struct xt_entry_target *t;
1042 unsigned int entry_offset;
1043 int off, i, ret;
1044
1045 off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1046 entry_offset = (void *)e - base;
1047 xt_ematch_foreach(ematch, e)
1048 off += xt_compat_match_offset(ematch->u.kernel.match);
1049 t = ip6t_get_target_c(e);
1050 off += xt_compat_target_offset(t->u.kernel.target);
1051 newinfo->size -= off;
1052 ret = xt_compat_add_offset(AF_INET6, entry_offset, off);
1053 if (ret)
1054 return ret;
1055
1056 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1057 if (info->hook_entry[i] &&
1058 (e < (struct ip6t_entry *)(base + info->hook_entry[i])))
1059 newinfo->hook_entry[i] -= off;
1060 if (info->underflow[i] &&
1061 (e < (struct ip6t_entry *)(base + info->underflow[i])))
1062 newinfo->underflow[i] -= off;
1063 }
1064 return 0;
1065 }
1066
1067 static int compat_table_info(const struct xt_table_info *info,
1068 struct xt_table_info *newinfo)
1069 {
1070 struct ip6t_entry *iter;
1071 const void *loc_cpu_entry;
1072 int ret;
1073
1074 if (!newinfo || !info)
1075 return -EINVAL;
1076
1077 /* we dont care about newinfo->entries */
1078 memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
1079 newinfo->initial_entries = 0;
1080 loc_cpu_entry = info->entries;
1081 xt_compat_init_offsets(AF_INET6, info->number);
1082 xt_entry_foreach(iter, loc_cpu_entry, info->size) {
1083 ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo);
1084 if (ret != 0)
1085 return ret;
1086 }
1087 return 0;
1088 }
1089 #endif
1090
1091 static int get_info(struct net *net, void __user *user,
1092 const int *len, int compat)
1093 {
1094 char name[XT_TABLE_MAXNAMELEN];
1095 struct xt_table *t;
1096 int ret;
1097
1098 if (*len != sizeof(struct ip6t_getinfo)) {
1099 duprintf("length %u != %zu\n", *len,
1100 sizeof(struct ip6t_getinfo));
1101 return -EINVAL;
1102 }
1103
1104 if (copy_from_user(name, user, sizeof(name)) != 0)
1105 return -EFAULT;
1106
1107 name[XT_TABLE_MAXNAMELEN-1] = '\0';
1108 #ifdef CONFIG_COMPAT
1109 if (compat)
1110 xt_compat_lock(AF_INET6);
1111 #endif
1112 t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
1113 "ip6table_%s", name);
1114 if (!IS_ERR_OR_NULL(t)) {
1115 struct ip6t_getinfo info;
1116 const struct xt_table_info *private = t->private;
1117 #ifdef CONFIG_COMPAT
1118 struct xt_table_info tmp;
1119
1120 if (compat) {
1121 ret = compat_table_info(private, &tmp);
1122 xt_compat_flush_offsets(AF_INET6);
1123 private = &tmp;
1124 }
1125 #endif
1126 memset(&info, 0, sizeof(info));
1127 info.valid_hooks = t->valid_hooks;
1128 memcpy(info.hook_entry, private->hook_entry,
1129 sizeof(info.hook_entry));
1130 memcpy(info.underflow, private->underflow,
1131 sizeof(info.underflow));
1132 info.num_entries = private->number;
1133 info.size = private->size;
1134 strcpy(info.name, name);
1135
1136 if (copy_to_user(user, &info, *len) != 0)
1137 ret = -EFAULT;
1138 else
1139 ret = 0;
1140
1141 xt_table_unlock(t);
1142 module_put(t->me);
1143 } else
1144 ret = t ? PTR_ERR(t) : -ENOENT;
1145 #ifdef CONFIG_COMPAT
1146 if (compat)
1147 xt_compat_unlock(AF_INET6);
1148 #endif
1149 return ret;
1150 }
1151
1152 static int
1153 get_entries(struct net *net, struct ip6t_get_entries __user *uptr,
1154 const int *len)
1155 {
1156 int ret;
1157 struct ip6t_get_entries get;
1158 struct xt_table *t;
1159
1160 if (*len < sizeof(get)) {
1161 duprintf("get_entries: %u < %zu\n", *len, sizeof(get));
1162 return -EINVAL;
1163 }
1164 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1165 return -EFAULT;
1166 if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1167 duprintf("get_entries: %u != %zu\n",
1168 *len, sizeof(get) + get.size);
1169 return -EINVAL;
1170 }
1171
1172 t = xt_find_table_lock(net, AF_INET6, get.name);
1173 if (!IS_ERR_OR_NULL(t)) {
1174 struct xt_table_info *private = t->private;
1175 duprintf("t->private->number = %u\n", private->number);
1176 if (get.size == private->size)
1177 ret = copy_entries_to_user(private->size,
1178 t, uptr->entrytable);
1179 else {
1180 duprintf("get_entries: I've got %u not %u!\n",
1181 private->size, get.size);
1182 ret = -EAGAIN;
1183 }
1184 module_put(t->me);
1185 xt_table_unlock(t);
1186 } else
1187 ret = t ? PTR_ERR(t) : -ENOENT;
1188
1189 return ret;
1190 }
1191
1192 static int
1193 __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
1194 struct xt_table_info *newinfo, unsigned int num_counters,
1195 void __user *counters_ptr)
1196 {
1197 int ret;
1198 struct xt_table *t;
1199 struct xt_table_info *oldinfo;
1200 struct xt_counters *counters;
1201 struct ip6t_entry *iter;
1202
1203 ret = 0;
1204 counters = vzalloc(num_counters * sizeof(struct xt_counters));
1205 if (!counters) {
1206 ret = -ENOMEM;
1207 goto out;
1208 }
1209
1210 t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
1211 "ip6table_%s", name);
1212 if (IS_ERR_OR_NULL(t)) {
1213 ret = t ? PTR_ERR(t) : -ENOENT;
1214 goto free_newinfo_counters_untrans;
1215 }
1216
1217 /* You lied! */
1218 if (valid_hooks != t->valid_hooks) {
1219 duprintf("Valid hook crap: %08X vs %08X\n",
1220 valid_hooks, t->valid_hooks);
1221 ret = -EINVAL;
1222 goto put_module;
1223 }
1224
1225 oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);
1226 if (!oldinfo)
1227 goto put_module;
1228
1229 /* Update module usage count based on number of rules */
1230 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1231 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1232 if ((oldinfo->number > oldinfo->initial_entries) ||
1233 (newinfo->number <= oldinfo->initial_entries))
1234 module_put(t->me);
1235 if ((oldinfo->number > oldinfo->initial_entries) &&
1236 (newinfo->number <= oldinfo->initial_entries))
1237 module_put(t->me);
1238
1239 /* Get the old counters, and synchronize with replace */
1240 get_counters(oldinfo, counters);
1241
1242 /* Decrease module usage counts and free resource */
1243 xt_entry_foreach(iter, oldinfo->entries, oldinfo->size)
1244 cleanup_entry(iter, net);
1245
1246 xt_free_table_info(oldinfo);
1247 if (copy_to_user(counters_ptr, counters,
1248 sizeof(struct xt_counters) * num_counters) != 0) {
1249 /* Silent error, can't fail, new table is already in place */
1250 net_warn_ratelimited("ip6tables: counters copy to user failed while replacing table\n");
1251 }
1252 vfree(counters);
1253 xt_table_unlock(t);
1254 return ret;
1255
1256 put_module:
1257 module_put(t->me);
1258 xt_table_unlock(t);
1259 free_newinfo_counters_untrans:
1260 vfree(counters);
1261 out:
1262 return ret;
1263 }
1264
1265 static int
1266 do_replace(struct net *net, const void __user *user, unsigned int len)
1267 {
1268 int ret;
1269 struct ip6t_replace tmp;
1270 struct xt_table_info *newinfo;
1271 void *loc_cpu_entry;
1272 struct ip6t_entry *iter;
1273
1274 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1275 return -EFAULT;
1276
1277 /* overflow check */
1278 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1279 return -ENOMEM;
1280 if (tmp.num_counters == 0)
1281 return -EINVAL;
1282
1283 tmp.name[sizeof(tmp.name)-1] = 0;
1284
1285 newinfo = xt_alloc_table_info(tmp.size);
1286 if (!newinfo)
1287 return -ENOMEM;
1288
1289 loc_cpu_entry = newinfo->entries;
1290 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1291 tmp.size) != 0) {
1292 ret = -EFAULT;
1293 goto free_newinfo;
1294 }
1295
1296 ret = translate_table(net, newinfo, loc_cpu_entry, &tmp);
1297 if (ret != 0)
1298 goto free_newinfo;
1299
1300 duprintf("ip_tables: Translated table\n");
1301
1302 ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1303 tmp.num_counters, tmp.counters);
1304 if (ret)
1305 goto free_newinfo_untrans;
1306 return 0;
1307
1308 free_newinfo_untrans:
1309 xt_entry_foreach(iter, loc_cpu_entry, newinfo->size)
1310 cleanup_entry(iter, net);
1311 free_newinfo:
1312 xt_free_table_info(newinfo);
1313 return ret;
1314 }
1315
1316 static int
1317 do_add_counters(struct net *net, const void __user *user, unsigned int len,
1318 int compat)
1319 {
1320 unsigned int i;
1321 struct xt_counters_info tmp;
1322 struct xt_counters *paddc;
1323 unsigned int num_counters;
1324 char *name;
1325 int size;
1326 void *ptmp;
1327 struct xt_table *t;
1328 const struct xt_table_info *private;
1329 int ret = 0;
1330 struct ip6t_entry *iter;
1331 unsigned int addend;
1332 #ifdef CONFIG_COMPAT
1333 struct compat_xt_counters_info compat_tmp;
1334
1335 if (compat) {
1336 ptmp = &compat_tmp;
1337 size = sizeof(struct compat_xt_counters_info);
1338 } else
1339 #endif
1340 {
1341 ptmp = &tmp;
1342 size = sizeof(struct xt_counters_info);
1343 }
1344
1345 if (copy_from_user(ptmp, user, size) != 0)
1346 return -EFAULT;
1347
1348 #ifdef CONFIG_COMPAT
1349 if (compat) {
1350 num_counters = compat_tmp.num_counters;
1351 name = compat_tmp.name;
1352 } else
1353 #endif
1354 {
1355 num_counters = tmp.num_counters;
1356 name = tmp.name;
1357 }
1358
1359 if (len != size + num_counters * sizeof(struct xt_counters))
1360 return -EINVAL;
1361
1362 paddc = vmalloc(len - size);
1363 if (!paddc)
1364 return -ENOMEM;
1365
1366 if (copy_from_user(paddc, user + size, len - size) != 0) {
1367 ret = -EFAULT;
1368 goto free;
1369 }
1370
1371 t = xt_find_table_lock(net, AF_INET6, name);
1372 if (IS_ERR_OR_NULL(t)) {
1373 ret = t ? PTR_ERR(t) : -ENOENT;
1374 goto free;
1375 }
1376
1377 local_bh_disable();
1378 private = t->private;
1379 if (private->number != num_counters) {
1380 ret = -EINVAL;
1381 goto unlock_up_free;
1382 }
1383
1384 i = 0;
1385 addend = xt_write_recseq_begin();
1386 xt_entry_foreach(iter, private->entries, private->size) {
1387 struct xt_counters *tmp;
1388
1389 tmp = xt_get_this_cpu_counter(&iter->counters);
1390 ADD_COUNTER(*tmp, paddc[i].bcnt, paddc[i].pcnt);
1391 ++i;
1392 }
1393 xt_write_recseq_end(addend);
1394 unlock_up_free:
1395 local_bh_enable();
1396 xt_table_unlock(t);
1397 module_put(t->me);
1398 free:
1399 vfree(paddc);
1400
1401 return ret;
1402 }
1403
1404 #ifdef CONFIG_COMPAT
1405 struct compat_ip6t_replace {
1406 char name[XT_TABLE_MAXNAMELEN];
1407 u32 valid_hooks;
1408 u32 num_entries;
1409 u32 size;
1410 u32 hook_entry[NF_INET_NUMHOOKS];
1411 u32 underflow[NF_INET_NUMHOOKS];
1412 u32 num_counters;
1413 compat_uptr_t counters; /* struct xt_counters * */
1414 struct compat_ip6t_entry entries[0];
1415 };
1416
1417 static int
1418 compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr,
1419 unsigned int *size, struct xt_counters *counters,
1420 unsigned int i)
1421 {
1422 struct xt_entry_target *t;
1423 struct compat_ip6t_entry __user *ce;
1424 u_int16_t target_offset, next_offset;
1425 compat_uint_t origsize;
1426 const struct xt_entry_match *ematch;
1427 int ret = 0;
1428
1429 origsize = *size;
1430 ce = (struct compat_ip6t_entry __user *)*dstptr;
1431 if (copy_to_user(ce, e, sizeof(struct ip6t_entry)) != 0 ||
1432 copy_to_user(&ce->counters, &counters[i],
1433 sizeof(counters[i])) != 0)
1434 return -EFAULT;
1435
1436 *dstptr += sizeof(struct compat_ip6t_entry);
1437 *size -= sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1438
1439 xt_ematch_foreach(ematch, e) {
1440 ret = xt_compat_match_to_user(ematch, dstptr, size);
1441 if (ret != 0)
1442 return ret;
1443 }
1444 target_offset = e->target_offset - (origsize - *size);
1445 t = ip6t_get_target(e);
1446 ret = xt_compat_target_to_user(t, dstptr, size);
1447 if (ret)
1448 return ret;
1449 next_offset = e->next_offset - (origsize - *size);
1450 if (put_user(target_offset, &ce->target_offset) != 0 ||
1451 put_user(next_offset, &ce->next_offset) != 0)
1452 return -EFAULT;
1453 return 0;
1454 }
1455
1456 static int
1457 compat_find_calc_match(struct xt_entry_match *m,
1458 const char *name,
1459 const struct ip6t_ip6 *ipv6,
1460 int *size)
1461 {
1462 struct xt_match *match;
1463
1464 match = xt_request_find_match(NFPROTO_IPV6, m->u.user.name,
1465 m->u.user.revision);
1466 if (IS_ERR(match)) {
1467 duprintf("compat_check_calc_match: `%s' not found\n",
1468 m->u.user.name);
1469 return PTR_ERR(match);
1470 }
1471 m->u.kernel.match = match;
1472 *size += xt_compat_match_offset(match);
1473 return 0;
1474 }
1475
1476 static void compat_release_entry(struct compat_ip6t_entry *e)
1477 {
1478 struct xt_entry_target *t;
1479 struct xt_entry_match *ematch;
1480
1481 /* Cleanup all matches */
1482 xt_ematch_foreach(ematch, e)
1483 module_put(ematch->u.kernel.match->me);
1484 t = compat_ip6t_get_target(e);
1485 module_put(t->u.kernel.target->me);
1486 }
1487
1488 static int
1489 check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e,
1490 struct xt_table_info *newinfo,
1491 unsigned int *size,
1492 const unsigned char *base,
1493 const unsigned char *limit,
1494 const unsigned int *hook_entries,
1495 const unsigned int *underflows,
1496 const char *name)
1497 {
1498 struct xt_entry_match *ematch;
1499 struct xt_entry_target *t;
1500 struct xt_target *target;
1501 unsigned int entry_offset;
1502 unsigned int j;
1503 int ret, off, h;
1504
1505 duprintf("check_compat_entry_size_and_hooks %p\n", e);
1506 if ((unsigned long)e % __alignof__(struct compat_ip6t_entry) != 0 ||
1507 (unsigned char *)e + sizeof(struct compat_ip6t_entry) >= limit) {
1508 duprintf("Bad offset %p, limit = %p\n", e, limit);
1509 return -EINVAL;
1510 }
1511
1512 if (e->next_offset < sizeof(struct compat_ip6t_entry) +
1513 sizeof(struct compat_xt_entry_target)) {
1514 duprintf("checking: element %p size %u\n",
1515 e, e->next_offset);
1516 return -EINVAL;
1517 }
1518
1519 /* For purposes of check_entry casting the compat entry is fine */
1520 ret = check_entry((struct ip6t_entry *)e, name);
1521 if (ret)
1522 return ret;
1523
1524 off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1525 entry_offset = (void *)e - (void *)base;
1526 j = 0;
1527 xt_ematch_foreach(ematch, e) {
1528 ret = compat_find_calc_match(ematch, name, &e->ipv6, &off);
1529 if (ret != 0)
1530 goto release_matches;
1531 ++j;
1532 }
1533
1534 t = compat_ip6t_get_target(e);
1535 target = xt_request_find_target(NFPROTO_IPV6, t->u.user.name,
1536 t->u.user.revision);
1537 if (IS_ERR(target)) {
1538 duprintf("check_compat_entry_size_and_hooks: `%s' not found\n",
1539 t->u.user.name);
1540 ret = PTR_ERR(target);
1541 goto release_matches;
1542 }
1543 t->u.kernel.target = target;
1544
1545 off += xt_compat_target_offset(target);
1546 *size += off;
1547 ret = xt_compat_add_offset(AF_INET6, entry_offset, off);
1548 if (ret)
1549 goto out;
1550
1551 /* Check hooks & underflows */
1552 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1553 if ((unsigned char *)e - base == hook_entries[h])
1554 newinfo->hook_entry[h] = hook_entries[h];
1555 if ((unsigned char *)e - base == underflows[h])
1556 newinfo->underflow[h] = underflows[h];
1557 }
1558
1559 /* Clear counters and comefrom */
1560 memset(&e->counters, 0, sizeof(e->counters));
1561 e->comefrom = 0;
1562 return 0;
1563
1564 out:
1565 module_put(t->u.kernel.target->me);
1566 release_matches:
1567 xt_ematch_foreach(ematch, e) {
1568 if (j-- == 0)
1569 break;
1570 module_put(ematch->u.kernel.match->me);
1571 }
1572 return ret;
1573 }
1574
1575 static int
1576 compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr,
1577 unsigned int *size, const char *name,
1578 struct xt_table_info *newinfo, unsigned char *base)
1579 {
1580 struct xt_entry_target *t;
1581 struct ip6t_entry *de;
1582 unsigned int origsize;
1583 int ret, h;
1584 struct xt_entry_match *ematch;
1585
1586 ret = 0;
1587 origsize = *size;
1588 de = (struct ip6t_entry *)*dstptr;
1589 memcpy(de, e, sizeof(struct ip6t_entry));
1590 memcpy(&de->counters, &e->counters, sizeof(e->counters));
1591
1592 *dstptr += sizeof(struct ip6t_entry);
1593 *size += sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1594
1595 xt_ematch_foreach(ematch, e) {
1596 ret = xt_compat_match_from_user(ematch, dstptr, size);
1597 if (ret != 0)
1598 return ret;
1599 }
1600 de->target_offset = e->target_offset - (origsize - *size);
1601 t = compat_ip6t_get_target(e);
1602 xt_compat_target_from_user(t, dstptr, size);
1603
1604 de->next_offset = e->next_offset - (origsize - *size);
1605 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1606 if ((unsigned char *)de - base < newinfo->hook_entry[h])
1607 newinfo->hook_entry[h] -= origsize - *size;
1608 if ((unsigned char *)de - base < newinfo->underflow[h])
1609 newinfo->underflow[h] -= origsize - *size;
1610 }
1611 return ret;
1612 }
1613
1614 static int compat_check_entry(struct ip6t_entry *e, struct net *net,
1615 const char *name)
1616 {
1617 unsigned int j;
1618 int ret = 0;
1619 struct xt_mtchk_param mtpar;
1620 struct xt_entry_match *ematch;
1621
1622 e->counters.pcnt = xt_percpu_counter_alloc();
1623 if (IS_ERR_VALUE(e->counters.pcnt))
1624 return -ENOMEM;
1625 j = 0;
1626 mtpar.net = net;
1627 mtpar.table = name;
1628 mtpar.entryinfo = &e->ipv6;
1629 mtpar.hook_mask = e->comefrom;
1630 mtpar.family = NFPROTO_IPV6;
1631 xt_ematch_foreach(ematch, e) {
1632 ret = check_match(ematch, &mtpar);
1633 if (ret != 0)
1634 goto cleanup_matches;
1635 ++j;
1636 }
1637
1638 ret = check_target(e, net, name);
1639 if (ret)
1640 goto cleanup_matches;
1641 return 0;
1642
1643 cleanup_matches:
1644 xt_ematch_foreach(ematch, e) {
1645 if (j-- == 0)
1646 break;
1647 cleanup_match(ematch, net);
1648 }
1649
1650 xt_percpu_counter_free(e->counters.pcnt);
1651
1652 return ret;
1653 }
1654
1655 static int
1656 translate_compat_table(struct net *net,
1657 const char *name,
1658 unsigned int valid_hooks,
1659 struct xt_table_info **pinfo,
1660 void **pentry0,
1661 unsigned int total_size,
1662 unsigned int number,
1663 unsigned int *hook_entries,
1664 unsigned int *underflows)
1665 {
1666 unsigned int i, j;
1667 struct xt_table_info *newinfo, *info;
1668 void *pos, *entry0, *entry1;
1669 struct compat_ip6t_entry *iter0;
1670 struct ip6t_entry *iter1;
1671 unsigned int size;
1672 int ret = 0;
1673
1674 info = *pinfo;
1675 entry0 = *pentry0;
1676 size = total_size;
1677 info->number = number;
1678
1679 /* Init all hooks to impossible value. */
1680 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1681 info->hook_entry[i] = 0xFFFFFFFF;
1682 info->underflow[i] = 0xFFFFFFFF;
1683 }
1684
1685 duprintf("translate_compat_table: size %u\n", info->size);
1686 j = 0;
1687 xt_compat_lock(AF_INET6);
1688 xt_compat_init_offsets(AF_INET6, number);
1689 /* Walk through entries, checking offsets. */
1690 xt_entry_foreach(iter0, entry0, total_size) {
1691 ret = check_compat_entry_size_and_hooks(iter0, info, &size,
1692 entry0,
1693 entry0 + total_size,
1694 hook_entries,
1695 underflows,
1696 name);
1697 if (ret != 0)
1698 goto out_unlock;
1699 ++j;
1700 }
1701
1702 ret = -EINVAL;
1703 if (j != number) {
1704 duprintf("translate_compat_table: %u not %u entries\n",
1705 j, number);
1706 goto out_unlock;
1707 }
1708
1709 /* Check hooks all assigned */
1710 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1711 /* Only hooks which are valid */
1712 if (!(valid_hooks & (1 << i)))
1713 continue;
1714 if (info->hook_entry[i] == 0xFFFFFFFF) {
1715 duprintf("Invalid hook entry %u %u\n",
1716 i, hook_entries[i]);
1717 goto out_unlock;
1718 }
1719 if (info->underflow[i] == 0xFFFFFFFF) {
1720 duprintf("Invalid underflow %u %u\n",
1721 i, underflows[i]);
1722 goto out_unlock;
1723 }
1724 }
1725
1726 ret = -ENOMEM;
1727 newinfo = xt_alloc_table_info(size);
1728 if (!newinfo)
1729 goto out_unlock;
1730
1731 newinfo->number = number;
1732 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1733 newinfo->hook_entry[i] = info->hook_entry[i];
1734 newinfo->underflow[i] = info->underflow[i];
1735 }
1736 entry1 = newinfo->entries;
1737 pos = entry1;
1738 size = total_size;
1739 xt_entry_foreach(iter0, entry0, total_size) {
1740 ret = compat_copy_entry_from_user(iter0, &pos, &size,
1741 name, newinfo, entry1);
1742 if (ret != 0)
1743 break;
1744 }
1745 xt_compat_flush_offsets(AF_INET6);
1746 xt_compat_unlock(AF_INET6);
1747 if (ret)
1748 goto free_newinfo;
1749
1750 ret = -ELOOP;
1751 if (!mark_source_chains(newinfo, valid_hooks, entry1))
1752 goto free_newinfo;
1753
1754 i = 0;
1755 xt_entry_foreach(iter1, entry1, newinfo->size) {
1756 ret = compat_check_entry(iter1, net, name);
1757 if (ret != 0)
1758 break;
1759 ++i;
1760 if (strcmp(ip6t_get_target(iter1)->u.user.name,
1761 XT_ERROR_TARGET) == 0)
1762 ++newinfo->stacksize;
1763 }
1764 if (ret) {
1765 /*
1766 * The first i matches need cleanup_entry (calls ->destroy)
1767 * because they had called ->check already. The other j-i
1768 * entries need only release.
1769 */
1770 int skip = i;
1771 j -= i;
1772 xt_entry_foreach(iter0, entry0, newinfo->size) {
1773 if (skip-- > 0)
1774 continue;
1775 if (j-- == 0)
1776 break;
1777 compat_release_entry(iter0);
1778 }
1779 xt_entry_foreach(iter1, entry1, newinfo->size) {
1780 if (i-- == 0)
1781 break;
1782 cleanup_entry(iter1, net);
1783 }
1784 xt_free_table_info(newinfo);
1785 return ret;
1786 }
1787
1788 *pinfo = newinfo;
1789 *pentry0 = entry1;
1790 xt_free_table_info(info);
1791 return 0;
1792
1793 free_newinfo:
1794 xt_free_table_info(newinfo);
1795 out:
1796 xt_entry_foreach(iter0, entry0, total_size) {
1797 if (j-- == 0)
1798 break;
1799 compat_release_entry(iter0);
1800 }
1801 return ret;
1802 out_unlock:
1803 xt_compat_flush_offsets(AF_INET6);
1804 xt_compat_unlock(AF_INET6);
1805 goto out;
1806 }
1807
1808 static int
1809 compat_do_replace(struct net *net, void __user *user, unsigned int len)
1810 {
1811 int ret;
1812 struct compat_ip6t_replace tmp;
1813 struct xt_table_info *newinfo;
1814 void *loc_cpu_entry;
1815 struct ip6t_entry *iter;
1816
1817 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1818 return -EFAULT;
1819
1820 /* overflow check */
1821 if (tmp.size >= INT_MAX / num_possible_cpus())
1822 return -ENOMEM;
1823 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1824 return -ENOMEM;
1825 if (tmp.num_counters == 0)
1826 return -EINVAL;
1827
1828 tmp.name[sizeof(tmp.name)-1] = 0;
1829
1830 newinfo = xt_alloc_table_info(tmp.size);
1831 if (!newinfo)
1832 return -ENOMEM;
1833
1834 loc_cpu_entry = newinfo->entries;
1835 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1836 tmp.size) != 0) {
1837 ret = -EFAULT;
1838 goto free_newinfo;
1839 }
1840
1841 ret = translate_compat_table(net, tmp.name, tmp.valid_hooks,
1842 &newinfo, &loc_cpu_entry, tmp.size,
1843 tmp.num_entries, tmp.hook_entry,
1844 tmp.underflow);
1845 if (ret != 0)
1846 goto free_newinfo;
1847
1848 duprintf("compat_do_replace: Translated table\n");
1849
1850 ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1851 tmp.num_counters, compat_ptr(tmp.counters));
1852 if (ret)
1853 goto free_newinfo_untrans;
1854 return 0;
1855
1856 free_newinfo_untrans:
1857 xt_entry_foreach(iter, loc_cpu_entry, newinfo->size)
1858 cleanup_entry(iter, net);
1859 free_newinfo:
1860 xt_free_table_info(newinfo);
1861 return ret;
1862 }
1863
1864 static int
1865 compat_do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user,
1866 unsigned int len)
1867 {
1868 int ret;
1869
1870 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
1871 return -EPERM;
1872
1873 switch (cmd) {
1874 case IP6T_SO_SET_REPLACE:
1875 ret = compat_do_replace(sock_net(sk), user, len);
1876 break;
1877
1878 case IP6T_SO_SET_ADD_COUNTERS:
1879 ret = do_add_counters(sock_net(sk), user, len, 1);
1880 break;
1881
1882 default:
1883 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1884 ret = -EINVAL;
1885 }
1886
1887 return ret;
1888 }
1889
1890 struct compat_ip6t_get_entries {
1891 char name[XT_TABLE_MAXNAMELEN];
1892 compat_uint_t size;
1893 struct compat_ip6t_entry entrytable[0];
1894 };
1895
1896 static int
1897 compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table,
1898 void __user *userptr)
1899 {
1900 struct xt_counters *counters;
1901 const struct xt_table_info *private = table->private;
1902 void __user *pos;
1903 unsigned int size;
1904 int ret = 0;
1905 unsigned int i = 0;
1906 struct ip6t_entry *iter;
1907
1908 counters = alloc_counters(table);
1909 if (IS_ERR(counters))
1910 return PTR_ERR(counters);
1911
1912 pos = userptr;
1913 size = total_size;
1914 xt_entry_foreach(iter, private->entries, total_size) {
1915 ret = compat_copy_entry_to_user(iter, &pos,
1916 &size, counters, i++);
1917 if (ret != 0)
1918 break;
1919 }
1920
1921 vfree(counters);
1922 return ret;
1923 }
1924
1925 static int
1926 compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr,
1927 int *len)
1928 {
1929 int ret;
1930 struct compat_ip6t_get_entries get;
1931 struct xt_table *t;
1932
1933 if (*len < sizeof(get)) {
1934 duprintf("compat_get_entries: %u < %zu\n", *len, sizeof(get));
1935 return -EINVAL;
1936 }
1937
1938 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1939 return -EFAULT;
1940
1941 if (*len != sizeof(struct compat_ip6t_get_entries) + get.size) {
1942 duprintf("compat_get_entries: %u != %zu\n",
1943 *len, sizeof(get) + get.size);
1944 return -EINVAL;
1945 }
1946
1947 xt_compat_lock(AF_INET6);
1948 t = xt_find_table_lock(net, AF_INET6, get.name);
1949 if (!IS_ERR_OR_NULL(t)) {
1950 const struct xt_table_info *private = t->private;
1951 struct xt_table_info info;
1952 duprintf("t->private->number = %u\n", private->number);
1953 ret = compat_table_info(private, &info);
1954 if (!ret && get.size == info.size) {
1955 ret = compat_copy_entries_to_user(private->size,
1956 t, uptr->entrytable);
1957 } else if (!ret) {
1958 duprintf("compat_get_entries: I've got %u not %u!\n",
1959 private->size, get.size);
1960 ret = -EAGAIN;
1961 }
1962 xt_compat_flush_offsets(AF_INET6);
1963 module_put(t->me);
1964 xt_table_unlock(t);
1965 } else
1966 ret = t ? PTR_ERR(t) : -ENOENT;
1967
1968 xt_compat_unlock(AF_INET6);
1969 return ret;
1970 }
1971
1972 static int do_ip6t_get_ctl(struct sock *, int, void __user *, int *);
1973
1974 static int
1975 compat_do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1976 {
1977 int ret;
1978
1979 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
1980 return -EPERM;
1981
1982 switch (cmd) {
1983 case IP6T_SO_GET_INFO:
1984 ret = get_info(sock_net(sk), user, len, 1);
1985 break;
1986 case IP6T_SO_GET_ENTRIES:
1987 ret = compat_get_entries(sock_net(sk), user, len);
1988 break;
1989 default:
1990 ret = do_ip6t_get_ctl(sk, cmd, user, len);
1991 }
1992 return ret;
1993 }
1994 #endif
1995
1996 static int
1997 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1998 {
1999 int ret;
2000
2001 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
2002 return -EPERM;
2003
2004 switch (cmd) {
2005 case IP6T_SO_SET_REPLACE:
2006 ret = do_replace(sock_net(sk), user, len);
2007 break;
2008
2009 case IP6T_SO_SET_ADD_COUNTERS:
2010 ret = do_add_counters(sock_net(sk), user, len, 0);
2011 break;
2012
2013 default:
2014 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
2015 ret = -EINVAL;
2016 }
2017
2018 return ret;
2019 }
2020
2021 static int
2022 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
2023 {
2024 int ret;
2025
2026 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
2027 return -EPERM;
2028
2029 switch (cmd) {
2030 case IP6T_SO_GET_INFO:
2031 ret = get_info(sock_net(sk), user, len, 0);
2032 break;
2033
2034 case IP6T_SO_GET_ENTRIES:
2035 ret = get_entries(sock_net(sk), user, len);
2036 break;
2037
2038 case IP6T_SO_GET_REVISION_MATCH:
2039 case IP6T_SO_GET_REVISION_TARGET: {
2040 struct xt_get_revision rev;
2041 int target;
2042
2043 if (*len != sizeof(rev)) {
2044 ret = -EINVAL;
2045 break;
2046 }
2047 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
2048 ret = -EFAULT;
2049 break;
2050 }
2051 rev.name[sizeof(rev.name)-1] = 0;
2052
2053 if (cmd == IP6T_SO_GET_REVISION_TARGET)
2054 target = 1;
2055 else
2056 target = 0;
2057
2058 try_then_request_module(xt_find_revision(AF_INET6, rev.name,
2059 rev.revision,
2060 target, &ret),
2061 "ip6t_%s", rev.name);
2062 break;
2063 }
2064
2065 default:
2066 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
2067 ret = -EINVAL;
2068 }
2069
2070 return ret;
2071 }
2072
2073 struct xt_table *ip6t_register_table(struct net *net,
2074 const struct xt_table *table,
2075 const struct ip6t_replace *repl)
2076 {
2077 int ret;
2078 struct xt_table_info *newinfo;
2079 struct xt_table_info bootstrap = {0};
2080 void *loc_cpu_entry;
2081 struct xt_table *new_table;
2082
2083 newinfo = xt_alloc_table_info(repl->size);
2084 if (!newinfo) {
2085 ret = -ENOMEM;
2086 goto out;
2087 }
2088
2089 loc_cpu_entry = newinfo->entries;
2090 memcpy(loc_cpu_entry, repl->entries, repl->size);
2091
2092 ret = translate_table(net, newinfo, loc_cpu_entry, repl);
2093 if (ret != 0)
2094 goto out_free;
2095
2096 new_table = xt_register_table(net, table, &bootstrap, newinfo);
2097 if (IS_ERR(new_table)) {
2098 ret = PTR_ERR(new_table);
2099 goto out_free;
2100 }
2101 return new_table;
2102
2103 out_free:
2104 xt_free_table_info(newinfo);
2105 out:
2106 return ERR_PTR(ret);
2107 }
2108
2109 void ip6t_unregister_table(struct net *net, struct xt_table *table)
2110 {
2111 struct xt_table_info *private;
2112 void *loc_cpu_entry;
2113 struct module *table_owner = table->me;
2114 struct ip6t_entry *iter;
2115
2116 private = xt_unregister_table(table);
2117
2118 /* Decrease module usage counts and free resources */
2119 loc_cpu_entry = private->entries;
2120 xt_entry_foreach(iter, loc_cpu_entry, private->size)
2121 cleanup_entry(iter, net);
2122 if (private->number > private->initial_entries)
2123 module_put(table_owner);
2124 xt_free_table_info(private);
2125 }
2126
2127 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
2128 static inline bool
2129 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
2130 u_int8_t type, u_int8_t code,
2131 bool invert)
2132 {
2133 return (type == test_type && code >= min_code && code <= max_code)
2134 ^ invert;
2135 }
2136
2137 static bool
2138 icmp6_match(const struct sk_buff *skb, struct xt_action_param *par)
2139 {
2140 const struct icmp6hdr *ic;
2141 struct icmp6hdr _icmph;
2142 const struct ip6t_icmp *icmpinfo = par->matchinfo;
2143
2144 /* Must not be a fragment. */
2145 if (par->fragoff != 0)
2146 return false;
2147
2148 ic = skb_header_pointer(skb, par->thoff, sizeof(_icmph), &_icmph);
2149 if (ic == NULL) {
2150 /* We've been asked to examine this packet, and we
2151 * can't. Hence, no choice but to drop.
2152 */
2153 duprintf("Dropping evil ICMP tinygram.\n");
2154 par->hotdrop = true;
2155 return false;
2156 }
2157
2158 return icmp6_type_code_match(icmpinfo->type,
2159 icmpinfo->code[0],
2160 icmpinfo->code[1],
2161 ic->icmp6_type, ic->icmp6_code,
2162 !!(icmpinfo->invflags&IP6T_ICMP_INV));
2163 }
2164
2165 /* Called when user tries to insert an entry of this type. */
2166 static int icmp6_checkentry(const struct xt_mtchk_param *par)
2167 {
2168 const struct ip6t_icmp *icmpinfo = par->matchinfo;
2169
2170 /* Must specify no unknown invflags */
2171 return (icmpinfo->invflags & ~IP6T_ICMP_INV) ? -EINVAL : 0;
2172 }
2173
2174 /* The built-in targets: standard (NULL) and error. */
2175 static struct xt_target ip6t_builtin_tg[] __read_mostly = {
2176 {
2177 .name = XT_STANDARD_TARGET,
2178 .targetsize = sizeof(int),
2179 .family = NFPROTO_IPV6,
2180 #ifdef CONFIG_COMPAT
2181 .compatsize = sizeof(compat_int_t),
2182 .compat_from_user = compat_standard_from_user,
2183 .compat_to_user = compat_standard_to_user,
2184 #endif
2185 },
2186 {
2187 .name = XT_ERROR_TARGET,
2188 .target = ip6t_error,
2189 .targetsize = XT_FUNCTION_MAXNAMELEN,
2190 .family = NFPROTO_IPV6,
2191 },
2192 };
2193
2194 static struct nf_sockopt_ops ip6t_sockopts = {
2195 .pf = PF_INET6,
2196 .set_optmin = IP6T_BASE_CTL,
2197 .set_optmax = IP6T_SO_SET_MAX+1,
2198 .set = do_ip6t_set_ctl,
2199 #ifdef CONFIG_COMPAT
2200 .compat_set = compat_do_ip6t_set_ctl,
2201 #endif
2202 .get_optmin = IP6T_BASE_CTL,
2203 .get_optmax = IP6T_SO_GET_MAX+1,
2204 .get = do_ip6t_get_ctl,
2205 #ifdef CONFIG_COMPAT
2206 .compat_get = compat_do_ip6t_get_ctl,
2207 #endif
2208 .owner = THIS_MODULE,
2209 };
2210
2211 static struct xt_match ip6t_builtin_mt[] __read_mostly = {
2212 {
2213 .name = "icmp6",
2214 .match = icmp6_match,
2215 .matchsize = sizeof(struct ip6t_icmp),
2216 .checkentry = icmp6_checkentry,
2217 .proto = IPPROTO_ICMPV6,
2218 .family = NFPROTO_IPV6,
2219 },
2220 };
2221
2222 static int __net_init ip6_tables_net_init(struct net *net)
2223 {
2224 return xt_proto_init(net, NFPROTO_IPV6);
2225 }
2226
2227 static void __net_exit ip6_tables_net_exit(struct net *net)
2228 {
2229 xt_proto_fini(net, NFPROTO_IPV6);
2230 }
2231
2232 static struct pernet_operations ip6_tables_net_ops = {
2233 .init = ip6_tables_net_init,
2234 .exit = ip6_tables_net_exit,
2235 };
2236
2237 static int __init ip6_tables_init(void)
2238 {
2239 int ret;
2240
2241 ret = register_pernet_subsys(&ip6_tables_net_ops);
2242 if (ret < 0)
2243 goto err1;
2244
2245 /* No one else will be downing sem now, so we won't sleep */
2246 ret = xt_register_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
2247 if (ret < 0)
2248 goto err2;
2249 ret = xt_register_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
2250 if (ret < 0)
2251 goto err4;
2252
2253 /* Register setsockopt */
2254 ret = nf_register_sockopt(&ip6t_sockopts);
2255 if (ret < 0)
2256 goto err5;
2257
2258 pr_info("(C) 2000-2006 Netfilter Core Team\n");
2259 return 0;
2260
2261 err5:
2262 xt_unregister_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
2263 err4:
2264 xt_unregister_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
2265 err2:
2266 unregister_pernet_subsys(&ip6_tables_net_ops);
2267 err1:
2268 return ret;
2269 }
2270
2271 static void __exit ip6_tables_fini(void)
2272 {
2273 nf_unregister_sockopt(&ip6t_sockopts);
2274
2275 xt_unregister_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
2276 xt_unregister_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
2277 unregister_pernet_subsys(&ip6_tables_net_ops);
2278 }
2279
2280 EXPORT_SYMBOL(ip6t_register_table);
2281 EXPORT_SYMBOL(ip6t_unregister_table);
2282 EXPORT_SYMBOL(ip6t_do_table);
2283
2284 module_init(ip6_tables_init);
2285 module_exit(ip6_tables_fini);
This page took 0.087086 seconds and 5 git commands to generate.