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