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