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

TOMOYO Linux Cross Reference
Linux/net/ipv4/netfilter/ip_tables.c

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

~ [ 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