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