~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/ipv6/netfilter/ip6_tables.c

Version: ~ [ linux-5.13-rc5 ] ~ [ linux-5.12.9 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.42 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.124 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.193 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.235 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.271 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.271 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp