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