[NETFILTER]: ip_tables: account for struct ipt_entry/struct compat_ipt_entry size...
[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 struct compat_delta {
1018         struct compat_delta *next;
1019         unsigned int offset;
1020         short delta;
1021 };
1022
1023 static struct compat_delta *compat_offsets;
1024
1025 static int compat_add_offset(unsigned int offset, short delta)
1026 {
1027         struct compat_delta *tmp;
1028
1029         tmp = kmalloc(sizeof(struct compat_delta), GFP_KERNEL);
1030         if (!tmp)
1031                 return -ENOMEM;
1032         tmp->offset = offset;
1033         tmp->delta = delta;
1034         if (compat_offsets) {
1035                 tmp->next = compat_offsets->next;
1036                 compat_offsets->next = tmp;
1037         } else {
1038                 compat_offsets = tmp;
1039                 tmp->next = NULL;
1040         }
1041         return 0;
1042 }
1043
1044 static void compat_flush_offsets(void)
1045 {
1046         struct compat_delta *tmp, *next;
1047
1048         if (compat_offsets) {
1049                 for (tmp = compat_offsets; tmp; tmp = next) {
1050                         next = tmp->next;
1051                         kfree(tmp);
1052                 }
1053                 compat_offsets = NULL;
1054         }
1055 }
1056
1057 static short compat_calc_jump(unsigned int offset)
1058 {
1059         struct compat_delta *tmp;
1060         short delta;
1061
1062         for (tmp = compat_offsets, delta = 0; tmp; tmp = tmp->next)
1063                 if (tmp->offset < offset)
1064                         delta += tmp->delta;
1065         return delta;
1066 }
1067
1068 static void compat_standard_from_user(void *dst, void *src)
1069 {
1070         int v = *(compat_int_t *)src;
1071
1072         if (v > 0)
1073                 v += compat_calc_jump(v);
1074         memcpy(dst, &v, sizeof(v));
1075 }
1076
1077 static int compat_standard_to_user(void __user *dst, void *src)
1078 {
1079         compat_int_t cv = *(int *)src;
1080
1081         if (cv > 0)
1082                 cv -= compat_calc_jump(cv);
1083         return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
1084 }
1085
1086 static inline int
1087 compat_calc_match(struct ipt_entry_match *m, int *size)
1088 {
1089         *size += xt_compat_match_offset(m->u.kernel.match);
1090         return 0;
1091 }
1092
1093 static int compat_calc_entry(struct ipt_entry *e,
1094                              const struct xt_table_info *info,
1095                              void *base, struct xt_table_info *newinfo)
1096 {
1097         struct ipt_entry_target *t;
1098         unsigned int entry_offset;
1099         int off, i, ret;
1100
1101         off = sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry);
1102         entry_offset = (void *)e - base;
1103         IPT_MATCH_ITERATE(e, compat_calc_match, &off);
1104         t = ipt_get_target(e);
1105         off += xt_compat_target_offset(t->u.kernel.target);
1106         newinfo->size -= off;
1107         ret = compat_add_offset(entry_offset, off);
1108         if (ret)
1109                 return ret;
1110
1111         for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1112                 if (info->hook_entry[i] &&
1113                     (e < (struct ipt_entry *)(base + info->hook_entry[i])))
1114                         newinfo->hook_entry[i] -= off;
1115                 if (info->underflow[i] &&
1116                     (e < (struct ipt_entry *)(base + info->underflow[i])))
1117                         newinfo->underflow[i] -= off;
1118         }
1119         return 0;
1120 }
1121
1122 static int compat_table_info(const struct xt_table_info *info,
1123                              struct xt_table_info *newinfo)
1124 {
1125         void *loc_cpu_entry;
1126
1127         if (!newinfo || !info)
1128                 return -EINVAL;
1129
1130         /* we dont care about newinfo->entries[] */
1131         memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
1132         newinfo->initial_entries = 0;
1133         loc_cpu_entry = info->entries[raw_smp_processor_id()];
1134         return IPT_ENTRY_ITERATE(loc_cpu_entry, info->size,
1135                                  compat_calc_entry, info, loc_cpu_entry,
1136                                  newinfo);
1137 }
1138 #endif
1139
1140 static int get_info(void __user *user, int *len, int compat)
1141 {
1142         char name[IPT_TABLE_MAXNAMELEN];
1143         struct xt_table *t;
1144         int ret;
1145
1146         if (*len != sizeof(struct ipt_getinfo)) {
1147                 duprintf("length %u != %u\n", *len,
1148                         (unsigned int)sizeof(struct ipt_getinfo));
1149                 return -EINVAL;
1150         }
1151
1152         if (copy_from_user(name, user, sizeof(name)) != 0)
1153                 return -EFAULT;
1154
1155         name[IPT_TABLE_MAXNAMELEN-1] = '\0';
1156 #ifdef CONFIG_COMPAT
1157         if (compat)
1158                 xt_compat_lock(AF_INET);
1159 #endif
1160         t = try_then_request_module(xt_find_table_lock(AF_INET, name),
1161                                     "iptable_%s", name);
1162         if (t && !IS_ERR(t)) {
1163                 struct ipt_getinfo info;
1164                 struct xt_table_info *private = t->private;
1165
1166 #ifdef CONFIG_COMPAT
1167                 if (compat) {
1168                         struct xt_table_info tmp;
1169                         ret = compat_table_info(private, &tmp);
1170                         compat_flush_offsets();
1171                         private = &tmp;
1172                 }
1173 #endif
1174                 info.valid_hooks = t->valid_hooks;
1175                 memcpy(info.hook_entry, private->hook_entry,
1176                        sizeof(info.hook_entry));
1177                 memcpy(info.underflow, private->underflow,
1178                        sizeof(info.underflow));
1179                 info.num_entries = private->number;
1180                 info.size = private->size;
1181                 strcpy(info.name, name);
1182
1183                 if (copy_to_user(user, &info, *len) != 0)
1184                         ret = -EFAULT;
1185                 else
1186                         ret = 0;
1187
1188                 xt_table_unlock(t);
1189                 module_put(t->me);
1190         } else
1191                 ret = t ? PTR_ERR(t) : -ENOENT;
1192 #ifdef CONFIG_COMPAT
1193         if (compat)
1194                 xt_compat_unlock(AF_INET);
1195 #endif
1196         return ret;
1197 }
1198
1199 static int
1200 get_entries(struct ipt_get_entries __user *uptr, int *len)
1201 {
1202         int ret;
1203         struct ipt_get_entries get;
1204         struct xt_table *t;
1205
1206         if (*len < sizeof(get)) {
1207                 duprintf("get_entries: %u < %d\n", *len,
1208                                 (unsigned int)sizeof(get));
1209                 return -EINVAL;
1210         }
1211         if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1212                 return -EFAULT;
1213         if (*len != sizeof(struct ipt_get_entries) + get.size) {
1214                 duprintf("get_entries: %u != %u\n", *len,
1215                                 (unsigned int)(sizeof(struct ipt_get_entries) +
1216                                 get.size));
1217                 return -EINVAL;
1218         }
1219
1220         t = xt_find_table_lock(AF_INET, get.name);
1221         if (t && !IS_ERR(t)) {
1222                 struct xt_table_info *private = t->private;
1223                 duprintf("t->private->number = %u\n",
1224                          private->number);
1225                 if (get.size == private->size)
1226                         ret = copy_entries_to_user(private->size,
1227                                                    t, uptr->entrytable);
1228                 else {
1229                         duprintf("get_entries: I've got %u not %u!\n",
1230                                  private->size,
1231                                  get.size);
1232                         ret = -EINVAL;
1233                 }
1234                 module_put(t->me);
1235                 xt_table_unlock(t);
1236         } else
1237                 ret = t ? PTR_ERR(t) : -ENOENT;
1238
1239         return ret;
1240 }
1241
1242 static int
1243 __do_replace(const char *name, unsigned int valid_hooks,
1244              struct xt_table_info *newinfo, unsigned int num_counters,
1245              void __user *counters_ptr)
1246 {
1247         int ret;
1248         struct xt_table *t;
1249         struct xt_table_info *oldinfo;
1250         struct xt_counters *counters;
1251         void *loc_cpu_old_entry;
1252
1253         ret = 0;
1254         counters = vmalloc(num_counters * sizeof(struct xt_counters));
1255         if (!counters) {
1256                 ret = -ENOMEM;
1257                 goto out;
1258         }
1259
1260         t = try_then_request_module(xt_find_table_lock(AF_INET, name),
1261                                     "iptable_%s", name);
1262         if (!t || IS_ERR(t)) {
1263                 ret = t ? PTR_ERR(t) : -ENOENT;
1264                 goto free_newinfo_counters_untrans;
1265         }
1266
1267         /* You lied! */
1268         if (valid_hooks != t->valid_hooks) {
1269                 duprintf("Valid hook crap: %08X vs %08X\n",
1270                          valid_hooks, t->valid_hooks);
1271                 ret = -EINVAL;
1272                 goto put_module;
1273         }
1274
1275         oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);
1276         if (!oldinfo)
1277                 goto put_module;
1278
1279         /* Update module usage count based on number of rules */
1280         duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1281                 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1282         if ((oldinfo->number > oldinfo->initial_entries) ||
1283             (newinfo->number <= oldinfo->initial_entries))
1284                 module_put(t->me);
1285         if ((oldinfo->number > oldinfo->initial_entries) &&
1286             (newinfo->number <= oldinfo->initial_entries))
1287                 module_put(t->me);
1288
1289         /* Get the old counters. */
1290         get_counters(oldinfo, counters);
1291         /* Decrease module usage counts and free resource */
1292         loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1293         IPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,
1294                           NULL);
1295         xt_free_table_info(oldinfo);
1296         if (copy_to_user(counters_ptr, counters,
1297                          sizeof(struct xt_counters) * num_counters) != 0)
1298                 ret = -EFAULT;
1299         vfree(counters);
1300         xt_table_unlock(t);
1301         return ret;
1302
1303  put_module:
1304         module_put(t->me);
1305         xt_table_unlock(t);
1306  free_newinfo_counters_untrans:
1307         vfree(counters);
1308  out:
1309         return ret;
1310 }
1311
1312 static int
1313 do_replace(void __user *user, unsigned int len)
1314 {
1315         int ret;
1316         struct ipt_replace tmp;
1317         struct xt_table_info *newinfo;
1318         void *loc_cpu_entry;
1319
1320         if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1321                 return -EFAULT;
1322
1323         /* Hack: Causes ipchains to give correct error msg --RR */
1324         if (len != sizeof(tmp) + tmp.size)
1325                 return -ENOPROTOOPT;
1326
1327         /* overflow check */
1328         if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1329                 return -ENOMEM;
1330
1331         newinfo = xt_alloc_table_info(tmp.size);
1332         if (!newinfo)
1333                 return -ENOMEM;
1334
1335         /* choose the copy that is our node/cpu */
1336         loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1337         if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1338                            tmp.size) != 0) {
1339                 ret = -EFAULT;
1340                 goto free_newinfo;
1341         }
1342
1343         ret = translate_table(tmp.name, tmp.valid_hooks,
1344                               newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
1345                               tmp.hook_entry, tmp.underflow);
1346         if (ret != 0)
1347                 goto free_newinfo;
1348
1349         duprintf("ip_tables: Translated table\n");
1350
1351         ret = __do_replace(tmp.name, tmp.valid_hooks, newinfo,
1352                            tmp.num_counters, tmp.counters);
1353         if (ret)
1354                 goto free_newinfo_untrans;
1355         return 0;
1356
1357  free_newinfo_untrans:
1358         IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1359  free_newinfo:
1360         xt_free_table_info(newinfo);
1361         return ret;
1362 }
1363
1364 /* We're lazy, and add to the first CPU; overflow works its fey magic
1365  * and everything is OK. */
1366 static inline int
1367 add_counter_to_entry(struct ipt_entry *e,
1368                      const struct xt_counters addme[],
1369                      unsigned int *i)
1370 {
1371 #if 0
1372         duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1373                  *i,
1374                  (long unsigned int)e->counters.pcnt,
1375                  (long unsigned int)e->counters.bcnt,
1376                  (long unsigned int)addme[*i].pcnt,
1377                  (long unsigned int)addme[*i].bcnt);
1378 #endif
1379
1380         ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1381
1382         (*i)++;
1383         return 0;
1384 }
1385
1386 static int
1387 do_add_counters(void __user *user, unsigned int len, int compat)
1388 {
1389         unsigned int i;
1390         struct xt_counters_info tmp;
1391         struct xt_counters *paddc;
1392         unsigned int num_counters;
1393         char *name;
1394         int size;
1395         void *ptmp;
1396         struct xt_table *t;
1397         struct xt_table_info *private;
1398         int ret = 0;
1399         void *loc_cpu_entry;
1400 #ifdef CONFIG_COMPAT
1401         struct compat_xt_counters_info compat_tmp;
1402
1403         if (compat) {
1404                 ptmp = &compat_tmp;
1405                 size = sizeof(struct compat_xt_counters_info);
1406         } else
1407 #endif
1408         {
1409                 ptmp = &tmp;
1410                 size = sizeof(struct xt_counters_info);
1411         }
1412
1413         if (copy_from_user(ptmp, user, size) != 0)
1414                 return -EFAULT;
1415
1416 #ifdef CONFIG_COMPAT
1417         if (compat) {
1418                 num_counters = compat_tmp.num_counters;
1419                 name = compat_tmp.name;
1420         } else
1421 #endif
1422         {
1423                 num_counters = tmp.num_counters;
1424                 name = tmp.name;
1425         }
1426
1427         if (len != size + num_counters * sizeof(struct xt_counters))
1428                 return -EINVAL;
1429
1430         paddc = vmalloc_node(len - size, numa_node_id());
1431         if (!paddc)
1432                 return -ENOMEM;
1433
1434         if (copy_from_user(paddc, user + size, len - size) != 0) {
1435                 ret = -EFAULT;
1436                 goto free;
1437         }
1438
1439         t = xt_find_table_lock(AF_INET, name);
1440         if (!t || IS_ERR(t)) {
1441                 ret = t ? PTR_ERR(t) : -ENOENT;
1442                 goto free;
1443         }
1444
1445         write_lock_bh(&t->lock);
1446         private = t->private;
1447         if (private->number != num_counters) {
1448                 ret = -EINVAL;
1449                 goto unlock_up_free;
1450         }
1451
1452         i = 0;
1453         /* Choose the copy that is on our node */
1454         loc_cpu_entry = private->entries[raw_smp_processor_id()];
1455         IPT_ENTRY_ITERATE(loc_cpu_entry,
1456                           private->size,
1457                           add_counter_to_entry,
1458                           paddc,
1459                           &i);
1460  unlock_up_free:
1461         write_unlock_bh(&t->lock);
1462         xt_table_unlock(t);
1463         module_put(t->me);
1464  free:
1465         vfree(paddc);
1466
1467         return ret;
1468 }
1469
1470 #ifdef CONFIG_COMPAT
1471 struct compat_ipt_replace {
1472         char                    name[IPT_TABLE_MAXNAMELEN];
1473         u32                     valid_hooks;
1474         u32                     num_entries;
1475         u32                     size;
1476         u32                     hook_entry[NF_INET_NUMHOOKS];
1477         u32                     underflow[NF_INET_NUMHOOKS];
1478         u32                     num_counters;
1479         compat_uptr_t           counters;       /* struct ipt_counters * */
1480         struct compat_ipt_entry entries[0];
1481 };
1482
1483 static int
1484 compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr,
1485                           compat_uint_t *size, struct xt_counters *counters,
1486                           unsigned int *i)
1487 {
1488         struct ipt_entry_target *t;
1489         struct compat_ipt_entry __user *ce;
1490         u_int16_t target_offset, next_offset;
1491         compat_uint_t origsize;
1492         int ret;
1493
1494         ret = -EFAULT;
1495         origsize = *size;
1496         ce = (struct compat_ipt_entry __user *)*dstptr;
1497         if (copy_to_user(ce, e, sizeof(struct ipt_entry)))
1498                 goto out;
1499
1500         if (copy_to_user(&ce->counters, &counters[*i], sizeof(counters[*i])))
1501                 goto out;
1502
1503         *dstptr += sizeof(struct compat_ipt_entry);
1504         *size -= sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry);
1505
1506         ret = IPT_MATCH_ITERATE(e, xt_compat_match_to_user, dstptr, size);
1507         target_offset = e->target_offset - (origsize - *size);
1508         if (ret)
1509                 goto out;
1510         t = ipt_get_target(e);
1511         ret = xt_compat_target_to_user(t, dstptr, size);
1512         if (ret)
1513                 goto out;
1514         ret = -EFAULT;
1515         next_offset = e->next_offset - (origsize - *size);
1516         if (put_user(target_offset, &ce->target_offset))
1517                 goto out;
1518         if (put_user(next_offset, &ce->next_offset))
1519                 goto out;
1520
1521         (*i)++;
1522         return 0;
1523 out:
1524         return ret;
1525 }
1526
1527 static inline int
1528 compat_find_calc_match(struct ipt_entry_match *m,
1529                        const char *name,
1530                        const struct ipt_ip *ip,
1531                        unsigned int hookmask,
1532                        int *size, int *i)
1533 {
1534         struct xt_match *match;
1535
1536         match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
1537                                                       m->u.user.revision),
1538                                         "ipt_%s", m->u.user.name);
1539         if (IS_ERR(match) || !match) {
1540                 duprintf("compat_check_calc_match: `%s' not found\n",
1541                          m->u.user.name);
1542                 return match ? PTR_ERR(match) : -ENOENT;
1543         }
1544         m->u.kernel.match = match;
1545         *size += xt_compat_match_offset(match);
1546
1547         (*i)++;
1548         return 0;
1549 }
1550
1551 static inline int
1552 compat_release_match(struct ipt_entry_match *m, unsigned int *i)
1553 {
1554         if (i && (*i)-- == 0)
1555                 return 1;
1556
1557         module_put(m->u.kernel.match->me);
1558         return 0;
1559 }
1560
1561 static inline int
1562 compat_release_entry(struct ipt_entry *e, unsigned int *i)
1563 {
1564         struct ipt_entry_target *t;
1565
1566         if (i && (*i)-- == 0)
1567                 return 1;
1568
1569         /* Cleanup all matches */
1570         IPT_MATCH_ITERATE(e, compat_release_match, NULL);
1571         t = ipt_get_target(e);
1572         module_put(t->u.kernel.target->me);
1573         return 0;
1574 }
1575
1576 static inline int
1577 check_compat_entry_size_and_hooks(struct ipt_entry *e,
1578                                   struct xt_table_info *newinfo,
1579                                   unsigned int *size,
1580                                   unsigned char *base,
1581                                   unsigned char *limit,
1582                                   unsigned int *hook_entries,
1583                                   unsigned int *underflows,
1584                                   unsigned int *i,
1585                                   const char *name)
1586 {
1587         struct ipt_entry_target *t;
1588         struct xt_target *target;
1589         unsigned int entry_offset;
1590         int ret, off, h, j;
1591
1592         duprintf("check_compat_entry_size_and_hooks %p\n", e);
1593         if ((unsigned long)e % __alignof__(struct compat_ipt_entry) != 0
1594             || (unsigned char *)e + sizeof(struct compat_ipt_entry) >= limit) {
1595                 duprintf("Bad offset %p, limit = %p\n", e, limit);
1596                 return -EINVAL;
1597         }
1598
1599         if (e->next_offset < sizeof(struct compat_ipt_entry) +
1600                              sizeof(struct compat_xt_entry_target)) {
1601                 duprintf("checking: element %p size %u\n",
1602                          e, e->next_offset);
1603                 return -EINVAL;
1604         }
1605
1606         ret = check_entry(e, name);
1607         if (ret)
1608                 return ret;
1609
1610         off = sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry);
1611         entry_offset = (void *)e - (void *)base;
1612         j = 0;
1613         ret = IPT_MATCH_ITERATE(e, compat_find_calc_match, name, &e->ip,
1614                                 e->comefrom, &off, &j);
1615         if (ret != 0)
1616                 goto release_matches;
1617
1618         t = ipt_get_target(e);
1619         target = try_then_request_module(xt_find_target(AF_INET,
1620                                                         t->u.user.name,
1621                                                         t->u.user.revision),
1622                                          "ipt_%s", t->u.user.name);
1623         if (IS_ERR(target) || !target) {
1624                 duprintf("check_compat_entry_size_and_hooks: `%s' not found\n",
1625                          t->u.user.name);
1626                 ret = target ? PTR_ERR(target) : -ENOENT;
1627                 goto release_matches;
1628         }
1629         t->u.kernel.target = target;
1630
1631         off += xt_compat_target_offset(target);
1632         *size += off;
1633         ret = compat_add_offset(entry_offset, off);
1634         if (ret)
1635                 goto out;
1636
1637         /* Check hooks & underflows */
1638         for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1639                 if ((unsigned char *)e - base == hook_entries[h])
1640                         newinfo->hook_entry[h] = hook_entries[h];
1641                 if ((unsigned char *)e - base == underflows[h])
1642                         newinfo->underflow[h] = underflows[h];
1643         }
1644
1645         /* Clear counters and comefrom */
1646         e->counters = ((struct ipt_counters) { 0, 0 });
1647         e->comefrom = 0;
1648
1649         (*i)++;
1650         return 0;
1651
1652 out:
1653         module_put(t->u.kernel.target->me);
1654 release_matches:
1655         IPT_MATCH_ITERATE(e, compat_release_match, &j);
1656         return ret;
1657 }
1658
1659 static int
1660 compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
1661                             unsigned int *size, const char *name,
1662                             struct xt_table_info *newinfo, unsigned char *base)
1663 {
1664         struct ipt_entry_target *t;
1665         struct xt_target *target;
1666         struct ipt_entry *de;
1667         unsigned int origsize;
1668         int ret, h;
1669
1670         ret = 0;
1671         origsize = *size;
1672         de = (struct ipt_entry *)*dstptr;
1673         memcpy(de, e, sizeof(struct ipt_entry));
1674
1675         *dstptr += sizeof(struct compat_ipt_entry);
1676         *size += sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry);
1677
1678         ret = IPT_MATCH_ITERATE(e, xt_compat_match_from_user, dstptr, size);
1679         if (ret)
1680                 return ret;
1681         de->target_offset = e->target_offset - (origsize - *size);
1682         t = ipt_get_target(e);
1683         target = t->u.kernel.target;
1684         xt_compat_target_from_user(t, dstptr, size);
1685
1686         de->next_offset = e->next_offset - (origsize - *size);
1687         for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1688                 if ((unsigned char *)de - base < newinfo->hook_entry[h])
1689                         newinfo->hook_entry[h] -= origsize - *size;
1690                 if ((unsigned char *)de - base < newinfo->underflow[h])
1691                         newinfo->underflow[h] -= origsize - *size;
1692         }
1693         return ret;
1694 }
1695
1696 static inline int compat_check_entry(struct ipt_entry *e, const char *name,
1697                                      unsigned int *i)
1698 {
1699         int j, ret;
1700
1701         j = 0;
1702         ret = IPT_MATCH_ITERATE(e, check_match, name, &e->ip, e->comefrom, &j);
1703         if (ret)
1704                 goto cleanup_matches;
1705
1706         ret = check_target(e, name);
1707         if (ret)
1708                 goto cleanup_matches;
1709
1710         (*i)++;
1711         return 0;
1712
1713  cleanup_matches:
1714         IPT_MATCH_ITERATE(e, cleanup_match, &j);
1715         return ret;
1716 }
1717
1718 static int
1719 translate_compat_table(const char *name,
1720                        unsigned int valid_hooks,
1721                        struct xt_table_info **pinfo,
1722                        void **pentry0,
1723                        unsigned int total_size,
1724                        unsigned int number,
1725                        unsigned int *hook_entries,
1726                        unsigned int *underflows)
1727 {
1728         unsigned int i, j;
1729         struct xt_table_info *newinfo, *info;
1730         void *pos, *entry0, *entry1;
1731         unsigned int size;
1732         int ret;
1733
1734         info = *pinfo;
1735         entry0 = *pentry0;
1736         size = total_size;
1737         info->number = number;
1738
1739         /* Init all hooks to impossible value. */
1740         for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1741                 info->hook_entry[i] = 0xFFFFFFFF;
1742                 info->underflow[i] = 0xFFFFFFFF;
1743         }
1744
1745         duprintf("translate_compat_table: size %u\n", info->size);
1746         j = 0;
1747         xt_compat_lock(AF_INET);
1748         /* Walk through entries, checking offsets. */
1749         ret = IPT_ENTRY_ITERATE(entry0, total_size,
1750                                 check_compat_entry_size_and_hooks,
1751                                 info, &size, entry0,
1752                                 entry0 + total_size,
1753                                 hook_entries, underflows, &j, name);
1754         if (ret != 0)
1755                 goto out_unlock;
1756
1757         ret = -EINVAL;
1758         if (j != number) {
1759                 duprintf("translate_compat_table: %u not %u entries\n",
1760                          j, number);
1761                 goto out_unlock;
1762         }
1763
1764         /* Check hooks all assigned */
1765         for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1766                 /* Only hooks which are valid */
1767                 if (!(valid_hooks & (1 << i)))
1768                         continue;
1769                 if (info->hook_entry[i] == 0xFFFFFFFF) {
1770                         duprintf("Invalid hook entry %u %u\n",
1771                                  i, hook_entries[i]);
1772                         goto out_unlock;
1773                 }
1774                 if (info->underflow[i] == 0xFFFFFFFF) {
1775                         duprintf("Invalid underflow %u %u\n",
1776                                  i, underflows[i]);
1777                         goto out_unlock;
1778                 }
1779         }
1780
1781         ret = -ENOMEM;
1782         newinfo = xt_alloc_table_info(size);
1783         if (!newinfo)
1784                 goto out_unlock;
1785
1786         newinfo->number = number;
1787         for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1788                 newinfo->hook_entry[i] = info->hook_entry[i];
1789                 newinfo->underflow[i] = info->underflow[i];
1790         }
1791         entry1 = newinfo->entries[raw_smp_processor_id()];
1792         pos = entry1;
1793         size = total_size;
1794         ret = IPT_ENTRY_ITERATE(entry0, total_size,
1795                                 compat_copy_entry_from_user, &pos, &size,
1796                                 name, newinfo, entry1);
1797         compat_flush_offsets();
1798         xt_compat_unlock(AF_INET);
1799         if (ret)
1800                 goto free_newinfo;
1801
1802         ret = -ELOOP;
1803         if (!mark_source_chains(newinfo, valid_hooks, entry1))
1804                 goto free_newinfo;
1805
1806         i = 0;
1807         ret = IPT_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry,
1808                                 name, &i);
1809         if (ret) {
1810                 j -= i;
1811                 IPT_ENTRY_ITERATE_CONTINUE(entry1, newinfo->size, i,
1812                                            compat_release_entry, &j);
1813                 IPT_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, &i);
1814                 xt_free_table_info(newinfo);
1815                 return ret;
1816         }
1817
1818         /* And one copy for every other CPU */
1819         for_each_possible_cpu(i)
1820                 if (newinfo->entries[i] && newinfo->entries[i] != entry1)
1821                         memcpy(newinfo->entries[i], entry1, newinfo->size);
1822
1823         *pinfo = newinfo;
1824         *pentry0 = entry1;
1825         xt_free_table_info(info);
1826         return 0;
1827
1828 free_newinfo:
1829         xt_free_table_info(newinfo);
1830 out:
1831         IPT_ENTRY_ITERATE(entry0, total_size, compat_release_entry, &j);
1832         return ret;
1833 out_unlock:
1834         compat_flush_offsets();
1835         xt_compat_unlock(AF_INET);
1836         goto out;
1837 }
1838
1839 static int
1840 compat_do_replace(void __user *user, unsigned int len)
1841 {
1842         int ret;
1843         struct compat_ipt_replace tmp;
1844         struct xt_table_info *newinfo;
1845         void *loc_cpu_entry;
1846
1847         if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1848                 return -EFAULT;
1849
1850         /* Hack: Causes ipchains to give correct error msg --RR */
1851         if (len != sizeof(tmp) + tmp.size)
1852                 return -ENOPROTOOPT;
1853
1854         /* overflow check */
1855         if (tmp.size >= INT_MAX / num_possible_cpus())
1856                 return -ENOMEM;
1857         if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1858                 return -ENOMEM;
1859
1860         newinfo = xt_alloc_table_info(tmp.size);
1861         if (!newinfo)
1862                 return -ENOMEM;
1863
1864         /* choose the copy that is our node/cpu */
1865         loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1866         if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1867                            tmp.size) != 0) {
1868                 ret = -EFAULT;
1869                 goto free_newinfo;
1870         }
1871
1872         ret = translate_compat_table(tmp.name, tmp.valid_hooks,
1873                                      &newinfo, &loc_cpu_entry, tmp.size,
1874                                      tmp.num_entries, tmp.hook_entry,
1875                                      tmp.underflow);
1876         if (ret != 0)
1877                 goto free_newinfo;
1878
1879         duprintf("compat_do_replace: Translated table\n");
1880
1881         ret = __do_replace(tmp.name, tmp.valid_hooks, newinfo,
1882                            tmp.num_counters, compat_ptr(tmp.counters));
1883         if (ret)
1884                 goto free_newinfo_untrans;
1885         return 0;
1886
1887  free_newinfo_untrans:
1888         IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL);
1889  free_newinfo:
1890         xt_free_table_info(newinfo);
1891         return ret;
1892 }
1893
1894 static int
1895 compat_do_ipt_set_ctl(struct sock *sk,  int cmd, void __user *user,
1896                       unsigned int len)
1897 {
1898         int ret;
1899
1900         if (!capable(CAP_NET_ADMIN))
1901                 return -EPERM;
1902
1903         switch (cmd) {
1904         case IPT_SO_SET_REPLACE:
1905                 ret = compat_do_replace(user, len);
1906                 break;
1907
1908         case IPT_SO_SET_ADD_COUNTERS:
1909                 ret = do_add_counters(user, len, 1);
1910                 break;
1911
1912         default:
1913                 duprintf("do_ipt_set_ctl:  unknown request %i\n", cmd);
1914                 ret = -EINVAL;
1915         }
1916
1917         return ret;
1918 }
1919
1920 struct compat_ipt_get_entries {
1921         char name[IPT_TABLE_MAXNAMELEN];
1922         compat_uint_t size;
1923         struct compat_ipt_entry entrytable[0];
1924 };
1925
1926 static int
1927 compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table,
1928                             void __user *userptr)
1929 {
1930         struct xt_counters *counters;
1931         struct xt_table_info *private = table->private;
1932         void __user *pos;
1933         unsigned int size;
1934         int ret = 0;
1935         void *loc_cpu_entry;
1936         unsigned int i = 0;
1937
1938         counters = alloc_counters(table);
1939         if (IS_ERR(counters))
1940                 return PTR_ERR(counters);
1941
1942         /* choose the copy that is on our node/cpu, ...
1943          * This choice is lazy (because current thread is
1944          * allowed to migrate to another cpu)
1945          */
1946         loc_cpu_entry = private->entries[raw_smp_processor_id()];
1947         pos = userptr;
1948         size = total_size;
1949         ret = IPT_ENTRY_ITERATE(loc_cpu_entry, total_size,
1950                                 compat_copy_entry_to_user,
1951                                 &pos, &size, counters, &i);
1952
1953         vfree(counters);
1954         return ret;
1955 }
1956
1957 static int
1958 compat_get_entries(struct compat_ipt_get_entries __user *uptr, int *len)
1959 {
1960         int ret;
1961         struct compat_ipt_get_entries get;
1962         struct xt_table *t;
1963
1964         if (*len < sizeof(get)) {
1965                 duprintf("compat_get_entries: %u < %u\n",
1966                          *len, (unsigned int)sizeof(get));
1967                 return -EINVAL;
1968         }
1969
1970         if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1971                 return -EFAULT;
1972
1973         if (*len != sizeof(struct compat_ipt_get_entries) + get.size) {
1974                 duprintf("compat_get_entries: %u != %u\n", *len,
1975                          (unsigned int)(sizeof(struct compat_ipt_get_entries) +
1976                          get.size));
1977                 return -EINVAL;
1978         }
1979
1980         xt_compat_lock(AF_INET);
1981         t = xt_find_table_lock(AF_INET, get.name);
1982         if (t && !IS_ERR(t)) {
1983                 struct xt_table_info *private = t->private;
1984                 struct xt_table_info info;
1985                 duprintf("t->private->number = %u\n",
1986                          private->number);
1987                 ret = compat_table_info(private, &info);
1988                 if (!ret && get.size == info.size) {
1989                         ret = compat_copy_entries_to_user(private->size,
1990                                                           t, uptr->entrytable);
1991                 } else if (!ret) {
1992                         duprintf("compat_get_entries: I've got %u not %u!\n",
1993                                  private->size,
1994                                  get.size);
1995                         ret = -EINVAL;
1996                 }
1997                 compat_flush_offsets();
1998                 module_put(t->me);
1999                 xt_table_unlock(t);
2000         } else
2001                 ret = t ? PTR_ERR(t) : -ENOENT;
2002
2003         xt_compat_unlock(AF_INET);
2004         return ret;
2005 }
2006
2007 static int do_ipt_get_ctl(struct sock *, int, void __user *, int *);
2008
2009 static int
2010 compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
2011 {
2012         int ret;
2013
2014         if (!capable(CAP_NET_ADMIN))
2015                 return -EPERM;
2016
2017         switch (cmd) {
2018         case IPT_SO_GET_INFO:
2019                 ret = get_info(user, len, 1);
2020                 break;
2021         case IPT_SO_GET_ENTRIES:
2022                 ret = compat_get_entries(user, len);
2023                 break;
2024         default:
2025                 ret = do_ipt_get_ctl(sk, cmd, user, len);
2026         }
2027         return ret;
2028 }
2029 #endif
2030
2031 static int
2032 do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
2033 {
2034         int ret;
2035
2036         if (!capable(CAP_NET_ADMIN))
2037                 return -EPERM;
2038
2039         switch (cmd) {
2040         case IPT_SO_SET_REPLACE:
2041                 ret = do_replace(user, len);
2042                 break;
2043
2044         case IPT_SO_SET_ADD_COUNTERS:
2045                 ret = do_add_counters(user, len, 0);
2046                 break;
2047
2048         default:
2049                 duprintf("do_ipt_set_ctl:  unknown request %i\n", cmd);
2050                 ret = -EINVAL;
2051         }
2052
2053         return ret;
2054 }
2055
2056 static int
2057 do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
2058 {
2059         int ret;
2060
2061         if (!capable(CAP_NET_ADMIN))
2062                 return -EPERM;
2063
2064         switch (cmd) {
2065         case IPT_SO_GET_INFO:
2066                 ret = get_info(user, len, 0);
2067                 break;
2068
2069         case IPT_SO_GET_ENTRIES:
2070                 ret = get_entries(user, len);
2071                 break;
2072
2073         case IPT_SO_GET_REVISION_MATCH:
2074         case IPT_SO_GET_REVISION_TARGET: {
2075                 struct ipt_get_revision rev;
2076                 int target;
2077
2078                 if (*len != sizeof(rev)) {
2079                         ret = -EINVAL;
2080                         break;
2081                 }
2082                 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
2083                         ret = -EFAULT;
2084                         break;
2085                 }
2086
2087                 if (cmd == IPT_SO_GET_REVISION_TARGET)
2088                         target = 1;
2089                 else
2090                         target = 0;
2091
2092                 try_then_request_module(xt_find_revision(AF_INET, rev.name,
2093                                                          rev.revision,
2094                                                          target, &ret),
2095                                         "ipt_%s", rev.name);
2096                 break;
2097         }
2098
2099         default:
2100                 duprintf("do_ipt_get_ctl: unknown request %i\n", cmd);
2101                 ret = -EINVAL;
2102         }
2103
2104         return ret;
2105 }
2106
2107 int ipt_register_table(struct xt_table *table, const struct ipt_replace *repl)
2108 {
2109         int ret;
2110         struct xt_table_info *newinfo;
2111         struct xt_table_info bootstrap
2112                 = { 0, 0, 0, { 0 }, { 0 }, { } };
2113         void *loc_cpu_entry;
2114
2115         newinfo = xt_alloc_table_info(repl->size);
2116         if (!newinfo)
2117                 return -ENOMEM;
2118
2119         /* choose the copy on our node/cpu
2120          * but dont care of preemption
2121          */
2122         loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
2123         memcpy(loc_cpu_entry, repl->entries, repl->size);
2124
2125         ret = translate_table(table->name, table->valid_hooks,
2126                               newinfo, loc_cpu_entry, repl->size,
2127                               repl->num_entries,
2128                               repl->hook_entry,
2129                               repl->underflow);
2130         if (ret != 0) {
2131                 xt_free_table_info(newinfo);
2132                 return ret;
2133         }
2134
2135         ret = xt_register_table(table, &bootstrap, newinfo);
2136         if (ret != 0) {
2137                 xt_free_table_info(newinfo);
2138                 return ret;
2139         }
2140
2141         return 0;
2142 }
2143
2144 void ipt_unregister_table(struct xt_table *table)
2145 {
2146         struct xt_table_info *private;
2147         void *loc_cpu_entry;
2148
2149         private = xt_unregister_table(table);
2150
2151         /* Decrease module usage counts and free resources */
2152         loc_cpu_entry = private->entries[raw_smp_processor_id()];
2153         IPT_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
2154         xt_free_table_info(private);
2155 }
2156
2157 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
2158 static inline bool
2159 icmp_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
2160                      u_int8_t type, u_int8_t code,
2161                      bool invert)
2162 {
2163         return ((test_type == 0xFF) || (type == test_type && code >= min_code && code <= max_code))
2164                 ^ invert;
2165 }
2166
2167 static bool
2168 icmp_match(const struct sk_buff *skb,
2169            const struct net_device *in,
2170            const struct net_device *out,
2171            const struct xt_match *match,
2172            const void *matchinfo,
2173            int offset,
2174            unsigned int protoff,
2175            bool *hotdrop)
2176 {
2177         struct icmphdr _icmph, *ic;
2178         const struct ipt_icmp *icmpinfo = matchinfo;
2179
2180         /* Must not be a fragment. */
2181         if (offset)
2182                 return false;
2183
2184         ic = skb_header_pointer(skb, protoff, sizeof(_icmph), &_icmph);
2185         if (ic == NULL) {
2186                 /* We've been asked to examine this packet, and we
2187                  * can't.  Hence, no choice but to drop.
2188                  */
2189                 duprintf("Dropping evil ICMP tinygram.\n");
2190                 *hotdrop = true;
2191                 return false;
2192         }
2193
2194         return icmp_type_code_match(icmpinfo->type,
2195                                     icmpinfo->code[0],
2196                                     icmpinfo->code[1],
2197                                     ic->type, ic->code,
2198                                     !!(icmpinfo->invflags&IPT_ICMP_INV));
2199 }
2200
2201 /* Called when user tries to insert an entry of this type. */
2202 static bool
2203 icmp_checkentry(const char *tablename,
2204            const void *info,
2205            const struct xt_match *match,
2206            void *matchinfo,
2207            unsigned int hook_mask)
2208 {
2209         const struct ipt_icmp *icmpinfo = matchinfo;
2210
2211         /* Must specify no unknown invflags */
2212         return !(icmpinfo->invflags & ~IPT_ICMP_INV);
2213 }
2214
2215 /* The built-in targets: standard (NULL) and error. */
2216 static struct xt_target ipt_standard_target __read_mostly = {
2217         .name           = IPT_STANDARD_TARGET,
2218         .targetsize     = sizeof(int),
2219         .family         = AF_INET,
2220 #ifdef CONFIG_COMPAT
2221         .compatsize     = sizeof(compat_int_t),
2222         .compat_from_user = compat_standard_from_user,
2223         .compat_to_user = compat_standard_to_user,
2224 #endif
2225 };
2226
2227 static struct xt_target ipt_error_target __read_mostly = {
2228         .name           = IPT_ERROR_TARGET,
2229         .target         = ipt_error,
2230         .targetsize     = IPT_FUNCTION_MAXNAMELEN,
2231         .family         = AF_INET,
2232 };
2233
2234 static struct nf_sockopt_ops ipt_sockopts = {
2235         .pf             = PF_INET,
2236         .set_optmin     = IPT_BASE_CTL,
2237         .set_optmax     = IPT_SO_SET_MAX+1,
2238         .set            = do_ipt_set_ctl,
2239 #ifdef CONFIG_COMPAT
2240         .compat_set     = compat_do_ipt_set_ctl,
2241 #endif
2242         .get_optmin     = IPT_BASE_CTL,
2243         .get_optmax     = IPT_SO_GET_MAX+1,
2244         .get            = do_ipt_get_ctl,
2245 #ifdef CONFIG_COMPAT
2246         .compat_get     = compat_do_ipt_get_ctl,
2247 #endif
2248         .owner          = THIS_MODULE,
2249 };
2250
2251 static struct xt_match icmp_matchstruct __read_mostly = {
2252         .name           = "icmp",
2253         .match          = icmp_match,
2254         .matchsize      = sizeof(struct ipt_icmp),
2255         .proto          = IPPROTO_ICMP,
2256         .family         = AF_INET,
2257         .checkentry     = icmp_checkentry,
2258 };
2259
2260 static int __init ip_tables_init(void)
2261 {
2262         int ret;
2263
2264         ret = xt_proto_init(AF_INET);
2265         if (ret < 0)
2266                 goto err1;
2267
2268         /* Noone else will be downing sem now, so we won't sleep */
2269         ret = xt_register_target(&ipt_standard_target);
2270         if (ret < 0)
2271                 goto err2;
2272         ret = xt_register_target(&ipt_error_target);
2273         if (ret < 0)
2274                 goto err3;
2275         ret = xt_register_match(&icmp_matchstruct);
2276         if (ret < 0)
2277                 goto err4;
2278
2279         /* Register setsockopt */
2280         ret = nf_register_sockopt(&ipt_sockopts);
2281         if (ret < 0)
2282                 goto err5;
2283
2284         printk(KERN_INFO "ip_tables: (C) 2000-2006 Netfilter Core Team\n");
2285         return 0;
2286
2287 err5:
2288         xt_unregister_match(&icmp_matchstruct);
2289 err4:
2290         xt_unregister_target(&ipt_error_target);
2291 err3:
2292         xt_unregister_target(&ipt_standard_target);
2293 err2:
2294         xt_proto_fini(AF_INET);
2295 err1:
2296         return ret;
2297 }
2298
2299 static void __exit ip_tables_fini(void)
2300 {
2301         nf_unregister_sockopt(&ipt_sockopts);
2302
2303         xt_unregister_match(&icmp_matchstruct);
2304         xt_unregister_target(&ipt_error_target);
2305         xt_unregister_target(&ipt_standard_target);
2306
2307         xt_proto_fini(AF_INET);
2308 }
2309
2310 EXPORT_SYMBOL(ipt_register_table);
2311 EXPORT_SYMBOL(ipt_unregister_table);
2312 EXPORT_SYMBOL(ipt_do_table);
2313 module_init(ip_tables_init);
2314 module_exit(ip_tables_fini);