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