Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
[platform/kernel/linux-rpi.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 void *table_base;
287         const struct ip6t_entry *root;
288         const char *hookname, *chainname, *comment;
289         const struct ip6t_entry *iter;
290         unsigned int rulenum = 0;
291         struct net *net = dev_net(in ? in : out);
292
293         table_base = private->entries[smp_processor_id()];
294         root = get_entry(table_base, private->hook_entry[hook]);
295
296         hookname = chainname = hooknames[hook];
297         comment = comments[NF_IP6_TRACE_COMMENT_RULE];
298
299         xt_entry_foreach(iter, root, private->size - private->hook_entry[hook])
300                 if (get_chainname_rulenum(iter, e, hookname,
301                     &chainname, &comment, &rulenum) != 0)
302                         break;
303
304         nf_log_trace(net, AF_INET6, hook, skb, in, out, &trace_loginfo,
305                      "TRACE: %s:%s:%s:%u ",
306                      tablename, chainname, comment, rulenum);
307 }
308 #endif
309
310 static inline __pure struct ip6t_entry *
311 ip6t_next_entry(const struct ip6t_entry *entry)
312 {
313         return (void *)entry + entry->next_offset;
314 }
315
316 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
317 unsigned int
318 ip6t_do_table(struct sk_buff *skb,
319               unsigned int hook,
320               const struct nf_hook_state *state,
321               struct xt_table *table)
322 {
323         static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
324         /* Initializing verdict to NF_DROP keeps gcc happy. */
325         unsigned int verdict = NF_DROP;
326         const char *indev, *outdev;
327         const void *table_base;
328         struct ip6t_entry *e, **jumpstack;
329         unsigned int *stackptr, origptr, cpu;
330         const struct xt_table_info *private;
331         struct xt_action_param acpar;
332         unsigned int addend;
333
334         /* Initialization */
335         indev = state->in ? state->in->name : nulldevname;
336         outdev = state->out ? state->out->name : nulldevname;
337         /* We handle fragments by dealing with the first fragment as
338          * if it was a normal packet.  All other fragments are treated
339          * normally, except that they will NEVER match rules that ask
340          * things we don't know, ie. tcp syn flag or ports).  If the
341          * rule is also a fragment-specific rule, non-fragments won't
342          * match it. */
343         acpar.hotdrop = false;
344         acpar.in      = state->in;
345         acpar.out     = state->out;
346         acpar.family  = NFPROTO_IPV6;
347         acpar.hooknum = hook;
348
349         IP_NF_ASSERT(table->valid_hooks & (1 << hook));
350
351         local_bh_disable();
352         addend = xt_write_recseq_begin();
353         private = table->private;
354         /*
355          * Ensure we load private-> members after we've fetched the base
356          * pointer.
357          */
358         smp_read_barrier_depends();
359         cpu        = smp_processor_id();
360         table_base = private->entries[cpu];
361         jumpstack  = (struct ip6t_entry **)private->jumpstack[cpu];
362         stackptr   = per_cpu_ptr(private->stackptr, cpu);
363         origptr    = *stackptr;
364
365         e = get_entry(table_base, private->hook_entry[hook]);
366
367         do {
368                 const struct xt_entry_target *t;
369                 const struct xt_entry_match *ematch;
370
371                 IP_NF_ASSERT(e);
372                 acpar.thoff = 0;
373                 if (!ip6_packet_match(skb, indev, outdev, &e->ipv6,
374                     &acpar.thoff, &acpar.fragoff, &acpar.hotdrop)) {
375  no_match:
376                         e = ip6t_next_entry(e);
377                         continue;
378                 }
379
380                 xt_ematch_foreach(ematch, e) {
381                         acpar.match     = ematch->u.kernel.match;
382                         acpar.matchinfo = ematch->data;
383                         if (!acpar.match->match(skb, &acpar))
384                                 goto no_match;
385                 }
386
387                 ADD_COUNTER(e->counters, skb->len, 1);
388
389                 t = ip6t_get_target_c(e);
390                 IP_NF_ASSERT(t->u.kernel.target);
391
392 #if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
393                 /* The packet is traced: log it */
394                 if (unlikely(skb->nf_trace))
395                         trace_packet(skb, hook, state->in, state->out,
396                                      table->name, private, e);
397 #endif
398                 /* Standard target? */
399                 if (!t->u.kernel.target->target) {
400                         int v;
401
402                         v = ((struct xt_standard_target *)t)->verdict;
403                         if (v < 0) {
404                                 /* Pop from stack? */
405                                 if (v != XT_RETURN) {
406                                         verdict = (unsigned int)(-v) - 1;
407                                         break;
408                                 }
409                                 if (*stackptr <= origptr)
410                                         e = get_entry(table_base,
411                                             private->underflow[hook]);
412                                 else
413                                         e = ip6t_next_entry(jumpstack[--*stackptr]);
414                                 continue;
415                         }
416                         if (table_base + v != ip6t_next_entry(e) &&
417                             !(e->ipv6.flags & IP6T_F_GOTO)) {
418                                 if (*stackptr >= private->stacksize) {
419                                         verdict = NF_DROP;
420                                         break;
421                                 }
422                                 jumpstack[(*stackptr)++] = e;
423                         }
424
425                         e = get_entry(table_base, v);
426                         continue;
427                 }
428
429                 acpar.target   = t->u.kernel.target;
430                 acpar.targinfo = t->data;
431
432                 verdict = t->u.kernel.target->target(skb, &acpar);
433                 if (verdict == XT_CONTINUE)
434                         e = ip6t_next_entry(e);
435                 else
436                         /* Verdict */
437                         break;
438         } while (!acpar.hotdrop);
439
440         *stackptr = origptr;
441
442         xt_write_recseq_end(addend);
443         local_bh_enable();
444
445 #ifdef DEBUG_ALLOW_ALL
446         return NF_ACCEPT;
447 #else
448         if (acpar.hotdrop)
449                 return NF_DROP;
450         else return verdict;
451 #endif
452 }
453
454 /* Figures out from what hook each rule can be called: returns 0 if
455    there are loops.  Puts hook bitmask in comefrom. */
456 static int
457 mark_source_chains(const struct xt_table_info *newinfo,
458                    unsigned int valid_hooks, void *entry0)
459 {
460         unsigned int hook;
461
462         /* No recursion; use packet counter to save back ptrs (reset
463            to 0 as we leave), and comefrom to save source hook bitmask */
464         for (hook = 0; hook < NF_INET_NUMHOOKS; hook++) {
465                 unsigned int pos = newinfo->hook_entry[hook];
466                 struct ip6t_entry *e = (struct ip6t_entry *)(entry0 + pos);
467
468                 if (!(valid_hooks & (1 << hook)))
469                         continue;
470
471                 /* Set initial back pointer. */
472                 e->counters.pcnt = pos;
473
474                 for (;;) {
475                         const struct xt_standard_target *t
476                                 = (void *)ip6t_get_target_c(e);
477                         int visited = e->comefrom & (1 << hook);
478
479                         if (e->comefrom & (1 << NF_INET_NUMHOOKS)) {
480                                 pr_err("iptables: loop hook %u pos %u %08X.\n",
481                                        hook, pos, e->comefrom);
482                                 return 0;
483                         }
484                         e->comefrom |= ((1 << hook) | (1 << NF_INET_NUMHOOKS));
485
486                         /* Unconditional return/END. */
487                         if ((e->target_offset == sizeof(struct ip6t_entry) &&
488                              (strcmp(t->target.u.user.name,
489                                      XT_STANDARD_TARGET) == 0) &&
490                              t->verdict < 0 &&
491                              unconditional(&e->ipv6)) || visited) {
492                                 unsigned int oldpos, size;
493
494                                 if ((strcmp(t->target.u.user.name,
495                                             XT_STANDARD_TARGET) == 0) &&
496                                     t->verdict < -NF_MAX_VERDICT - 1) {
497                                         duprintf("mark_source_chains: bad "
498                                                 "negative verdict (%i)\n",
499                                                                 t->verdict);
500                                         return 0;
501                                 }
502
503                                 /* Return: backtrack through the last
504                                    big jump. */
505                                 do {
506                                         e->comefrom ^= (1<<NF_INET_NUMHOOKS);
507 #ifdef DEBUG_IP_FIREWALL_USER
508                                         if (e->comefrom
509                                             & (1 << NF_INET_NUMHOOKS)) {
510                                                 duprintf("Back unset "
511                                                          "on hook %u "
512                                                          "rule %u\n",
513                                                          hook, pos);
514                                         }
515 #endif
516                                         oldpos = pos;
517                                         pos = e->counters.pcnt;
518                                         e->counters.pcnt = 0;
519
520                                         /* We're at the start. */
521                                         if (pos == oldpos)
522                                                 goto next;
523
524                                         e = (struct ip6t_entry *)
525                                                 (entry0 + pos);
526                                 } while (oldpos == pos + e->next_offset);
527
528                                 /* Move along one */
529                                 size = e->next_offset;
530                                 e = (struct ip6t_entry *)
531                                         (entry0 + pos + size);
532                                 e->counters.pcnt = pos;
533                                 pos += size;
534                         } else {
535                                 int newpos = t->verdict;
536
537                                 if (strcmp(t->target.u.user.name,
538                                            XT_STANDARD_TARGET) == 0 &&
539                                     newpos >= 0) {
540                                         if (newpos > newinfo->size -
541                                                 sizeof(struct ip6t_entry)) {
542                                                 duprintf("mark_source_chains: "
543                                                         "bad verdict (%i)\n",
544                                                                 newpos);
545                                                 return 0;
546                                         }
547                                         /* This a jump; chase it. */
548                                         duprintf("Jump rule %u -> %u\n",
549                                                  pos, newpos);
550                                 } else {
551                                         /* ... this is a fallthru */
552                                         newpos = pos + e->next_offset;
553                                 }
554                                 e = (struct ip6t_entry *)
555                                         (entry0 + newpos);
556                                 e->counters.pcnt = pos;
557                                 pos = newpos;
558                         }
559                 }
560                 next:
561                 duprintf("Finished chain %u\n", hook);
562         }
563         return 1;
564 }
565
566 static void cleanup_match(struct xt_entry_match *m, struct net *net)
567 {
568         struct xt_mtdtor_param par;
569
570         par.net       = net;
571         par.match     = m->u.kernel.match;
572         par.matchinfo = m->data;
573         par.family    = NFPROTO_IPV6;
574         if (par.match->destroy != NULL)
575                 par.match->destroy(&par);
576         module_put(par.match->me);
577 }
578
579 static int
580 check_entry(const struct ip6t_entry *e, const char *name)
581 {
582         const struct xt_entry_target *t;
583
584         if (!ip6_checkentry(&e->ipv6)) {
585                 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
586                 return -EINVAL;
587         }
588
589         if (e->target_offset + sizeof(struct xt_entry_target) >
590             e->next_offset)
591                 return -EINVAL;
592
593         t = ip6t_get_target_c(e);
594         if (e->target_offset + t->u.target_size > e->next_offset)
595                 return -EINVAL;
596
597         return 0;
598 }
599
600 static int check_match(struct xt_entry_match *m, struct xt_mtchk_param *par)
601 {
602         const struct ip6t_ip6 *ipv6 = par->entryinfo;
603         int ret;
604
605         par->match     = m->u.kernel.match;
606         par->matchinfo = m->data;
607
608         ret = xt_check_match(par, m->u.match_size - sizeof(*m),
609                              ipv6->proto, ipv6->invflags & IP6T_INV_PROTO);
610         if (ret < 0) {
611                 duprintf("ip_tables: check failed for `%s'.\n",
612                          par.match->name);
613                 return ret;
614         }
615         return 0;
616 }
617
618 static int
619 find_check_match(struct xt_entry_match *m, struct xt_mtchk_param *par)
620 {
621         struct xt_match *match;
622         int ret;
623
624         match = xt_request_find_match(NFPROTO_IPV6, m->u.user.name,
625                                       m->u.user.revision);
626         if (IS_ERR(match)) {
627                 duprintf("find_check_match: `%s' not found\n", m->u.user.name);
628                 return PTR_ERR(match);
629         }
630         m->u.kernel.match = match;
631
632         ret = check_match(m, par);
633         if (ret)
634                 goto err;
635
636         return 0;
637 err:
638         module_put(m->u.kernel.match->me);
639         return ret;
640 }
641
642 static int check_target(struct ip6t_entry *e, struct net *net, const char *name)
643 {
644         struct xt_entry_target *t = ip6t_get_target(e);
645         struct xt_tgchk_param par = {
646                 .net       = net,
647                 .table     = name,
648                 .entryinfo = e,
649                 .target    = t->u.kernel.target,
650                 .targinfo  = t->data,
651                 .hook_mask = e->comefrom,
652                 .family    = NFPROTO_IPV6,
653         };
654         int ret;
655
656         t = ip6t_get_target(e);
657         ret = xt_check_target(&par, t->u.target_size - sizeof(*t),
658               e->ipv6.proto, e->ipv6.invflags & IP6T_INV_PROTO);
659         if (ret < 0) {
660                 duprintf("ip_tables: check failed for `%s'.\n",
661                          t->u.kernel.target->name);
662                 return ret;
663         }
664         return 0;
665 }
666
667 static int
668 find_check_entry(struct ip6t_entry *e, struct net *net, const char *name,
669                  unsigned int size)
670 {
671         struct xt_entry_target *t;
672         struct xt_target *target;
673         int ret;
674         unsigned int j;
675         struct xt_mtchk_param mtpar;
676         struct xt_entry_match *ematch;
677
678         ret = check_entry(e, name);
679         if (ret)
680                 return ret;
681
682         j = 0;
683         mtpar.net       = net;
684         mtpar.table     = name;
685         mtpar.entryinfo = &e->ipv6;
686         mtpar.hook_mask = e->comefrom;
687         mtpar.family    = NFPROTO_IPV6;
688         xt_ematch_foreach(ematch, e) {
689                 ret = find_check_match(ematch, &mtpar);
690                 if (ret != 0)
691                         goto cleanup_matches;
692                 ++j;
693         }
694
695         t = ip6t_get_target(e);
696         target = xt_request_find_target(NFPROTO_IPV6, t->u.user.name,
697                                         t->u.user.revision);
698         if (IS_ERR(target)) {
699                 duprintf("find_check_entry: `%s' not found\n", t->u.user.name);
700                 ret = PTR_ERR(target);
701                 goto cleanup_matches;
702         }
703         t->u.kernel.target = target;
704
705         ret = check_target(e, net, name);
706         if (ret)
707                 goto err;
708         return 0;
709  err:
710         module_put(t->u.kernel.target->me);
711  cleanup_matches:
712         xt_ematch_foreach(ematch, e) {
713                 if (j-- == 0)
714                         break;
715                 cleanup_match(ematch, net);
716         }
717         return ret;
718 }
719
720 static bool check_underflow(const struct ip6t_entry *e)
721 {
722         const struct xt_entry_target *t;
723         unsigned int verdict;
724
725         if (!unconditional(&e->ipv6))
726                 return false;
727         t = ip6t_get_target_c(e);
728         if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
729                 return false;
730         verdict = ((struct xt_standard_target *)t)->verdict;
731         verdict = -verdict - 1;
732         return verdict == NF_DROP || verdict == NF_ACCEPT;
733 }
734
735 static int
736 check_entry_size_and_hooks(struct ip6t_entry *e,
737                            struct xt_table_info *newinfo,
738                            const unsigned char *base,
739                            const unsigned char *limit,
740                            const unsigned int *hook_entries,
741                            const unsigned int *underflows,
742                            unsigned int valid_hooks)
743 {
744         unsigned int h;
745
746         if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0 ||
747             (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
748                 duprintf("Bad offset %p\n", e);
749                 return -EINVAL;
750         }
751
752         if (e->next_offset
753             < sizeof(struct ip6t_entry) + sizeof(struct xt_entry_target)) {
754                 duprintf("checking: element %p size %u\n",
755                          e, e->next_offset);
756                 return -EINVAL;
757         }
758
759         /* Check hooks & underflows */
760         for (h = 0; h < NF_INET_NUMHOOKS; h++) {
761                 if (!(valid_hooks & (1 << h)))
762                         continue;
763                 if ((unsigned char *)e - base == hook_entries[h])
764                         newinfo->hook_entry[h] = hook_entries[h];
765                 if ((unsigned char *)e - base == underflows[h]) {
766                         if (!check_underflow(e)) {
767                                 pr_err("Underflows must be unconditional and "
768                                        "use the STANDARD target with "
769                                        "ACCEPT/DROP\n");
770                                 return -EINVAL;
771                         }
772                         newinfo->underflow[h] = underflows[h];
773                 }
774         }
775
776         /* Clear counters and comefrom */
777         e->counters = ((struct xt_counters) { 0, 0 });
778         e->comefrom = 0;
779         return 0;
780 }
781
782 static void cleanup_entry(struct ip6t_entry *e, struct net *net)
783 {
784         struct xt_tgdtor_param par;
785         struct xt_entry_target *t;
786         struct xt_entry_match *ematch;
787
788         /* Cleanup all matches */
789         xt_ematch_foreach(ematch, e)
790                 cleanup_match(ematch, net);
791         t = ip6t_get_target(e);
792
793         par.net      = net;
794         par.target   = t->u.kernel.target;
795         par.targinfo = t->data;
796         par.family   = NFPROTO_IPV6;
797         if (par.target->destroy != NULL)
798                 par.target->destroy(&par);
799         module_put(par.target->me);
800 }
801
802 /* Checks and translates the user-supplied table segment (held in
803    newinfo) */
804 static int
805 translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0,
806                 const struct ip6t_replace *repl)
807 {
808         struct ip6t_entry *iter;
809         unsigned int i;
810         int ret = 0;
811
812         newinfo->size = repl->size;
813         newinfo->number = repl->num_entries;
814
815         /* Init all hooks to impossible value. */
816         for (i = 0; i < NF_INET_NUMHOOKS; i++) {
817                 newinfo->hook_entry[i] = 0xFFFFFFFF;
818                 newinfo->underflow[i] = 0xFFFFFFFF;
819         }
820
821         duprintf("translate_table: size %u\n", newinfo->size);
822         i = 0;
823         /* Walk through entries, checking offsets. */
824         xt_entry_foreach(iter, entry0, newinfo->size) {
825                 ret = check_entry_size_and_hooks(iter, newinfo, entry0,
826                                                  entry0 + repl->size,
827                                                  repl->hook_entry,
828                                                  repl->underflow,
829                                                  repl->valid_hooks);
830                 if (ret != 0)
831                         return ret;
832                 ++i;
833                 if (strcmp(ip6t_get_target(iter)->u.user.name,
834                     XT_ERROR_TARGET) == 0)
835                         ++newinfo->stacksize;
836         }
837
838         if (i != repl->num_entries) {
839                 duprintf("translate_table: %u not %u entries\n",
840                          i, repl->num_entries);
841                 return -EINVAL;
842         }
843
844         /* Check hooks all assigned */
845         for (i = 0; i < NF_INET_NUMHOOKS; i++) {
846                 /* Only hooks which are valid */
847                 if (!(repl->valid_hooks & (1 << i)))
848                         continue;
849                 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
850                         duprintf("Invalid hook entry %u %u\n",
851                                  i, repl->hook_entry[i]);
852                         return -EINVAL;
853                 }
854                 if (newinfo->underflow[i] == 0xFFFFFFFF) {
855                         duprintf("Invalid underflow %u %u\n",
856                                  i, repl->underflow[i]);
857                         return -EINVAL;
858                 }
859         }
860
861         if (!mark_source_chains(newinfo, repl->valid_hooks, entry0))
862                 return -ELOOP;
863
864         /* Finally, each sanity check must pass */
865         i = 0;
866         xt_entry_foreach(iter, entry0, newinfo->size) {
867                 ret = find_check_entry(iter, net, repl->name, repl->size);
868                 if (ret != 0)
869                         break;
870                 ++i;
871         }
872
873         if (ret != 0) {
874                 xt_entry_foreach(iter, entry0, newinfo->size) {
875                         if (i-- == 0)
876                                 break;
877                         cleanup_entry(iter, net);
878                 }
879                 return ret;
880         }
881
882         /* And one copy for every other CPU */
883         for_each_possible_cpu(i) {
884                 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
885                         memcpy(newinfo->entries[i], entry0, newinfo->size);
886         }
887
888         return ret;
889 }
890
891 static void
892 get_counters(const struct xt_table_info *t,
893              struct xt_counters counters[])
894 {
895         struct ip6t_entry *iter;
896         unsigned int cpu;
897         unsigned int i;
898
899         for_each_possible_cpu(cpu) {
900                 seqcount_t *s = &per_cpu(xt_recseq, cpu);
901
902                 i = 0;
903                 xt_entry_foreach(iter, t->entries[cpu], t->size) {
904                         u64 bcnt, pcnt;
905                         unsigned int start;
906
907                         do {
908                                 start = read_seqcount_begin(s);
909                                 bcnt = iter->counters.bcnt;
910                                 pcnt = iter->counters.pcnt;
911                         } while (read_seqcount_retry(s, start));
912
913                         ADD_COUNTER(counters[i], bcnt, pcnt);
914                         ++i;
915                 }
916         }
917 }
918
919 static struct xt_counters *alloc_counters(const struct xt_table *table)
920 {
921         unsigned int countersize;
922         struct xt_counters *counters;
923         const struct xt_table_info *private = table->private;
924
925         /* We need atomic snapshot of counters: rest doesn't change
926            (other than comefrom, which userspace doesn't care
927            about). */
928         countersize = sizeof(struct xt_counters) * private->number;
929         counters = vzalloc(countersize);
930
931         if (counters == NULL)
932                 return ERR_PTR(-ENOMEM);
933
934         get_counters(private, counters);
935
936         return counters;
937 }
938
939 static int
940 copy_entries_to_user(unsigned int total_size,
941                      const struct xt_table *table,
942                      void __user *userptr)
943 {
944         unsigned int off, num;
945         const struct ip6t_entry *e;
946         struct xt_counters *counters;
947         const struct xt_table_info *private = table->private;
948         int ret = 0;
949         const void *loc_cpu_entry;
950
951         counters = alloc_counters(table);
952         if (IS_ERR(counters))
953                 return PTR_ERR(counters);
954
955         /* choose the copy that is on our node/cpu, ...
956          * This choice is lazy (because current thread is
957          * allowed to migrate to another cpu)
958          */
959         loc_cpu_entry = private->entries[raw_smp_processor_id()];
960         if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
961                 ret = -EFAULT;
962                 goto free_counters;
963         }
964
965         /* FIXME: use iterator macros --RR */
966         /* ... then go back and fix counters and names */
967         for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
968                 unsigned int i;
969                 const struct xt_entry_match *m;
970                 const struct xt_entry_target *t;
971
972                 e = (struct ip6t_entry *)(loc_cpu_entry + off);
973                 if (copy_to_user(userptr + off
974                                  + offsetof(struct ip6t_entry, counters),
975                                  &counters[num],
976                                  sizeof(counters[num])) != 0) {
977                         ret = -EFAULT;
978                         goto free_counters;
979                 }
980
981                 for (i = sizeof(struct ip6t_entry);
982                      i < e->target_offset;
983                      i += m->u.match_size) {
984                         m = (void *)e + i;
985
986                         if (copy_to_user(userptr + off + i
987                                          + offsetof(struct xt_entry_match,
988                                                     u.user.name),
989                                          m->u.kernel.match->name,
990                                          strlen(m->u.kernel.match->name)+1)
991                             != 0) {
992                                 ret = -EFAULT;
993                                 goto free_counters;
994                         }
995                 }
996
997                 t = ip6t_get_target_c(e);
998                 if (copy_to_user(userptr + off + e->target_offset
999                                  + offsetof(struct xt_entry_target,
1000                                             u.user.name),
1001                                  t->u.kernel.target->name,
1002                                  strlen(t->u.kernel.target->name)+1) != 0) {
1003                         ret = -EFAULT;
1004                         goto free_counters;
1005                 }
1006         }
1007
1008  free_counters:
1009         vfree(counters);
1010         return ret;
1011 }
1012
1013 #ifdef CONFIG_COMPAT
1014 static void compat_standard_from_user(void *dst, const void *src)
1015 {
1016         int v = *(compat_int_t *)src;
1017
1018         if (v > 0)
1019                 v += xt_compat_calc_jump(AF_INET6, v);
1020         memcpy(dst, &v, sizeof(v));
1021 }
1022
1023 static int compat_standard_to_user(void __user *dst, const void *src)
1024 {
1025         compat_int_t cv = *(int *)src;
1026
1027         if (cv > 0)
1028                 cv -= xt_compat_calc_jump(AF_INET6, cv);
1029         return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
1030 }
1031
1032 static int compat_calc_entry(const struct ip6t_entry *e,
1033                              const struct xt_table_info *info,
1034                              const void *base, struct xt_table_info *newinfo)
1035 {
1036         const struct xt_entry_match *ematch;
1037         const struct xt_entry_target *t;
1038         unsigned int entry_offset;
1039         int off, i, ret;
1040
1041         off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1042         entry_offset = (void *)e - base;
1043         xt_ematch_foreach(ematch, e)
1044                 off += xt_compat_match_offset(ematch->u.kernel.match);
1045         t = ip6t_get_target_c(e);
1046         off += xt_compat_target_offset(t->u.kernel.target);
1047         newinfo->size -= off;
1048         ret = xt_compat_add_offset(AF_INET6, entry_offset, off);
1049         if (ret)
1050                 return ret;
1051
1052         for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1053                 if (info->hook_entry[i] &&
1054                     (e < (struct ip6t_entry *)(base + info->hook_entry[i])))
1055                         newinfo->hook_entry[i] -= off;
1056                 if (info->underflow[i] &&
1057                     (e < (struct ip6t_entry *)(base + info->underflow[i])))
1058                         newinfo->underflow[i] -= off;
1059         }
1060         return 0;
1061 }
1062
1063 static int compat_table_info(const struct xt_table_info *info,
1064                              struct xt_table_info *newinfo)
1065 {
1066         struct ip6t_entry *iter;
1067         void *loc_cpu_entry;
1068         int ret;
1069
1070         if (!newinfo || !info)
1071                 return -EINVAL;
1072
1073         /* we dont care about newinfo->entries[] */
1074         memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
1075         newinfo->initial_entries = 0;
1076         loc_cpu_entry = info->entries[raw_smp_processor_id()];
1077         xt_compat_init_offsets(AF_INET6, info->number);
1078         xt_entry_foreach(iter, loc_cpu_entry, info->size) {
1079                 ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo);
1080                 if (ret != 0)
1081                         return ret;
1082         }
1083         return 0;
1084 }
1085 #endif
1086
1087 static int get_info(struct net *net, void __user *user,
1088                     const int *len, int compat)
1089 {
1090         char name[XT_TABLE_MAXNAMELEN];
1091         struct xt_table *t;
1092         int ret;
1093
1094         if (*len != sizeof(struct ip6t_getinfo)) {
1095                 duprintf("length %u != %zu\n", *len,
1096                          sizeof(struct ip6t_getinfo));
1097                 return -EINVAL;
1098         }
1099
1100         if (copy_from_user(name, user, sizeof(name)) != 0)
1101                 return -EFAULT;
1102
1103         name[XT_TABLE_MAXNAMELEN-1] = '\0';
1104 #ifdef CONFIG_COMPAT
1105         if (compat)
1106                 xt_compat_lock(AF_INET6);
1107 #endif
1108         t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
1109                                     "ip6table_%s", name);
1110         if (!IS_ERR_OR_NULL(t)) {
1111                 struct ip6t_getinfo info;
1112                 const struct xt_table_info *private = t->private;
1113 #ifdef CONFIG_COMPAT
1114                 struct xt_table_info tmp;
1115
1116                 if (compat) {
1117                         ret = compat_table_info(private, &tmp);
1118                         xt_compat_flush_offsets(AF_INET6);
1119                         private = &tmp;
1120                 }
1121 #endif
1122                 memset(&info, 0, sizeof(info));
1123                 info.valid_hooks = t->valid_hooks;
1124                 memcpy(info.hook_entry, private->hook_entry,
1125                        sizeof(info.hook_entry));
1126                 memcpy(info.underflow, private->underflow,
1127                        sizeof(info.underflow));
1128                 info.num_entries = private->number;
1129                 info.size = private->size;
1130                 strcpy(info.name, name);
1131
1132                 if (copy_to_user(user, &info, *len) != 0)
1133                         ret = -EFAULT;
1134                 else
1135                         ret = 0;
1136
1137                 xt_table_unlock(t);
1138                 module_put(t->me);
1139         } else
1140                 ret = t ? PTR_ERR(t) : -ENOENT;
1141 #ifdef CONFIG_COMPAT
1142         if (compat)
1143                 xt_compat_unlock(AF_INET6);
1144 #endif
1145         return ret;
1146 }
1147
1148 static int
1149 get_entries(struct net *net, struct ip6t_get_entries __user *uptr,
1150             const int *len)
1151 {
1152         int ret;
1153         struct ip6t_get_entries get;
1154         struct xt_table *t;
1155
1156         if (*len < sizeof(get)) {
1157                 duprintf("get_entries: %u < %zu\n", *len, sizeof(get));
1158                 return -EINVAL;
1159         }
1160         if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1161                 return -EFAULT;
1162         if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1163                 duprintf("get_entries: %u != %zu\n",
1164                          *len, sizeof(get) + get.size);
1165                 return -EINVAL;
1166         }
1167
1168         t = xt_find_table_lock(net, AF_INET6, get.name);
1169         if (!IS_ERR_OR_NULL(t)) {
1170                 struct xt_table_info *private = t->private;
1171                 duprintf("t->private->number = %u\n", private->number);
1172                 if (get.size == private->size)
1173                         ret = copy_entries_to_user(private->size,
1174                                                    t, uptr->entrytable);
1175                 else {
1176                         duprintf("get_entries: I've got %u not %u!\n",
1177                                  private->size, get.size);
1178                         ret = -EAGAIN;
1179                 }
1180                 module_put(t->me);
1181                 xt_table_unlock(t);
1182         } else
1183                 ret = t ? PTR_ERR(t) : -ENOENT;
1184
1185         return ret;
1186 }
1187
1188 static int
1189 __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
1190              struct xt_table_info *newinfo, unsigned int num_counters,
1191              void __user *counters_ptr)
1192 {
1193         int ret;
1194         struct xt_table *t;
1195         struct xt_table_info *oldinfo;
1196         struct xt_counters *counters;
1197         const void *loc_cpu_old_entry;
1198         struct ip6t_entry *iter;
1199
1200         ret = 0;
1201         counters = vzalloc(num_counters * sizeof(struct xt_counters));
1202         if (!counters) {
1203                 ret = -ENOMEM;
1204                 goto out;
1205         }
1206
1207         t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
1208                                     "ip6table_%s", name);
1209         if (IS_ERR_OR_NULL(t)) {
1210                 ret = t ? PTR_ERR(t) : -ENOENT;
1211                 goto free_newinfo_counters_untrans;
1212         }
1213
1214         /* You lied! */
1215         if (valid_hooks != t->valid_hooks) {
1216                 duprintf("Valid hook crap: %08X vs %08X\n",
1217                          valid_hooks, t->valid_hooks);
1218                 ret = -EINVAL;
1219                 goto put_module;
1220         }
1221
1222         oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);
1223         if (!oldinfo)
1224                 goto put_module;
1225
1226         /* Update module usage count based on number of rules */
1227         duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1228                 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1229         if ((oldinfo->number > oldinfo->initial_entries) ||
1230             (newinfo->number <= oldinfo->initial_entries))
1231                 module_put(t->me);
1232         if ((oldinfo->number > oldinfo->initial_entries) &&
1233             (newinfo->number <= oldinfo->initial_entries))
1234                 module_put(t->me);
1235
1236         /* Get the old counters, and synchronize with replace */
1237         get_counters(oldinfo, counters);
1238
1239         /* Decrease module usage counts and free resource */
1240         loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1241         xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size)
1242                 cleanup_entry(iter, net);
1243
1244         xt_free_table_info(oldinfo);
1245         if (copy_to_user(counters_ptr, counters,
1246                          sizeof(struct xt_counters) * num_counters) != 0) {
1247                 /* Silent error, can't fail, new table is already in place */
1248                 net_warn_ratelimited("ip6tables: counters copy to user failed while replacing table\n");
1249         }
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         unsigned int addend;
1329 #ifdef CONFIG_COMPAT
1330         struct compat_xt_counters_info compat_tmp;
1331
1332         if (compat) {
1333                 ptmp = &compat_tmp;
1334                 size = sizeof(struct compat_xt_counters_info);
1335         } else
1336 #endif
1337         {
1338                 ptmp = &tmp;
1339                 size = sizeof(struct xt_counters_info);
1340         }
1341
1342         if (copy_from_user(ptmp, user, size) != 0)
1343                 return -EFAULT;
1344
1345 #ifdef CONFIG_COMPAT
1346         if (compat) {
1347                 num_counters = compat_tmp.num_counters;
1348                 name = compat_tmp.name;
1349         } else
1350 #endif
1351         {
1352                 num_counters = tmp.num_counters;
1353                 name = tmp.name;
1354         }
1355
1356         if (len != size + num_counters * sizeof(struct xt_counters))
1357                 return -EINVAL;
1358
1359         paddc = vmalloc(len - size);
1360         if (!paddc)
1361                 return -ENOMEM;
1362
1363         if (copy_from_user(paddc, user + size, len - size) != 0) {
1364                 ret = -EFAULT;
1365                 goto free;
1366         }
1367
1368         t = xt_find_table_lock(net, AF_INET6, name);
1369         if (IS_ERR_OR_NULL(t)) {
1370                 ret = t ? PTR_ERR(t) : -ENOENT;
1371                 goto free;
1372         }
1373
1374
1375         local_bh_disable();
1376         private = t->private;
1377         if (private->number != num_counters) {
1378                 ret = -EINVAL;
1379                 goto unlock_up_free;
1380         }
1381
1382         i = 0;
1383         /* Choose the copy that is on our node */
1384         curcpu = smp_processor_id();
1385         addend = xt_write_recseq_begin();
1386         loc_cpu_entry = private->entries[curcpu];
1387         xt_entry_foreach(iter, loc_cpu_entry, private->size) {
1388                 ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt);
1389                 ++i;
1390         }
1391         xt_write_recseq_end(addend);
1392
1393  unlock_up_free:
1394         local_bh_enable();
1395         xt_table_unlock(t);
1396         module_put(t->me);
1397  free:
1398         vfree(paddc);
1399
1400         return ret;
1401 }
1402
1403 #ifdef CONFIG_COMPAT
1404 struct compat_ip6t_replace {
1405         char                    name[XT_TABLE_MAXNAMELEN];
1406         u32                     valid_hooks;
1407         u32                     num_entries;
1408         u32                     size;
1409         u32                     hook_entry[NF_INET_NUMHOOKS];
1410         u32                     underflow[NF_INET_NUMHOOKS];
1411         u32                     num_counters;
1412         compat_uptr_t           counters;       /* struct xt_counters * */
1413         struct compat_ip6t_entry entries[0];
1414 };
1415
1416 static int
1417 compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr,
1418                           unsigned int *size, struct xt_counters *counters,
1419                           unsigned int i)
1420 {
1421         struct xt_entry_target *t;
1422         struct compat_ip6t_entry __user *ce;
1423         u_int16_t target_offset, next_offset;
1424         compat_uint_t origsize;
1425         const struct xt_entry_match *ematch;
1426         int ret = 0;
1427
1428         origsize = *size;
1429         ce = (struct compat_ip6t_entry __user *)*dstptr;
1430         if (copy_to_user(ce, e, sizeof(struct ip6t_entry)) != 0 ||
1431             copy_to_user(&ce->counters, &counters[i],
1432             sizeof(counters[i])) != 0)
1433                 return -EFAULT;
1434
1435         *dstptr += sizeof(struct compat_ip6t_entry);
1436         *size -= sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1437
1438         xt_ematch_foreach(ematch, e) {
1439                 ret = xt_compat_match_to_user(ematch, dstptr, size);
1440                 if (ret != 0)
1441                         return ret;
1442         }
1443         target_offset = e->target_offset - (origsize - *size);
1444         t = ip6t_get_target(e);
1445         ret = xt_compat_target_to_user(t, dstptr, size);
1446         if (ret)
1447                 return ret;
1448         next_offset = e->next_offset - (origsize - *size);
1449         if (put_user(target_offset, &ce->target_offset) != 0 ||
1450             put_user(next_offset, &ce->next_offset) != 0)
1451                 return -EFAULT;
1452         return 0;
1453 }
1454
1455 static int
1456 compat_find_calc_match(struct xt_entry_match *m,
1457                        const char *name,
1458                        const struct ip6t_ip6 *ipv6,
1459                        unsigned int hookmask,
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,
1529                                              &e->ipv6, e->comefrom, &off);
1530                 if (ret != 0)
1531                         goto release_matches;
1532                 ++j;
1533         }
1534
1535         t = compat_ip6t_get_target(e);
1536         target = xt_request_find_target(NFPROTO_IPV6, t->u.user.name,
1537                                         t->u.user.revision);
1538         if (IS_ERR(target)) {
1539                 duprintf("check_compat_entry_size_and_hooks: `%s' not found\n",
1540                          t->u.user.name);
1541                 ret = PTR_ERR(target);
1542                 goto release_matches;
1543         }
1544         t->u.kernel.target = target;
1545
1546         off += xt_compat_target_offset(target);
1547         *size += off;
1548         ret = xt_compat_add_offset(AF_INET6, entry_offset, off);
1549         if (ret)
1550                 goto out;
1551
1552         /* Check hooks & underflows */
1553         for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1554                 if ((unsigned char *)e - base == hook_entries[h])
1555                         newinfo->hook_entry[h] = hook_entries[h];
1556                 if ((unsigned char *)e - base == underflows[h])
1557                         newinfo->underflow[h] = underflows[h];
1558         }
1559
1560         /* Clear counters and comefrom */
1561         memset(&e->counters, 0, sizeof(e->counters));
1562         e->comefrom = 0;
1563         return 0;
1564
1565 out:
1566         module_put(t->u.kernel.target->me);
1567 release_matches:
1568         xt_ematch_foreach(ematch, e) {
1569                 if (j-- == 0)
1570                         break;
1571                 module_put(ematch->u.kernel.match->me);
1572         }
1573         return ret;
1574 }
1575
1576 static int
1577 compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr,
1578                             unsigned int *size, const char *name,
1579                             struct xt_table_info *newinfo, unsigned char *base)
1580 {
1581         struct xt_entry_target *t;
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         xt_compat_target_from_user(t, dstptr, size);
1604
1605         de->next_offset = e->next_offset - (origsize - *size);
1606         for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1607                 if ((unsigned char *)de - base < newinfo->hook_entry[h])
1608                         newinfo->hook_entry[h] -= origsize - *size;
1609                 if ((unsigned char *)de - base < newinfo->underflow[h])
1610                         newinfo->underflow[h] -= origsize - *size;
1611         }
1612         return ret;
1613 }
1614
1615 static int compat_check_entry(struct ip6t_entry *e, struct net *net,
1616                               const char *name)
1617 {
1618         unsigned int j;
1619         int ret = 0;
1620         struct xt_mtchk_param mtpar;
1621         struct xt_entry_match *ematch;
1622
1623         j = 0;
1624         mtpar.net       = net;
1625         mtpar.table     = name;
1626         mtpar.entryinfo = &e->ipv6;
1627         mtpar.hook_mask = e->comefrom;
1628         mtpar.family    = NFPROTO_IPV6;
1629         xt_ematch_foreach(ematch, e) {
1630                 ret = check_match(ematch, &mtpar);
1631                 if (ret != 0)
1632                         goto cleanup_matches;
1633                 ++j;
1634         }
1635
1636         ret = check_target(e, net, name);
1637         if (ret)
1638                 goto cleanup_matches;
1639         return 0;
1640
1641  cleanup_matches:
1642         xt_ematch_foreach(ematch, e) {
1643                 if (j-- == 0)
1644                         break;
1645                 cleanup_match(ematch, net);
1646         }
1647         return ret;
1648 }
1649
1650 static int
1651 translate_compat_table(struct net *net,
1652                        const char *name,
1653                        unsigned int valid_hooks,
1654                        struct xt_table_info **pinfo,
1655                        void **pentry0,
1656                        unsigned int total_size,
1657                        unsigned int number,
1658                        unsigned int *hook_entries,
1659                        unsigned int *underflows)
1660 {
1661         unsigned int i, j;
1662         struct xt_table_info *newinfo, *info;
1663         void *pos, *entry0, *entry1;
1664         struct compat_ip6t_entry *iter0;
1665         struct ip6t_entry *iter1;
1666         unsigned int size;
1667         int ret = 0;
1668
1669         info = *pinfo;
1670         entry0 = *pentry0;
1671         size = total_size;
1672         info->number = number;
1673
1674         /* Init all hooks to impossible value. */
1675         for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1676                 info->hook_entry[i] = 0xFFFFFFFF;
1677                 info->underflow[i] = 0xFFFFFFFF;
1678         }
1679
1680         duprintf("translate_compat_table: size %u\n", info->size);
1681         j = 0;
1682         xt_compat_lock(AF_INET6);
1683         xt_compat_init_offsets(AF_INET6, number);
1684         /* Walk through entries, checking offsets. */
1685         xt_entry_foreach(iter0, entry0, total_size) {
1686                 ret = check_compat_entry_size_and_hooks(iter0, info, &size,
1687                                                         entry0,
1688                                                         entry0 + total_size,
1689                                                         hook_entries,
1690                                                         underflows,
1691                                                         name);
1692                 if (ret != 0)
1693                         goto out_unlock;
1694                 ++j;
1695         }
1696
1697         ret = -EINVAL;
1698         if (j != number) {
1699                 duprintf("translate_compat_table: %u not %u entries\n",
1700                          j, number);
1701                 goto out_unlock;
1702         }
1703
1704         /* Check hooks all assigned */
1705         for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1706                 /* Only hooks which are valid */
1707                 if (!(valid_hooks & (1 << i)))
1708                         continue;
1709                 if (info->hook_entry[i] == 0xFFFFFFFF) {
1710                         duprintf("Invalid hook entry %u %u\n",
1711                                  i, hook_entries[i]);
1712                         goto out_unlock;
1713                 }
1714                 if (info->underflow[i] == 0xFFFFFFFF) {
1715                         duprintf("Invalid underflow %u %u\n",
1716                                  i, underflows[i]);
1717                         goto out_unlock;
1718                 }
1719         }
1720
1721         ret = -ENOMEM;
1722         newinfo = xt_alloc_table_info(size);
1723         if (!newinfo)
1724                 goto out_unlock;
1725
1726         newinfo->number = number;
1727         for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1728                 newinfo->hook_entry[i] = info->hook_entry[i];
1729                 newinfo->underflow[i] = info->underflow[i];
1730         }
1731         entry1 = newinfo->entries[raw_smp_processor_id()];
1732         pos = entry1;
1733         size = total_size;
1734         xt_entry_foreach(iter0, entry0, total_size) {
1735                 ret = compat_copy_entry_from_user(iter0, &pos, &size,
1736                                                   name, newinfo, entry1);
1737                 if (ret != 0)
1738                         break;
1739         }
1740         xt_compat_flush_offsets(AF_INET6);
1741         xt_compat_unlock(AF_INET6);
1742         if (ret)
1743                 goto free_newinfo;
1744
1745         ret = -ELOOP;
1746         if (!mark_source_chains(newinfo, valid_hooks, entry1))
1747                 goto free_newinfo;
1748
1749         i = 0;
1750         xt_entry_foreach(iter1, entry1, newinfo->size) {
1751                 ret = compat_check_entry(iter1, net, name);
1752                 if (ret != 0)
1753                         break;
1754                 ++i;
1755                 if (strcmp(ip6t_get_target(iter1)->u.user.name,
1756                     XT_ERROR_TARGET) == 0)
1757                         ++newinfo->stacksize;
1758         }
1759         if (ret) {
1760                 /*
1761                  * The first i matches need cleanup_entry (calls ->destroy)
1762                  * because they had called ->check already. The other j-i
1763                  * entries need only release.
1764                  */
1765                 int skip = i;
1766                 j -= i;
1767                 xt_entry_foreach(iter0, entry0, newinfo->size) {
1768                         if (skip-- > 0)
1769                                 continue;
1770                         if (j-- == 0)
1771                                 break;
1772                         compat_release_entry(iter0);
1773                 }
1774                 xt_entry_foreach(iter1, entry1, newinfo->size) {
1775                         if (i-- == 0)
1776                                 break;
1777                         cleanup_entry(iter1, net);
1778                 }
1779                 xt_free_table_info(newinfo);
1780                 return ret;
1781         }
1782
1783         /* And one copy for every other CPU */
1784         for_each_possible_cpu(i)
1785                 if (newinfo->entries[i] && newinfo->entries[i] != entry1)
1786                         memcpy(newinfo->entries[i], entry1, newinfo->size);
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         tmp.name[sizeof(tmp.name)-1] = 0;
1826
1827         newinfo = xt_alloc_table_info(tmp.size);
1828         if (!newinfo)
1829                 return -ENOMEM;
1830
1831         /* choose the copy that is on our node/cpu */
1832         loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1833         if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1834                            tmp.size) != 0) {
1835                 ret = -EFAULT;
1836                 goto free_newinfo;
1837         }
1838
1839         ret = translate_compat_table(net, tmp.name, tmp.valid_hooks,
1840                                      &newinfo, &loc_cpu_entry, tmp.size,
1841                                      tmp.num_entries, tmp.hook_entry,
1842                                      tmp.underflow);
1843         if (ret != 0)
1844                 goto free_newinfo;
1845
1846         duprintf("compat_do_replace: Translated table\n");
1847
1848         ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1849                            tmp.num_counters, compat_ptr(tmp.counters));
1850         if (ret)
1851                 goto free_newinfo_untrans;
1852         return 0;
1853
1854  free_newinfo_untrans:
1855         xt_entry_foreach(iter, loc_cpu_entry, newinfo->size)
1856                 cleanup_entry(iter, net);
1857  free_newinfo:
1858         xt_free_table_info(newinfo);
1859         return ret;
1860 }
1861
1862 static int
1863 compat_do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user,
1864                        unsigned int len)
1865 {
1866         int ret;
1867
1868         if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
1869                 return -EPERM;
1870
1871         switch (cmd) {
1872         case IP6T_SO_SET_REPLACE:
1873                 ret = compat_do_replace(sock_net(sk), user, len);
1874                 break;
1875
1876         case IP6T_SO_SET_ADD_COUNTERS:
1877                 ret = do_add_counters(sock_net(sk), user, len, 1);
1878                 break;
1879
1880         default:
1881                 duprintf("do_ip6t_set_ctl:  unknown request %i\n", cmd);
1882                 ret = -EINVAL;
1883         }
1884
1885         return ret;
1886 }
1887
1888 struct compat_ip6t_get_entries {
1889         char name[XT_TABLE_MAXNAMELEN];
1890         compat_uint_t size;
1891         struct compat_ip6t_entry entrytable[0];
1892 };
1893
1894 static int
1895 compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table,
1896                             void __user *userptr)
1897 {
1898         struct xt_counters *counters;
1899         const struct xt_table_info *private = table->private;
1900         void __user *pos;
1901         unsigned int size;
1902         int ret = 0;
1903         const void *loc_cpu_entry;
1904         unsigned int i = 0;
1905         struct ip6t_entry *iter;
1906
1907         counters = alloc_counters(table);
1908         if (IS_ERR(counters))
1909                 return PTR_ERR(counters);
1910
1911         /* choose the copy that is on our node/cpu, ...
1912          * This choice is lazy (because current thread is
1913          * allowed to migrate to another cpu)
1914          */
1915         loc_cpu_entry = private->entries[raw_smp_processor_id()];
1916         pos = userptr;
1917         size = total_size;
1918         xt_entry_foreach(iter, loc_cpu_entry, total_size) {
1919                 ret = compat_copy_entry_to_user(iter, &pos,
1920                                                 &size, counters, i++);
1921                 if (ret != 0)
1922                         break;
1923         }
1924
1925         vfree(counters);
1926         return ret;
1927 }
1928
1929 static int
1930 compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr,
1931                    int *len)
1932 {
1933         int ret;
1934         struct compat_ip6t_get_entries get;
1935         struct xt_table *t;
1936
1937         if (*len < sizeof(get)) {
1938                 duprintf("compat_get_entries: %u < %zu\n", *len, sizeof(get));
1939                 return -EINVAL;
1940         }
1941
1942         if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1943                 return -EFAULT;
1944
1945         if (*len != sizeof(struct compat_ip6t_get_entries) + get.size) {
1946                 duprintf("compat_get_entries: %u != %zu\n",
1947                          *len, sizeof(get) + get.size);
1948                 return -EINVAL;
1949         }
1950
1951         xt_compat_lock(AF_INET6);
1952         t = xt_find_table_lock(net, AF_INET6, get.name);
1953         if (!IS_ERR_OR_NULL(t)) {
1954                 const struct xt_table_info *private = t->private;
1955                 struct xt_table_info info;
1956                 duprintf("t->private->number = %u\n", private->number);
1957                 ret = compat_table_info(private, &info);
1958                 if (!ret && get.size == info.size) {
1959                         ret = compat_copy_entries_to_user(private->size,
1960                                                           t, uptr->entrytable);
1961                 } else if (!ret) {
1962                         duprintf("compat_get_entries: I've got %u not %u!\n",
1963                                  private->size, get.size);
1964                         ret = -EAGAIN;
1965                 }
1966                 xt_compat_flush_offsets(AF_INET6);
1967                 module_put(t->me);
1968                 xt_table_unlock(t);
1969         } else
1970                 ret = t ? PTR_ERR(t) : -ENOENT;
1971
1972         xt_compat_unlock(AF_INET6);
1973         return ret;
1974 }
1975
1976 static int do_ip6t_get_ctl(struct sock *, int, void __user *, int *);
1977
1978 static int
1979 compat_do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1980 {
1981         int ret;
1982
1983         if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
1984                 return -EPERM;
1985
1986         switch (cmd) {
1987         case IP6T_SO_GET_INFO:
1988                 ret = get_info(sock_net(sk), user, len, 1);
1989                 break;
1990         case IP6T_SO_GET_ENTRIES:
1991                 ret = compat_get_entries(sock_net(sk), user, len);
1992                 break;
1993         default:
1994                 ret = do_ip6t_get_ctl(sk, cmd, user, len);
1995         }
1996         return ret;
1997 }
1998 #endif
1999
2000 static int
2001 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
2002 {
2003         int ret;
2004
2005         if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
2006                 return -EPERM;
2007
2008         switch (cmd) {
2009         case IP6T_SO_SET_REPLACE:
2010                 ret = do_replace(sock_net(sk), user, len);
2011                 break;
2012
2013         case IP6T_SO_SET_ADD_COUNTERS:
2014                 ret = do_add_counters(sock_net(sk), user, len, 0);
2015                 break;
2016
2017         default:
2018                 duprintf("do_ip6t_set_ctl:  unknown request %i\n", cmd);
2019                 ret = -EINVAL;
2020         }
2021
2022         return ret;
2023 }
2024
2025 static int
2026 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
2027 {
2028         int ret;
2029
2030         if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
2031                 return -EPERM;
2032
2033         switch (cmd) {
2034         case IP6T_SO_GET_INFO:
2035                 ret = get_info(sock_net(sk), user, len, 0);
2036                 break;
2037
2038         case IP6T_SO_GET_ENTRIES:
2039                 ret = get_entries(sock_net(sk), user, len);
2040                 break;
2041
2042         case IP6T_SO_GET_REVISION_MATCH:
2043         case IP6T_SO_GET_REVISION_TARGET: {
2044                 struct xt_get_revision rev;
2045                 int target;
2046
2047                 if (*len != sizeof(rev)) {
2048                         ret = -EINVAL;
2049                         break;
2050                 }
2051                 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
2052                         ret = -EFAULT;
2053                         break;
2054                 }
2055                 rev.name[sizeof(rev.name)-1] = 0;
2056
2057                 if (cmd == IP6T_SO_GET_REVISION_TARGET)
2058                         target = 1;
2059                 else
2060                         target = 0;
2061
2062                 try_then_request_module(xt_find_revision(AF_INET6, rev.name,
2063                                                          rev.revision,
2064                                                          target, &ret),
2065                                         "ip6t_%s", rev.name);
2066                 break;
2067         }
2068
2069         default:
2070                 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
2071                 ret = -EINVAL;
2072         }
2073
2074         return ret;
2075 }
2076
2077 struct xt_table *ip6t_register_table(struct net *net,
2078                                      const struct xt_table *table,
2079                                      const struct ip6t_replace *repl)
2080 {
2081         int ret;
2082         struct xt_table_info *newinfo;
2083         struct xt_table_info bootstrap = {0};
2084         void *loc_cpu_entry;
2085         struct xt_table *new_table;
2086
2087         newinfo = xt_alloc_table_info(repl->size);
2088         if (!newinfo) {
2089                 ret = -ENOMEM;
2090                 goto out;
2091         }
2092
2093         /* choose the copy on our node/cpu, but dont care about preemption */
2094         loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
2095         memcpy(loc_cpu_entry, repl->entries, repl->size);
2096
2097         ret = translate_table(net, newinfo, loc_cpu_entry, repl);
2098         if (ret != 0)
2099                 goto out_free;
2100
2101         new_table = xt_register_table(net, table, &bootstrap, newinfo);
2102         if (IS_ERR(new_table)) {
2103                 ret = PTR_ERR(new_table);
2104                 goto out_free;
2105         }
2106         return new_table;
2107
2108 out_free:
2109         xt_free_table_info(newinfo);
2110 out:
2111         return ERR_PTR(ret);
2112 }
2113
2114 void ip6t_unregister_table(struct net *net, struct xt_table *table)
2115 {
2116         struct xt_table_info *private;
2117         void *loc_cpu_entry;
2118         struct module *table_owner = table->me;
2119         struct ip6t_entry *iter;
2120
2121         private = xt_unregister_table(table);
2122
2123         /* Decrease module usage counts and free resources */
2124         loc_cpu_entry = private->entries[raw_smp_processor_id()];
2125         xt_entry_foreach(iter, loc_cpu_entry, private->size)
2126                 cleanup_entry(iter, net);
2127         if (private->number > private->initial_entries)
2128                 module_put(table_owner);
2129         xt_free_table_info(private);
2130 }
2131
2132 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
2133 static inline bool
2134 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
2135                      u_int8_t type, u_int8_t code,
2136                      bool invert)
2137 {
2138         return (type == test_type && code >= min_code && code <= max_code)
2139                 ^ invert;
2140 }
2141
2142 static bool
2143 icmp6_match(const struct sk_buff *skb, struct xt_action_param *par)
2144 {
2145         const struct icmp6hdr *ic;
2146         struct icmp6hdr _icmph;
2147         const struct ip6t_icmp *icmpinfo = par->matchinfo;
2148
2149         /* Must not be a fragment. */
2150         if (par->fragoff != 0)
2151                 return false;
2152
2153         ic = skb_header_pointer(skb, par->thoff, sizeof(_icmph), &_icmph);
2154         if (ic == NULL) {
2155                 /* We've been asked to examine this packet, and we
2156                  * can't.  Hence, no choice but to drop.
2157                  */
2158                 duprintf("Dropping evil ICMP tinygram.\n");
2159                 par->hotdrop = true;
2160                 return false;
2161         }
2162
2163         return icmp6_type_code_match(icmpinfo->type,
2164                                      icmpinfo->code[0],
2165                                      icmpinfo->code[1],
2166                                      ic->icmp6_type, ic->icmp6_code,
2167                                      !!(icmpinfo->invflags&IP6T_ICMP_INV));
2168 }
2169
2170 /* Called when user tries to insert an entry of this type. */
2171 static int icmp6_checkentry(const struct xt_mtchk_param *par)
2172 {
2173         const struct ip6t_icmp *icmpinfo = par->matchinfo;
2174
2175         /* Must specify no unknown invflags */
2176         return (icmpinfo->invflags & ~IP6T_ICMP_INV) ? -EINVAL : 0;
2177 }
2178
2179 /* The built-in targets: standard (NULL) and error. */
2180 static struct xt_target ip6t_builtin_tg[] __read_mostly = {
2181         {
2182                 .name             = XT_STANDARD_TARGET,
2183                 .targetsize       = sizeof(int),
2184                 .family           = NFPROTO_IPV6,
2185 #ifdef CONFIG_COMPAT
2186                 .compatsize       = sizeof(compat_int_t),
2187                 .compat_from_user = compat_standard_from_user,
2188                 .compat_to_user   = compat_standard_to_user,
2189 #endif
2190         },
2191         {
2192                 .name             = XT_ERROR_TARGET,
2193                 .target           = ip6t_error,
2194                 .targetsize       = XT_FUNCTION_MAXNAMELEN,
2195                 .family           = NFPROTO_IPV6,
2196         },
2197 };
2198
2199 static struct nf_sockopt_ops ip6t_sockopts = {
2200         .pf             = PF_INET6,
2201         .set_optmin     = IP6T_BASE_CTL,
2202         .set_optmax     = IP6T_SO_SET_MAX+1,
2203         .set            = do_ip6t_set_ctl,
2204 #ifdef CONFIG_COMPAT
2205         .compat_set     = compat_do_ip6t_set_ctl,
2206 #endif
2207         .get_optmin     = IP6T_BASE_CTL,
2208         .get_optmax     = IP6T_SO_GET_MAX+1,
2209         .get            = do_ip6t_get_ctl,
2210 #ifdef CONFIG_COMPAT
2211         .compat_get     = compat_do_ip6t_get_ctl,
2212 #endif
2213         .owner          = THIS_MODULE,
2214 };
2215
2216 static struct xt_match ip6t_builtin_mt[] __read_mostly = {
2217         {
2218                 .name       = "icmp6",
2219                 .match      = icmp6_match,
2220                 .matchsize  = sizeof(struct ip6t_icmp),
2221                 .checkentry = icmp6_checkentry,
2222                 .proto      = IPPROTO_ICMPV6,
2223                 .family     = NFPROTO_IPV6,
2224         },
2225 };
2226
2227 static int __net_init ip6_tables_net_init(struct net *net)
2228 {
2229         return xt_proto_init(net, NFPROTO_IPV6);
2230 }
2231
2232 static void __net_exit ip6_tables_net_exit(struct net *net)
2233 {
2234         xt_proto_fini(net, NFPROTO_IPV6);
2235 }
2236
2237 static struct pernet_operations ip6_tables_net_ops = {
2238         .init = ip6_tables_net_init,
2239         .exit = ip6_tables_net_exit,
2240 };
2241
2242 static int __init ip6_tables_init(void)
2243 {
2244         int ret;
2245
2246         ret = register_pernet_subsys(&ip6_tables_net_ops);
2247         if (ret < 0)
2248                 goto err1;
2249
2250         /* No one else will be downing sem now, so we won't sleep */
2251         ret = xt_register_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
2252         if (ret < 0)
2253                 goto err2;
2254         ret = xt_register_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
2255         if (ret < 0)
2256                 goto err4;
2257
2258         /* Register setsockopt */
2259         ret = nf_register_sockopt(&ip6t_sockopts);
2260         if (ret < 0)
2261                 goto err5;
2262
2263         pr_info("(C) 2000-2006 Netfilter Core Team\n");
2264         return 0;
2265
2266 err5:
2267         xt_unregister_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
2268 err4:
2269         xt_unregister_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
2270 err2:
2271         unregister_pernet_subsys(&ip6_tables_net_ops);
2272 err1:
2273         return ret;
2274 }
2275
2276 static void __exit ip6_tables_fini(void)
2277 {
2278         nf_unregister_sockopt(&ip6t_sockopts);
2279
2280         xt_unregister_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
2281         xt_unregister_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
2282         unregister_pernet_subsys(&ip6_tables_net_ops);
2283 }
2284
2285 EXPORT_SYMBOL(ip6t_register_table);
2286 EXPORT_SYMBOL(ip6t_unregister_table);
2287 EXPORT_SYMBOL(ip6t_do_table);
2288
2289 module_init(ip6_tables_init);
2290 module_exit(ip6_tables_fini);