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