[NETFILTER]: Fix {ip,ip6,arp}_tables hook validation
[linux-2.6.22.y-op.git] / net / ipv4 / netfilter / ip_tables.c
blob2bddf8491982f31e032ed6dab0972fa90d191c22
1 /*
2 * Packet matching code.
4 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
5 * Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
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.
11 * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
12 * - increase module usage count as soon as we have rules inside
13 * a table
14 * 08 Oct 2005 Harald Welte <lafore@netfilter.org>
15 * - Generalize into "x_tables" layer and "{ip,ip6,arp}_tables"
17 #include <linux/cache.h>
18 #include <linux/capability.h>
19 #include <linux/skbuff.h>
20 #include <linux/kmod.h>
21 #include <linux/vmalloc.h>
22 #include <linux/netdevice.h>
23 #include <linux/module.h>
24 #include <linux/icmp.h>
25 #include <net/ip.h>
26 #include <net/compat.h>
27 #include <asm/uaccess.h>
28 #include <linux/mutex.h>
29 #include <linux/proc_fs.h>
30 #include <linux/err.h>
31 #include <linux/cpumask.h>
33 #include <linux/netfilter/x_tables.h>
34 #include <linux/netfilter_ipv4/ip_tables.h>
36 MODULE_LICENSE("GPL");
37 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
38 MODULE_DESCRIPTION("IPv4 packet filter");
40 /*#define DEBUG_IP_FIREWALL*/
41 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
42 /*#define DEBUG_IP_FIREWALL_USER*/
44 #ifdef DEBUG_IP_FIREWALL
45 #define dprintf(format, args...) printk(format , ## args)
46 #else
47 #define dprintf(format, args...)
48 #endif
50 #ifdef DEBUG_IP_FIREWALL_USER
51 #define duprintf(format, args...) printk(format , ## args)
52 #else
53 #define duprintf(format, args...)
54 #endif
56 #ifdef CONFIG_NETFILTER_DEBUG
57 #define IP_NF_ASSERT(x) \
58 do { \
59 if (!(x)) \
60 printk("IP_NF_ASSERT: %s:%s:%u\n", \
61 __FUNCTION__, __FILE__, __LINE__); \
62 } while(0)
63 #else
64 #define IP_NF_ASSERT(x)
65 #endif
67 #if 0
68 /* All the better to debug you with... */
69 #define static
70 #define inline
71 #endif
74 We keep a set of rules for each CPU, so we can avoid write-locking
75 them in the softirq when updating the counters and therefore
76 only need to read-lock in the softirq; doing a write_lock_bh() in user
77 context stops packets coming through and allows user context to read
78 the counters or update the rules.
80 Hence the start of any table is given by get_table() below. */
82 /* Returns whether matches rule or not. */
83 static inline int
84 ip_packet_match(const struct iphdr *ip,
85 const char *indev,
86 const char *outdev,
87 const struct ipt_ip *ipinfo,
88 int isfrag)
90 size_t i;
91 unsigned long ret;
93 #define FWINV(bool,invflg) ((bool) ^ !!(ipinfo->invflags & invflg))
95 if (FWINV((ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr,
96 IPT_INV_SRCIP)
97 || FWINV((ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr,
98 IPT_INV_DSTIP)) {
99 dprintf("Source or dest mismatch.\n");
101 dprintf("SRC: %u.%u.%u.%u. Mask: %u.%u.%u.%u. Target: %u.%u.%u.%u.%s\n",
102 NIPQUAD(ip->saddr),
103 NIPQUAD(ipinfo->smsk.s_addr),
104 NIPQUAD(ipinfo->src.s_addr),
105 ipinfo->invflags & IPT_INV_SRCIP ? " (INV)" : "");
106 dprintf("DST: %u.%u.%u.%u Mask: %u.%u.%u.%u Target: %u.%u.%u.%u.%s\n",
107 NIPQUAD(ip->daddr),
108 NIPQUAD(ipinfo->dmsk.s_addr),
109 NIPQUAD(ipinfo->dst.s_addr),
110 ipinfo->invflags & IPT_INV_DSTIP ? " (INV)" : "");
111 return 0;
114 /* Look for ifname matches; this should unroll nicely. */
115 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
116 ret |= (((const unsigned long *)indev)[i]
117 ^ ((const unsigned long *)ipinfo->iniface)[i])
118 & ((const unsigned long *)ipinfo->iniface_mask)[i];
121 if (FWINV(ret != 0, IPT_INV_VIA_IN)) {
122 dprintf("VIA in mismatch (%s vs %s).%s\n",
123 indev, ipinfo->iniface,
124 ipinfo->invflags&IPT_INV_VIA_IN ?" (INV)":"");
125 return 0;
128 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
129 ret |= (((const unsigned long *)outdev)[i]
130 ^ ((const unsigned long *)ipinfo->outiface)[i])
131 & ((const unsigned long *)ipinfo->outiface_mask)[i];
134 if (FWINV(ret != 0, IPT_INV_VIA_OUT)) {
135 dprintf("VIA out mismatch (%s vs %s).%s\n",
136 outdev, ipinfo->outiface,
137 ipinfo->invflags&IPT_INV_VIA_OUT ?" (INV)":"");
138 return 0;
141 /* Check specific protocol */
142 if (ipinfo->proto
143 && FWINV(ip->protocol != ipinfo->proto, IPT_INV_PROTO)) {
144 dprintf("Packet protocol %hi does not match %hi.%s\n",
145 ip->protocol, ipinfo->proto,
146 ipinfo->invflags&IPT_INV_PROTO ? " (INV)":"");
147 return 0;
150 /* If we have a fragment rule but the packet is not a fragment
151 * then we return zero */
152 if (FWINV((ipinfo->flags&IPT_F_FRAG) && !isfrag, IPT_INV_FRAG)) {
153 dprintf("Fragment rule but not fragment.%s\n",
154 ipinfo->invflags & IPT_INV_FRAG ? " (INV)" : "");
155 return 0;
158 return 1;
161 static inline int
162 ip_checkentry(const struct ipt_ip *ip)
164 if (ip->flags & ~IPT_F_MASK) {
165 duprintf("Unknown flag bits set: %08X\n",
166 ip->flags & ~IPT_F_MASK);
167 return 0;
169 if (ip->invflags & ~IPT_INV_MASK) {
170 duprintf("Unknown invflag bits set: %08X\n",
171 ip->invflags & ~IPT_INV_MASK);
172 return 0;
174 return 1;
177 static unsigned int
178 ipt_error(struct sk_buff **pskb,
179 const struct net_device *in,
180 const struct net_device *out,
181 unsigned int hooknum,
182 const struct xt_target *target,
183 const void *targinfo)
185 if (net_ratelimit())
186 printk("ip_tables: error: `%s'\n", (char *)targinfo);
188 return NF_DROP;
191 static inline
192 int do_match(struct ipt_entry_match *m,
193 const struct sk_buff *skb,
194 const struct net_device *in,
195 const struct net_device *out,
196 int offset,
197 int *hotdrop)
199 /* Stop iteration if it doesn't match */
200 if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data,
201 offset, skb->nh.iph->ihl*4, hotdrop))
202 return 1;
203 else
204 return 0;
207 static inline struct ipt_entry *
208 get_entry(void *base, unsigned int offset)
210 return (struct ipt_entry *)(base + offset);
213 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
214 unsigned int
215 ipt_do_table(struct sk_buff **pskb,
216 unsigned int hook,
217 const struct net_device *in,
218 const struct net_device *out,
219 struct ipt_table *table)
221 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
222 u_int16_t offset;
223 struct iphdr *ip;
224 u_int16_t datalen;
225 int hotdrop = 0;
226 /* Initializing verdict to NF_DROP keeps gcc happy. */
227 unsigned int verdict = NF_DROP;
228 const char *indev, *outdev;
229 void *table_base;
230 struct ipt_entry *e, *back;
231 struct xt_table_info *private;
233 /* Initialization */
234 ip = (*pskb)->nh.iph;
235 datalen = (*pskb)->len - ip->ihl * 4;
236 indev = in ? in->name : nulldevname;
237 outdev = out ? out->name : nulldevname;
238 /* We handle fragments by dealing with the first fragment as
239 * if it was a normal packet. All other fragments are treated
240 * normally, except that they will NEVER match rules that ask
241 * things we don't know, ie. tcp syn flag or ports). If the
242 * rule is also a fragment-specific rule, non-fragments won't
243 * match it. */
244 offset = ntohs(ip->frag_off) & IP_OFFSET;
246 read_lock_bh(&table->lock);
247 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
248 private = table->private;
249 table_base = (void *)private->entries[smp_processor_id()];
250 e = get_entry(table_base, private->hook_entry[hook]);
252 /* For return from builtin chain */
253 back = get_entry(table_base, private->underflow[hook]);
255 do {
256 IP_NF_ASSERT(e);
257 IP_NF_ASSERT(back);
258 if (ip_packet_match(ip, indev, outdev, &e->ip, offset)) {
259 struct ipt_entry_target *t;
261 if (IPT_MATCH_ITERATE(e, do_match,
262 *pskb, in, out,
263 offset, &hotdrop) != 0)
264 goto no_match;
266 ADD_COUNTER(e->counters, ntohs(ip->tot_len), 1);
268 t = ipt_get_target(e);
269 IP_NF_ASSERT(t->u.kernel.target);
270 /* Standard target? */
271 if (!t->u.kernel.target->target) {
272 int v;
274 v = ((struct ipt_standard_target *)t)->verdict;
275 if (v < 0) {
276 /* Pop from stack? */
277 if (v != IPT_RETURN) {
278 verdict = (unsigned)(-v) - 1;
279 break;
281 e = back;
282 back = get_entry(table_base,
283 back->comefrom);
284 continue;
286 if (table_base + v != (void *)e + e->next_offset
287 && !(e->ip.flags & IPT_F_GOTO)) {
288 /* Save old back ptr in next entry */
289 struct ipt_entry *next
290 = (void *)e + e->next_offset;
291 next->comefrom
292 = (void *)back - table_base;
293 /* set back pointer to next entry */
294 back = next;
297 e = get_entry(table_base, v);
298 } else {
299 /* Targets which reenter must return
300 abs. verdicts */
301 #ifdef CONFIG_NETFILTER_DEBUG
302 ((struct ipt_entry *)table_base)->comefrom
303 = 0xeeeeeeec;
304 #endif
305 verdict = t->u.kernel.target->target(pskb,
306 in, out,
307 hook,
308 t->u.kernel.target,
309 t->data);
311 #ifdef CONFIG_NETFILTER_DEBUG
312 if (((struct ipt_entry *)table_base)->comefrom
313 != 0xeeeeeeec
314 && verdict == IPT_CONTINUE) {
315 printk("Target %s reentered!\n",
316 t->u.kernel.target->name);
317 verdict = NF_DROP;
319 ((struct ipt_entry *)table_base)->comefrom
320 = 0x57acc001;
321 #endif
322 /* Target might have changed stuff. */
323 ip = (*pskb)->nh.iph;
324 datalen = (*pskb)->len - ip->ihl * 4;
326 if (verdict == IPT_CONTINUE)
327 e = (void *)e + e->next_offset;
328 else
329 /* Verdict */
330 break;
332 } else {
334 no_match:
335 e = (void *)e + e->next_offset;
337 } while (!hotdrop);
339 read_unlock_bh(&table->lock);
341 #ifdef DEBUG_ALLOW_ALL
342 return NF_ACCEPT;
343 #else
344 if (hotdrop)
345 return NF_DROP;
346 else return verdict;
347 #endif
350 /* All zeroes == unconditional rule. */
351 static inline int
352 unconditional(const struct ipt_ip *ip)
354 unsigned int i;
356 for (i = 0; i < sizeof(*ip)/sizeof(__u32); i++)
357 if (((__u32 *)ip)[i])
358 return 0;
360 return 1;
363 /* Figures out from what hook each rule can be called: returns 0 if
364 there are loops. Puts hook bitmask in comefrom. */
365 static int
366 mark_source_chains(struct xt_table_info *newinfo,
367 unsigned int valid_hooks, void *entry0)
369 unsigned int hook;
371 /* No recursion; use packet counter to save back ptrs (reset
372 to 0 as we leave), and comefrom to save source hook bitmask */
373 for (hook = 0; hook < NF_IP_NUMHOOKS; hook++) {
374 unsigned int pos = newinfo->hook_entry[hook];
375 struct ipt_entry *e
376 = (struct ipt_entry *)(entry0 + pos);
378 if (!(valid_hooks & (1 << hook)))
379 continue;
381 /* Set initial back pointer. */
382 e->counters.pcnt = pos;
384 for (;;) {
385 struct ipt_standard_target *t
386 = (void *)ipt_get_target(e);
388 if (e->comefrom & (1 << NF_IP_NUMHOOKS)) {
389 printk("iptables: loop hook %u pos %u %08X.\n",
390 hook, pos, e->comefrom);
391 return 0;
393 e->comefrom
394 |= ((1 << hook) | (1 << NF_IP_NUMHOOKS));
396 /* Unconditional return/END. */
397 if (e->target_offset == sizeof(struct ipt_entry)
398 && (strcmp(t->target.u.user.name,
399 IPT_STANDARD_TARGET) == 0)
400 && t->verdict < 0
401 && unconditional(&e->ip)) {
402 unsigned int oldpos, size;
404 if (t->verdict < -NF_MAX_VERDICT - 1) {
405 duprintf("mark_source_chains: bad "
406 "negative verdict (%i)\n",
407 t->verdict);
408 return 0;
411 /* Return: backtrack through the last
412 big jump. */
413 do {
414 e->comefrom ^= (1<<NF_IP_NUMHOOKS);
415 #ifdef DEBUG_IP_FIREWALL_USER
416 if (e->comefrom
417 & (1 << NF_IP_NUMHOOKS)) {
418 duprintf("Back unset "
419 "on hook %u "
420 "rule %u\n",
421 hook, pos);
423 #endif
424 oldpos = pos;
425 pos = e->counters.pcnt;
426 e->counters.pcnt = 0;
428 /* We're at the start. */
429 if (pos == oldpos)
430 goto next;
432 e = (struct ipt_entry *)
433 (entry0 + pos);
434 } while (oldpos == pos + e->next_offset);
436 /* Move along one */
437 size = e->next_offset;
438 e = (struct ipt_entry *)
439 (entry0 + pos + size);
440 e->counters.pcnt = pos;
441 pos += size;
442 } else {
443 int newpos = t->verdict;
445 if (strcmp(t->target.u.user.name,
446 IPT_STANDARD_TARGET) == 0
447 && newpos >= 0) {
448 if (newpos > newinfo->size -
449 sizeof(struct ipt_entry)) {
450 duprintf("mark_source_chains: "
451 "bad verdict (%i)\n",
452 newpos);
453 return 0;
455 /* This a jump; chase it. */
456 duprintf("Jump rule %u -> %u\n",
457 pos, newpos);
458 } else {
459 /* ... this is a fallthru */
460 newpos = pos + e->next_offset;
462 e = (struct ipt_entry *)
463 (entry0 + newpos);
464 e->counters.pcnt = pos;
465 pos = newpos;
468 next:
469 duprintf("Finished chain %u\n", hook);
471 return 1;
474 static inline int
475 cleanup_match(struct ipt_entry_match *m, unsigned int *i)
477 if (i && (*i)-- == 0)
478 return 1;
480 if (m->u.kernel.match->destroy)
481 m->u.kernel.match->destroy(m->u.kernel.match, m->data);
482 module_put(m->u.kernel.match->me);
483 return 0;
486 static inline int
487 check_match(struct ipt_entry_match *m,
488 const char *name,
489 const struct ipt_ip *ip,
490 unsigned int hookmask,
491 unsigned int *i)
493 struct ipt_match *match;
494 int ret;
496 match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
497 m->u.user.revision),
498 "ipt_%s", m->u.user.name);
499 if (IS_ERR(match) || !match) {
500 duprintf("check_match: `%s' not found\n", m->u.user.name);
501 return match ? PTR_ERR(match) : -ENOENT;
503 m->u.kernel.match = match;
505 ret = xt_check_match(match, AF_INET, m->u.match_size - sizeof(*m),
506 name, hookmask, ip->proto,
507 ip->invflags & IPT_INV_PROTO);
508 if (ret)
509 goto err;
511 if (m->u.kernel.match->checkentry
512 && !m->u.kernel.match->checkentry(name, ip, match, m->data,
513 hookmask)) {
514 duprintf("ip_tables: check failed for `%s'.\n",
515 m->u.kernel.match->name);
516 ret = -EINVAL;
517 goto err;
520 (*i)++;
521 return 0;
522 err:
523 module_put(m->u.kernel.match->me);
524 return ret;
527 static struct ipt_target ipt_standard_target;
529 static inline int
530 check_entry(struct ipt_entry *e, const char *name, unsigned int size,
531 unsigned int *i)
533 struct ipt_entry_target *t;
534 struct ipt_target *target;
535 int ret;
536 unsigned int j;
538 if (!ip_checkentry(&e->ip)) {
539 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
540 return -EINVAL;
543 if (e->target_offset + sizeof(struct ipt_entry_target) > e->next_offset)
544 return -EINVAL;
546 j = 0;
547 ret = IPT_MATCH_ITERATE(e, check_match, name, &e->ip, e->comefrom, &j);
548 if (ret != 0)
549 goto cleanup_matches;
551 t = ipt_get_target(e);
552 ret = -EINVAL;
553 if (e->target_offset + t->u.target_size > e->next_offset)
554 goto cleanup_matches;
555 target = try_then_request_module(xt_find_target(AF_INET,
556 t->u.user.name,
557 t->u.user.revision),
558 "ipt_%s", t->u.user.name);
559 if (IS_ERR(target) || !target) {
560 duprintf("check_entry: `%s' not found\n", t->u.user.name);
561 ret = target ? PTR_ERR(target) : -ENOENT;
562 goto cleanup_matches;
564 t->u.kernel.target = target;
566 ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),
567 name, e->comefrom, e->ip.proto,
568 e->ip.invflags & IPT_INV_PROTO);
569 if (ret)
570 goto err;
572 if (t->u.kernel.target->checkentry
573 && !t->u.kernel.target->checkentry(name, e, target, t->data,
574 e->comefrom)) {
575 duprintf("ip_tables: check failed for `%s'.\n",
576 t->u.kernel.target->name);
577 ret = -EINVAL;
578 goto err;
581 (*i)++;
582 return 0;
583 err:
584 module_put(t->u.kernel.target->me);
585 cleanup_matches:
586 IPT_MATCH_ITERATE(e, cleanup_match, &j);
587 return ret;
590 static inline int
591 check_entry_size_and_hooks(struct ipt_entry *e,
592 struct xt_table_info *newinfo,
593 unsigned char *base,
594 unsigned char *limit,
595 const unsigned int *hook_entries,
596 const unsigned int *underflows,
597 unsigned int *i)
599 unsigned int h;
601 if ((unsigned long)e % __alignof__(struct ipt_entry) != 0
602 || (unsigned char *)e + sizeof(struct ipt_entry) >= limit) {
603 duprintf("Bad offset %p\n", e);
604 return -EINVAL;
607 if (e->next_offset
608 < sizeof(struct ipt_entry) + sizeof(struct ipt_entry_target)) {
609 duprintf("checking: element %p size %u\n",
610 e, e->next_offset);
611 return -EINVAL;
614 /* Check hooks & underflows */
615 for (h = 0; h < NF_IP_NUMHOOKS; h++) {
616 if ((unsigned char *)e - base == hook_entries[h])
617 newinfo->hook_entry[h] = hook_entries[h];
618 if ((unsigned char *)e - base == underflows[h])
619 newinfo->underflow[h] = underflows[h];
622 /* FIXME: underflows must be unconditional, standard verdicts
623 < 0 (not IPT_RETURN). --RR */
625 /* Clear counters and comefrom */
626 e->counters = ((struct xt_counters) { 0, 0 });
627 e->comefrom = 0;
629 (*i)++;
630 return 0;
633 static inline int
634 cleanup_entry(struct ipt_entry *e, unsigned int *i)
636 struct ipt_entry_target *t;
638 if (i && (*i)-- == 0)
639 return 1;
641 /* Cleanup all matches */
642 IPT_MATCH_ITERATE(e, cleanup_match, NULL);
643 t = ipt_get_target(e);
644 if (t->u.kernel.target->destroy)
645 t->u.kernel.target->destroy(t->u.kernel.target, t->data);
646 module_put(t->u.kernel.target->me);
647 return 0;
650 /* Checks and translates the user-supplied table segment (held in
651 newinfo) */
652 static int
653 translate_table(const char *name,
654 unsigned int valid_hooks,
655 struct xt_table_info *newinfo,
656 void *entry0,
657 unsigned int size,
658 unsigned int number,
659 const unsigned int *hook_entries,
660 const unsigned int *underflows)
662 unsigned int i;
663 int ret;
665 newinfo->size = size;
666 newinfo->number = number;
668 /* Init all hooks to impossible value. */
669 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
670 newinfo->hook_entry[i] = 0xFFFFFFFF;
671 newinfo->underflow[i] = 0xFFFFFFFF;
674 duprintf("translate_table: size %u\n", newinfo->size);
675 i = 0;
676 /* Walk through entries, checking offsets. */
677 ret = IPT_ENTRY_ITERATE(entry0, newinfo->size,
678 check_entry_size_and_hooks,
679 newinfo,
680 entry0,
681 entry0 + size,
682 hook_entries, underflows, &i);
683 if (ret != 0)
684 return ret;
686 if (i != number) {
687 duprintf("translate_table: %u not %u entries\n",
688 i, number);
689 return -EINVAL;
692 /* Check hooks all assigned */
693 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
694 /* Only hooks which are valid */
695 if (!(valid_hooks & (1 << i)))
696 continue;
697 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
698 duprintf("Invalid hook entry %u %u\n",
699 i, hook_entries[i]);
700 return -EINVAL;
702 if (newinfo->underflow[i] == 0xFFFFFFFF) {
703 duprintf("Invalid underflow %u %u\n",
704 i, underflows[i]);
705 return -EINVAL;
709 if (!mark_source_chains(newinfo, valid_hooks, entry0))
710 return -ELOOP;
712 /* Finally, each sanity check must pass */
713 i = 0;
714 ret = IPT_ENTRY_ITERATE(entry0, newinfo->size,
715 check_entry, name, size, &i);
717 if (ret != 0) {
718 IPT_ENTRY_ITERATE(entry0, newinfo->size,
719 cleanup_entry, &i);
720 return ret;
723 /* And one copy for every other CPU */
724 for_each_possible_cpu(i) {
725 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
726 memcpy(newinfo->entries[i], entry0, newinfo->size);
729 return ret;
732 /* Gets counters. */
733 static inline int
734 add_entry_to_counter(const struct ipt_entry *e,
735 struct xt_counters total[],
736 unsigned int *i)
738 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
740 (*i)++;
741 return 0;
744 static inline int
745 set_entry_to_counter(const struct ipt_entry *e,
746 struct ipt_counters total[],
747 unsigned int *i)
749 SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
751 (*i)++;
752 return 0;
755 static void
756 get_counters(const struct xt_table_info *t,
757 struct xt_counters counters[])
759 unsigned int cpu;
760 unsigned int i;
761 unsigned int curcpu;
763 /* Instead of clearing (by a previous call to memset())
764 * the counters and using adds, we set the counters
765 * with data used by 'current' CPU
766 * We dont care about preemption here.
768 curcpu = raw_smp_processor_id();
770 i = 0;
771 IPT_ENTRY_ITERATE(t->entries[curcpu],
772 t->size,
773 set_entry_to_counter,
774 counters,
775 &i);
777 for_each_possible_cpu(cpu) {
778 if (cpu == curcpu)
779 continue;
780 i = 0;
781 IPT_ENTRY_ITERATE(t->entries[cpu],
782 t->size,
783 add_entry_to_counter,
784 counters,
785 &i);
789 static inline struct xt_counters * alloc_counters(struct ipt_table *table)
791 unsigned int countersize;
792 struct xt_counters *counters;
793 struct xt_table_info *private = table->private;
795 /* We need atomic snapshot of counters: rest doesn't change
796 (other than comefrom, which userspace doesn't care
797 about). */
798 countersize = sizeof(struct xt_counters) * private->number;
799 counters = vmalloc_node(countersize, numa_node_id());
801 if (counters == NULL)
802 return ERR_PTR(-ENOMEM);
804 /* First, sum counters... */
805 write_lock_bh(&table->lock);
806 get_counters(private, counters);
807 write_unlock_bh(&table->lock);
809 return counters;
812 static int
813 copy_entries_to_user(unsigned int total_size,
814 struct ipt_table *table,
815 void __user *userptr)
817 unsigned int off, num;
818 struct ipt_entry *e;
819 struct xt_counters *counters;
820 struct xt_table_info *private = table->private;
821 int ret = 0;
822 void *loc_cpu_entry;
824 counters = alloc_counters(table);
825 if (IS_ERR(counters))
826 return PTR_ERR(counters);
828 /* choose the copy that is on our node/cpu, ...
829 * This choice is lazy (because current thread is
830 * allowed to migrate to another cpu)
832 loc_cpu_entry = private->entries[raw_smp_processor_id()];
833 /* ... then copy entire thing ... */
834 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
835 ret = -EFAULT;
836 goto free_counters;
839 /* FIXME: use iterator macros --RR */
840 /* ... then go back and fix counters and names */
841 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
842 unsigned int i;
843 struct ipt_entry_match *m;
844 struct ipt_entry_target *t;
846 e = (struct ipt_entry *)(loc_cpu_entry + off);
847 if (copy_to_user(userptr + off
848 + offsetof(struct ipt_entry, counters),
849 &counters[num],
850 sizeof(counters[num])) != 0) {
851 ret = -EFAULT;
852 goto free_counters;
855 for (i = sizeof(struct ipt_entry);
856 i < e->target_offset;
857 i += m->u.match_size) {
858 m = (void *)e + i;
860 if (copy_to_user(userptr + off + i
861 + offsetof(struct ipt_entry_match,
862 u.user.name),
863 m->u.kernel.match->name,
864 strlen(m->u.kernel.match->name)+1)
865 != 0) {
866 ret = -EFAULT;
867 goto free_counters;
871 t = ipt_get_target(e);
872 if (copy_to_user(userptr + off + e->target_offset
873 + offsetof(struct ipt_entry_target,
874 u.user.name),
875 t->u.kernel.target->name,
876 strlen(t->u.kernel.target->name)+1) != 0) {
877 ret = -EFAULT;
878 goto free_counters;
882 free_counters:
883 vfree(counters);
884 return ret;
887 #ifdef CONFIG_COMPAT
888 struct compat_delta {
889 struct compat_delta *next;
890 u_int16_t offset;
891 short delta;
894 static struct compat_delta *compat_offsets = NULL;
896 static int compat_add_offset(u_int16_t offset, short delta)
898 struct compat_delta *tmp;
900 tmp = kmalloc(sizeof(struct compat_delta), GFP_KERNEL);
901 if (!tmp)
902 return -ENOMEM;
903 tmp->offset = offset;
904 tmp->delta = delta;
905 if (compat_offsets) {
906 tmp->next = compat_offsets->next;
907 compat_offsets->next = tmp;
908 } else {
909 compat_offsets = tmp;
910 tmp->next = NULL;
912 return 0;
915 static void compat_flush_offsets(void)
917 struct compat_delta *tmp, *next;
919 if (compat_offsets) {
920 for(tmp = compat_offsets; tmp; tmp = next) {
921 next = tmp->next;
922 kfree(tmp);
924 compat_offsets = NULL;
928 static short compat_calc_jump(u_int16_t offset)
930 struct compat_delta *tmp;
931 short delta;
933 for(tmp = compat_offsets, delta = 0; tmp; tmp = tmp->next)
934 if (tmp->offset < offset)
935 delta += tmp->delta;
936 return delta;
939 static void compat_standard_from_user(void *dst, void *src)
941 int v = *(compat_int_t *)src;
943 if (v > 0)
944 v += compat_calc_jump(v);
945 memcpy(dst, &v, sizeof(v));
948 static int compat_standard_to_user(void __user *dst, void *src)
950 compat_int_t cv = *(int *)src;
952 if (cv > 0)
953 cv -= compat_calc_jump(cv);
954 return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
957 static inline int
958 compat_calc_match(struct ipt_entry_match *m, int * size)
960 *size += xt_compat_match_offset(m->u.kernel.match);
961 return 0;
964 static int compat_calc_entry(struct ipt_entry *e, struct xt_table_info *info,
965 void *base, struct xt_table_info *newinfo)
967 struct ipt_entry_target *t;
968 u_int16_t entry_offset;
969 int off, i, ret;
971 off = 0;
972 entry_offset = (void *)e - base;
973 IPT_MATCH_ITERATE(e, compat_calc_match, &off);
974 t = ipt_get_target(e);
975 off += xt_compat_target_offset(t->u.kernel.target);
976 newinfo->size -= off;
977 ret = compat_add_offset(entry_offset, off);
978 if (ret)
979 return ret;
981 for (i = 0; i< NF_IP_NUMHOOKS; i++) {
982 if (info->hook_entry[i] && (e < (struct ipt_entry *)
983 (base + info->hook_entry[i])))
984 newinfo->hook_entry[i] -= off;
985 if (info->underflow[i] && (e < (struct ipt_entry *)
986 (base + info->underflow[i])))
987 newinfo->underflow[i] -= off;
989 return 0;
992 static int compat_table_info(struct xt_table_info *info,
993 struct xt_table_info *newinfo)
995 void *loc_cpu_entry;
996 int i;
998 if (!newinfo || !info)
999 return -EINVAL;
1001 memset(newinfo, 0, sizeof(struct xt_table_info));
1002 newinfo->size = info->size;
1003 newinfo->number = info->number;
1004 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1005 newinfo->hook_entry[i] = info->hook_entry[i];
1006 newinfo->underflow[i] = info->underflow[i];
1008 loc_cpu_entry = info->entries[raw_smp_processor_id()];
1009 return IPT_ENTRY_ITERATE(loc_cpu_entry, info->size,
1010 compat_calc_entry, info, loc_cpu_entry, newinfo);
1012 #endif
1014 static int get_info(void __user *user, int *len, int compat)
1016 char name[IPT_TABLE_MAXNAMELEN];
1017 struct ipt_table *t;
1018 int ret;
1020 if (*len != sizeof(struct ipt_getinfo)) {
1021 duprintf("length %u != %u\n", *len,
1022 (unsigned int)sizeof(struct ipt_getinfo));
1023 return -EINVAL;
1026 if (copy_from_user(name, user, sizeof(name)) != 0)
1027 return -EFAULT;
1029 name[IPT_TABLE_MAXNAMELEN-1] = '\0';
1030 #ifdef CONFIG_COMPAT
1031 if (compat)
1032 xt_compat_lock(AF_INET);
1033 #endif
1034 t = try_then_request_module(xt_find_table_lock(AF_INET, name),
1035 "iptable_%s", name);
1036 if (t && !IS_ERR(t)) {
1037 struct ipt_getinfo info;
1038 struct xt_table_info *private = t->private;
1040 #ifdef CONFIG_COMPAT
1041 if (compat) {
1042 struct xt_table_info tmp;
1043 ret = compat_table_info(private, &tmp);
1044 compat_flush_offsets();
1045 private = &tmp;
1047 #endif
1048 info.valid_hooks = t->valid_hooks;
1049 memcpy(info.hook_entry, private->hook_entry,
1050 sizeof(info.hook_entry));
1051 memcpy(info.underflow, private->underflow,
1052 sizeof(info.underflow));
1053 info.num_entries = private->number;
1054 info.size = private->size;
1055 strcpy(info.name, name);
1057 if (copy_to_user(user, &info, *len) != 0)
1058 ret = -EFAULT;
1059 else
1060 ret = 0;
1062 xt_table_unlock(t);
1063 module_put(t->me);
1064 } else
1065 ret = t ? PTR_ERR(t) : -ENOENT;
1066 #ifdef CONFIG_COMPAT
1067 if (compat)
1068 xt_compat_unlock(AF_INET);
1069 #endif
1070 return ret;
1073 static int
1074 get_entries(struct ipt_get_entries __user *uptr, int *len)
1076 int ret;
1077 struct ipt_get_entries get;
1078 struct ipt_table *t;
1080 if (*len < sizeof(get)) {
1081 duprintf("get_entries: %u < %d\n", *len,
1082 (unsigned int)sizeof(get));
1083 return -EINVAL;
1085 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1086 return -EFAULT;
1087 if (*len != sizeof(struct ipt_get_entries) + get.size) {
1088 duprintf("get_entries: %u != %u\n", *len,
1089 (unsigned int)(sizeof(struct ipt_get_entries) +
1090 get.size));
1091 return -EINVAL;
1094 t = xt_find_table_lock(AF_INET, get.name);
1095 if (t && !IS_ERR(t)) {
1096 struct xt_table_info *private = t->private;
1097 duprintf("t->private->number = %u\n",
1098 private->number);
1099 if (get.size == private->size)
1100 ret = copy_entries_to_user(private->size,
1101 t, uptr->entrytable);
1102 else {
1103 duprintf("get_entries: I've got %u not %u!\n",
1104 private->size,
1105 get.size);
1106 ret = -EINVAL;
1108 module_put(t->me);
1109 xt_table_unlock(t);
1110 } else
1111 ret = t ? PTR_ERR(t) : -ENOENT;
1113 return ret;
1116 static int
1117 __do_replace(const char *name, unsigned int valid_hooks,
1118 struct xt_table_info *newinfo, unsigned int num_counters,
1119 void __user *counters_ptr)
1121 int ret;
1122 struct ipt_table *t;
1123 struct xt_table_info *oldinfo;
1124 struct xt_counters *counters;
1125 void *loc_cpu_old_entry;
1127 ret = 0;
1128 counters = vmalloc(num_counters * sizeof(struct xt_counters));
1129 if (!counters) {
1130 ret = -ENOMEM;
1131 goto out;
1134 t = try_then_request_module(xt_find_table_lock(AF_INET, name),
1135 "iptable_%s", name);
1136 if (!t || IS_ERR(t)) {
1137 ret = t ? PTR_ERR(t) : -ENOENT;
1138 goto free_newinfo_counters_untrans;
1141 /* You lied! */
1142 if (valid_hooks != t->valid_hooks) {
1143 duprintf("Valid hook crap: %08X vs %08X\n",
1144 valid_hooks, t->valid_hooks);
1145 ret = -EINVAL;
1146 goto put_module;
1149 oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);
1150 if (!oldinfo)
1151 goto put_module;
1153 /* Update module usage count based on number of rules */
1154 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1155 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1156 if ((oldinfo->number > oldinfo->initial_entries) ||
1157 (newinfo->number <= oldinfo->initial_entries))
1158 module_put(t->me);
1159 if ((oldinfo->number > oldinfo->initial_entries) &&
1160 (newinfo->number <= oldinfo->initial_entries))
1161 module_put(t->me);
1163 /* Get the old counters. */
1164 get_counters(oldinfo, counters);
1165 /* Decrease module usage counts and free resource */
1166 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1167 IPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
1168 xt_free_table_info(oldinfo);
1169 if (copy_to_user(counters_ptr, counters,
1170 sizeof(struct xt_counters) * num_counters) != 0)
1171 ret = -EFAULT;
1172 vfree(counters);
1173 xt_table_unlock(t);
1174 return ret;
1176 put_module:
1177 module_put(t->me);
1178 xt_table_unlock(t);
1179 free_newinfo_counters_untrans:
1180 vfree(counters);
1181 out:
1182 return ret;
1185 static int
1186 do_replace(void __user *user, unsigned int len)
1188 int ret;
1189 struct ipt_replace tmp;
1190 struct xt_table_info *newinfo;
1191 void *loc_cpu_entry;
1193 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1194 return -EFAULT;
1196 /* Hack: Causes ipchains to give correct error msg --RR */
1197 if (len != sizeof(tmp) + tmp.size)
1198 return -ENOPROTOOPT;
1200 /* overflow check */
1201 if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
1202 SMP_CACHE_BYTES)
1203 return -ENOMEM;
1204 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1205 return -ENOMEM;
1207 newinfo = xt_alloc_table_info(tmp.size);
1208 if (!newinfo)
1209 return -ENOMEM;
1211 /* choose the copy that is our node/cpu */
1212 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1213 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1214 tmp.size) != 0) {
1215 ret = -EFAULT;
1216 goto free_newinfo;
1219 ret = translate_table(tmp.name, tmp.valid_hooks,
1220 newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
1221 tmp.hook_entry, tmp.underflow);
1222 if (ret != 0)
1223 goto free_newinfo;
1225 duprintf("ip_tables: Translated table\n");
1227 ret = __do_replace(tmp.name, tmp.valid_hooks,
1228 newinfo, tmp.num_counters,
1229 tmp.counters);
1230 if (ret)
1231 goto free_newinfo_untrans;
1232 return 0;
1234 free_newinfo_untrans:
1235 IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1236 free_newinfo:
1237 xt_free_table_info(newinfo);
1238 return ret;
1241 /* We're lazy, and add to the first CPU; overflow works its fey magic
1242 * and everything is OK. */
1243 static inline int
1244 add_counter_to_entry(struct ipt_entry *e,
1245 const struct xt_counters addme[],
1246 unsigned int *i)
1248 #if 0
1249 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1251 (long unsigned int)e->counters.pcnt,
1252 (long unsigned int)e->counters.bcnt,
1253 (long unsigned int)addme[*i].pcnt,
1254 (long unsigned int)addme[*i].bcnt);
1255 #endif
1257 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1259 (*i)++;
1260 return 0;
1263 static int
1264 do_add_counters(void __user *user, unsigned int len, int compat)
1266 unsigned int i;
1267 struct xt_counters_info tmp;
1268 struct xt_counters *paddc;
1269 unsigned int num_counters;
1270 char *name;
1271 int size;
1272 void *ptmp;
1273 struct ipt_table *t;
1274 struct xt_table_info *private;
1275 int ret = 0;
1276 void *loc_cpu_entry;
1277 #ifdef CONFIG_COMPAT
1278 struct compat_xt_counters_info compat_tmp;
1280 if (compat) {
1281 ptmp = &compat_tmp;
1282 size = sizeof(struct compat_xt_counters_info);
1283 } else
1284 #endif
1286 ptmp = &tmp;
1287 size = sizeof(struct xt_counters_info);
1290 if (copy_from_user(ptmp, user, size) != 0)
1291 return -EFAULT;
1293 #ifdef CONFIG_COMPAT
1294 if (compat) {
1295 num_counters = compat_tmp.num_counters;
1296 name = compat_tmp.name;
1297 } else
1298 #endif
1300 num_counters = tmp.num_counters;
1301 name = tmp.name;
1304 if (len != size + num_counters * sizeof(struct xt_counters))
1305 return -EINVAL;
1307 paddc = vmalloc_node(len - size, numa_node_id());
1308 if (!paddc)
1309 return -ENOMEM;
1311 if (copy_from_user(paddc, user + size, len - size) != 0) {
1312 ret = -EFAULT;
1313 goto free;
1316 t = xt_find_table_lock(AF_INET, name);
1317 if (!t || IS_ERR(t)) {
1318 ret = t ? PTR_ERR(t) : -ENOENT;
1319 goto free;
1322 write_lock_bh(&t->lock);
1323 private = t->private;
1324 if (private->number != num_counters) {
1325 ret = -EINVAL;
1326 goto unlock_up_free;
1329 i = 0;
1330 /* Choose the copy that is on our node */
1331 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1332 IPT_ENTRY_ITERATE(loc_cpu_entry,
1333 private->size,
1334 add_counter_to_entry,
1335 paddc,
1336 &i);
1337 unlock_up_free:
1338 write_unlock_bh(&t->lock);
1339 xt_table_unlock(t);
1340 module_put(t->me);
1341 free:
1342 vfree(paddc);
1344 return ret;
1347 #ifdef CONFIG_COMPAT
1348 struct compat_ipt_replace {
1349 char name[IPT_TABLE_MAXNAMELEN];
1350 u32 valid_hooks;
1351 u32 num_entries;
1352 u32 size;
1353 u32 hook_entry[NF_IP_NUMHOOKS];
1354 u32 underflow[NF_IP_NUMHOOKS];
1355 u32 num_counters;
1356 compat_uptr_t counters; /* struct ipt_counters * */
1357 struct compat_ipt_entry entries[0];
1360 static inline int compat_copy_match_to_user(struct ipt_entry_match *m,
1361 void __user **dstptr, compat_uint_t *size)
1363 return xt_compat_match_to_user(m, dstptr, size);
1366 static int compat_copy_entry_to_user(struct ipt_entry *e,
1367 void __user **dstptr, compat_uint_t *size)
1369 struct ipt_entry_target *t;
1370 struct compat_ipt_entry __user *ce;
1371 u_int16_t target_offset, next_offset;
1372 compat_uint_t origsize;
1373 int ret;
1375 ret = -EFAULT;
1376 origsize = *size;
1377 ce = (struct compat_ipt_entry __user *)*dstptr;
1378 if (copy_to_user(ce, e, sizeof(struct ipt_entry)))
1379 goto out;
1381 *dstptr += sizeof(struct compat_ipt_entry);
1382 ret = IPT_MATCH_ITERATE(e, compat_copy_match_to_user, dstptr, size);
1383 target_offset = e->target_offset - (origsize - *size);
1384 if (ret)
1385 goto out;
1386 t = ipt_get_target(e);
1387 ret = xt_compat_target_to_user(t, dstptr, size);
1388 if (ret)
1389 goto out;
1390 ret = -EFAULT;
1391 next_offset = e->next_offset - (origsize - *size);
1392 if (put_user(target_offset, &ce->target_offset))
1393 goto out;
1394 if (put_user(next_offset, &ce->next_offset))
1395 goto out;
1396 return 0;
1397 out:
1398 return ret;
1401 static inline int
1402 compat_check_calc_match(struct ipt_entry_match *m,
1403 const char *name,
1404 const struct ipt_ip *ip,
1405 unsigned int hookmask,
1406 int *size, int *i)
1408 struct ipt_match *match;
1410 match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
1411 m->u.user.revision),
1412 "ipt_%s", m->u.user.name);
1413 if (IS_ERR(match) || !match) {
1414 duprintf("compat_check_calc_match: `%s' not found\n",
1415 m->u.user.name);
1416 return match ? PTR_ERR(match) : -ENOENT;
1418 m->u.kernel.match = match;
1419 *size += xt_compat_match_offset(match);
1421 (*i)++;
1422 return 0;
1425 static inline int
1426 check_compat_entry_size_and_hooks(struct ipt_entry *e,
1427 struct xt_table_info *newinfo,
1428 unsigned int *size,
1429 unsigned char *base,
1430 unsigned char *limit,
1431 unsigned int *hook_entries,
1432 unsigned int *underflows,
1433 unsigned int *i,
1434 const char *name)
1436 struct ipt_entry_target *t;
1437 struct ipt_target *target;
1438 u_int16_t entry_offset;
1439 int ret, off, h, j;
1441 duprintf("check_compat_entry_size_and_hooks %p\n", e);
1442 if ((unsigned long)e % __alignof__(struct compat_ipt_entry) != 0
1443 || (unsigned char *)e + sizeof(struct compat_ipt_entry) >= limit) {
1444 duprintf("Bad offset %p, limit = %p\n", e, limit);
1445 return -EINVAL;
1448 if (e->next_offset < sizeof(struct compat_ipt_entry) +
1449 sizeof(struct compat_xt_entry_target)) {
1450 duprintf("checking: element %p size %u\n",
1451 e, e->next_offset);
1452 return -EINVAL;
1455 if (!ip_checkentry(&e->ip)) {
1456 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
1457 return -EINVAL;
1460 if (e->target_offset + sizeof(struct compat_xt_entry_target) >
1461 e->next_offset)
1462 return -EINVAL;
1464 off = 0;
1465 entry_offset = (void *)e - (void *)base;
1466 j = 0;
1467 ret = IPT_MATCH_ITERATE(e, compat_check_calc_match, name, &e->ip,
1468 e->comefrom, &off, &j);
1469 if (ret != 0)
1470 goto cleanup_matches;
1472 t = ipt_get_target(e);
1473 ret = -EINVAL;
1474 if (e->target_offset + t->u.target_size > e->next_offset)
1475 goto cleanup_matches;
1476 target = try_then_request_module(xt_find_target(AF_INET,
1477 t->u.user.name,
1478 t->u.user.revision),
1479 "ipt_%s", t->u.user.name);
1480 if (IS_ERR(target) || !target) {
1481 duprintf("check_entry: `%s' not found\n", t->u.user.name);
1482 ret = target ? PTR_ERR(target) : -ENOENT;
1483 goto cleanup_matches;
1485 t->u.kernel.target = target;
1487 off += xt_compat_target_offset(target);
1488 *size += off;
1489 ret = compat_add_offset(entry_offset, off);
1490 if (ret)
1491 goto out;
1493 /* Check hooks & underflows */
1494 for (h = 0; h < NF_IP_NUMHOOKS; h++) {
1495 if ((unsigned char *)e - base == hook_entries[h])
1496 newinfo->hook_entry[h] = hook_entries[h];
1497 if ((unsigned char *)e - base == underflows[h])
1498 newinfo->underflow[h] = underflows[h];
1501 /* Clear counters and comefrom */
1502 e->counters = ((struct ipt_counters) { 0, 0 });
1503 e->comefrom = 0;
1505 (*i)++;
1506 return 0;
1508 out:
1509 module_put(t->u.kernel.target->me);
1510 cleanup_matches:
1511 IPT_MATCH_ITERATE(e, cleanup_match, &j);
1512 return ret;
1515 static inline int compat_copy_match_from_user(struct ipt_entry_match *m,
1516 void **dstptr, compat_uint_t *size, const char *name,
1517 const struct ipt_ip *ip, unsigned int hookmask)
1519 struct ipt_entry_match *dm;
1520 struct ipt_match *match;
1521 int ret;
1523 dm = (struct ipt_entry_match *)*dstptr;
1524 match = m->u.kernel.match;
1525 xt_compat_match_from_user(m, dstptr, size);
1527 ret = xt_check_match(match, AF_INET, dm->u.match_size - sizeof(*dm),
1528 name, hookmask, ip->proto,
1529 ip->invflags & IPT_INV_PROTO);
1530 if (!ret && m->u.kernel.match->checkentry
1531 && !m->u.kernel.match->checkentry(name, ip, match, dm->data,
1532 hookmask)) {
1533 duprintf("ip_tables: check failed for `%s'.\n",
1534 m->u.kernel.match->name);
1535 ret = -EINVAL;
1537 return ret;
1540 static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
1541 unsigned int *size, const char *name,
1542 struct xt_table_info *newinfo, unsigned char *base)
1544 struct ipt_entry_target *t;
1545 struct ipt_target *target;
1546 struct ipt_entry *de;
1547 unsigned int origsize;
1548 int ret, h;
1550 ret = 0;
1551 origsize = *size;
1552 de = (struct ipt_entry *)*dstptr;
1553 memcpy(de, e, sizeof(struct ipt_entry));
1555 *dstptr += sizeof(struct compat_ipt_entry);
1556 ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size,
1557 name, &de->ip, de->comefrom);
1558 if (ret)
1559 goto err;
1560 de->target_offset = e->target_offset - (origsize - *size);
1561 t = ipt_get_target(e);
1562 target = t->u.kernel.target;
1563 xt_compat_target_from_user(t, dstptr, size);
1565 de->next_offset = e->next_offset - (origsize - *size);
1566 for (h = 0; h < NF_IP_NUMHOOKS; h++) {
1567 if ((unsigned char *)de - base < newinfo->hook_entry[h])
1568 newinfo->hook_entry[h] -= origsize - *size;
1569 if ((unsigned char *)de - base < newinfo->underflow[h])
1570 newinfo->underflow[h] -= origsize - *size;
1573 t = ipt_get_target(de);
1574 target = t->u.kernel.target;
1575 ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),
1576 name, e->comefrom, e->ip.proto,
1577 e->ip.invflags & IPT_INV_PROTO);
1578 if (ret)
1579 goto err;
1581 if (t->u.kernel.target->checkentry
1582 && !t->u.kernel.target->checkentry(name, de, target,
1583 t->data, de->comefrom)) {
1584 duprintf("ip_tables: compat: check failed for `%s'.\n",
1585 t->u.kernel.target->name);
1586 ret = -EINVAL;
1588 err:
1589 return ret;
1592 static int
1593 translate_compat_table(const char *name,
1594 unsigned int valid_hooks,
1595 struct xt_table_info **pinfo,
1596 void **pentry0,
1597 unsigned int total_size,
1598 unsigned int number,
1599 unsigned int *hook_entries,
1600 unsigned int *underflows)
1602 unsigned int i, j;
1603 struct xt_table_info *newinfo, *info;
1604 void *pos, *entry0, *entry1;
1605 unsigned int size;
1606 int ret;
1608 info = *pinfo;
1609 entry0 = *pentry0;
1610 size = total_size;
1611 info->number = number;
1613 /* Init all hooks to impossible value. */
1614 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1615 info->hook_entry[i] = 0xFFFFFFFF;
1616 info->underflow[i] = 0xFFFFFFFF;
1619 duprintf("translate_compat_table: size %u\n", info->size);
1620 j = 0;
1621 xt_compat_lock(AF_INET);
1622 /* Walk through entries, checking offsets. */
1623 ret = IPT_ENTRY_ITERATE(entry0, total_size,
1624 check_compat_entry_size_and_hooks,
1625 info, &size, entry0,
1626 entry0 + total_size,
1627 hook_entries, underflows, &j, name);
1628 if (ret != 0)
1629 goto out_unlock;
1631 ret = -EINVAL;
1632 if (j != number) {
1633 duprintf("translate_compat_table: %u not %u entries\n",
1634 j, number);
1635 goto out_unlock;
1638 /* Check hooks all assigned */
1639 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1640 /* Only hooks which are valid */
1641 if (!(valid_hooks & (1 << i)))
1642 continue;
1643 if (info->hook_entry[i] == 0xFFFFFFFF) {
1644 duprintf("Invalid hook entry %u %u\n",
1645 i, hook_entries[i]);
1646 goto out_unlock;
1648 if (info->underflow[i] == 0xFFFFFFFF) {
1649 duprintf("Invalid underflow %u %u\n",
1650 i, underflows[i]);
1651 goto out_unlock;
1655 ret = -ENOMEM;
1656 newinfo = xt_alloc_table_info(size);
1657 if (!newinfo)
1658 goto out_unlock;
1660 newinfo->number = number;
1661 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1662 newinfo->hook_entry[i] = info->hook_entry[i];
1663 newinfo->underflow[i] = info->underflow[i];
1665 entry1 = newinfo->entries[raw_smp_processor_id()];
1666 pos = entry1;
1667 size = total_size;
1668 ret = IPT_ENTRY_ITERATE(entry0, total_size,
1669 compat_copy_entry_from_user, &pos, &size,
1670 name, newinfo, entry1);
1671 compat_flush_offsets();
1672 xt_compat_unlock(AF_INET);
1673 if (ret)
1674 goto free_newinfo;
1676 ret = -ELOOP;
1677 if (!mark_source_chains(newinfo, valid_hooks, entry1))
1678 goto free_newinfo;
1680 /* And one copy for every other CPU */
1681 for_each_possible_cpu(i)
1682 if (newinfo->entries[i] && newinfo->entries[i] != entry1)
1683 memcpy(newinfo->entries[i], entry1, newinfo->size);
1685 *pinfo = newinfo;
1686 *pentry0 = entry1;
1687 xt_free_table_info(info);
1688 return 0;
1690 free_newinfo:
1691 xt_free_table_info(newinfo);
1692 out:
1693 IPT_ENTRY_ITERATE(entry0, total_size, cleanup_entry, &j);
1694 return ret;
1695 out_unlock:
1696 compat_flush_offsets();
1697 xt_compat_unlock(AF_INET);
1698 goto out;
1701 static int
1702 compat_do_replace(void __user *user, unsigned int len)
1704 int ret;
1705 struct compat_ipt_replace tmp;
1706 struct xt_table_info *newinfo;
1707 void *loc_cpu_entry;
1709 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1710 return -EFAULT;
1712 /* Hack: Causes ipchains to give correct error msg --RR */
1713 if (len != sizeof(tmp) + tmp.size)
1714 return -ENOPROTOOPT;
1716 /* overflow check */
1717 if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
1718 SMP_CACHE_BYTES)
1719 return -ENOMEM;
1720 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1721 return -ENOMEM;
1723 newinfo = xt_alloc_table_info(tmp.size);
1724 if (!newinfo)
1725 return -ENOMEM;
1727 /* choose the copy that is our node/cpu */
1728 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1729 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1730 tmp.size) != 0) {
1731 ret = -EFAULT;
1732 goto free_newinfo;
1735 ret = translate_compat_table(tmp.name, tmp.valid_hooks,
1736 &newinfo, &loc_cpu_entry, tmp.size,
1737 tmp.num_entries, tmp.hook_entry, tmp.underflow);
1738 if (ret != 0)
1739 goto free_newinfo;
1741 duprintf("compat_do_replace: Translated table\n");
1743 ret = __do_replace(tmp.name, tmp.valid_hooks,
1744 newinfo, tmp.num_counters,
1745 compat_ptr(tmp.counters));
1746 if (ret)
1747 goto free_newinfo_untrans;
1748 return 0;
1750 free_newinfo_untrans:
1751 IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1752 free_newinfo:
1753 xt_free_table_info(newinfo);
1754 return ret;
1757 static int
1758 compat_do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user,
1759 unsigned int len)
1761 int ret;
1763 if (!capable(CAP_NET_ADMIN))
1764 return -EPERM;
1766 switch (cmd) {
1767 case IPT_SO_SET_REPLACE:
1768 ret = compat_do_replace(user, len);
1769 break;
1771 case IPT_SO_SET_ADD_COUNTERS:
1772 ret = do_add_counters(user, len, 1);
1773 break;
1775 default:
1776 duprintf("do_ipt_set_ctl: unknown request %i\n", cmd);
1777 ret = -EINVAL;
1780 return ret;
1783 struct compat_ipt_get_entries
1785 char name[IPT_TABLE_MAXNAMELEN];
1786 compat_uint_t size;
1787 struct compat_ipt_entry entrytable[0];
1790 static int compat_copy_entries_to_user(unsigned int total_size,
1791 struct ipt_table *table, void __user *userptr)
1793 unsigned int off, num;
1794 struct compat_ipt_entry e;
1795 struct xt_counters *counters;
1796 struct xt_table_info *private = table->private;
1797 void __user *pos;
1798 unsigned int size;
1799 int ret = 0;
1800 void *loc_cpu_entry;
1802 counters = alloc_counters(table);
1803 if (IS_ERR(counters))
1804 return PTR_ERR(counters);
1806 /* choose the copy that is on our node/cpu, ...
1807 * This choice is lazy (because current thread is
1808 * allowed to migrate to another cpu)
1810 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1811 pos = userptr;
1812 size = total_size;
1813 ret = IPT_ENTRY_ITERATE(loc_cpu_entry, total_size,
1814 compat_copy_entry_to_user, &pos, &size);
1815 if (ret)
1816 goto free_counters;
1818 /* ... then go back and fix counters and names */
1819 for (off = 0, num = 0; off < size; off += e.next_offset, num++) {
1820 unsigned int i;
1821 struct ipt_entry_match m;
1822 struct ipt_entry_target t;
1824 ret = -EFAULT;
1825 if (copy_from_user(&e, userptr + off,
1826 sizeof(struct compat_ipt_entry)))
1827 goto free_counters;
1828 if (copy_to_user(userptr + off +
1829 offsetof(struct compat_ipt_entry, counters),
1830 &counters[num], sizeof(counters[num])))
1831 goto free_counters;
1833 for (i = sizeof(struct compat_ipt_entry);
1834 i < e.target_offset; i += m.u.match_size) {
1835 if (copy_from_user(&m, userptr + off + i,
1836 sizeof(struct ipt_entry_match)))
1837 goto free_counters;
1838 if (copy_to_user(userptr + off + i +
1839 offsetof(struct ipt_entry_match, u.user.name),
1840 m.u.kernel.match->name,
1841 strlen(m.u.kernel.match->name) + 1))
1842 goto free_counters;
1845 if (copy_from_user(&t, userptr + off + e.target_offset,
1846 sizeof(struct ipt_entry_target)))
1847 goto free_counters;
1848 if (copy_to_user(userptr + off + e.target_offset +
1849 offsetof(struct ipt_entry_target, u.user.name),
1850 t.u.kernel.target->name,
1851 strlen(t.u.kernel.target->name) + 1))
1852 goto free_counters;
1854 ret = 0;
1855 free_counters:
1856 vfree(counters);
1857 return ret;
1860 static int
1861 compat_get_entries(struct compat_ipt_get_entries __user *uptr, int *len)
1863 int ret;
1864 struct compat_ipt_get_entries get;
1865 struct ipt_table *t;
1868 if (*len < sizeof(get)) {
1869 duprintf("compat_get_entries: %u < %u\n",
1870 *len, (unsigned int)sizeof(get));
1871 return -EINVAL;
1874 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1875 return -EFAULT;
1877 if (*len != sizeof(struct compat_ipt_get_entries) + get.size) {
1878 duprintf("compat_get_entries: %u != %u\n", *len,
1879 (unsigned int)(sizeof(struct compat_ipt_get_entries) +
1880 get.size));
1881 return -EINVAL;
1884 xt_compat_lock(AF_INET);
1885 t = xt_find_table_lock(AF_INET, get.name);
1886 if (t && !IS_ERR(t)) {
1887 struct xt_table_info *private = t->private;
1888 struct xt_table_info info;
1889 duprintf("t->private->number = %u\n",
1890 private->number);
1891 ret = compat_table_info(private, &info);
1892 if (!ret && get.size == info.size) {
1893 ret = compat_copy_entries_to_user(private->size,
1894 t, uptr->entrytable);
1895 } else if (!ret) {
1896 duprintf("compat_get_entries: I've got %u not %u!\n",
1897 private->size,
1898 get.size);
1899 ret = -EINVAL;
1901 compat_flush_offsets();
1902 module_put(t->me);
1903 xt_table_unlock(t);
1904 } else
1905 ret = t ? PTR_ERR(t) : -ENOENT;
1907 xt_compat_unlock(AF_INET);
1908 return ret;
1911 static int do_ipt_get_ctl(struct sock *, int, void __user *, int *);
1913 static int
1914 compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1916 int ret;
1918 if (!capable(CAP_NET_ADMIN))
1919 return -EPERM;
1921 switch (cmd) {
1922 case IPT_SO_GET_INFO:
1923 ret = get_info(user, len, 1);
1924 break;
1925 case IPT_SO_GET_ENTRIES:
1926 ret = compat_get_entries(user, len);
1927 break;
1928 default:
1929 ret = do_ipt_get_ctl(sk, cmd, user, len);
1931 return ret;
1933 #endif
1935 static int
1936 do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1938 int ret;
1940 if (!capable(CAP_NET_ADMIN))
1941 return -EPERM;
1943 switch (cmd) {
1944 case IPT_SO_SET_REPLACE:
1945 ret = do_replace(user, len);
1946 break;
1948 case IPT_SO_SET_ADD_COUNTERS:
1949 ret = do_add_counters(user, len, 0);
1950 break;
1952 default:
1953 duprintf("do_ipt_set_ctl: unknown request %i\n", cmd);
1954 ret = -EINVAL;
1957 return ret;
1960 static int
1961 do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1963 int ret;
1965 if (!capable(CAP_NET_ADMIN))
1966 return -EPERM;
1968 switch (cmd) {
1969 case IPT_SO_GET_INFO:
1970 ret = get_info(user, len, 0);
1971 break;
1973 case IPT_SO_GET_ENTRIES:
1974 ret = get_entries(user, len);
1975 break;
1977 case IPT_SO_GET_REVISION_MATCH:
1978 case IPT_SO_GET_REVISION_TARGET: {
1979 struct ipt_get_revision rev;
1980 int target;
1982 if (*len != sizeof(rev)) {
1983 ret = -EINVAL;
1984 break;
1986 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
1987 ret = -EFAULT;
1988 break;
1991 if (cmd == IPT_SO_GET_REVISION_TARGET)
1992 target = 1;
1993 else
1994 target = 0;
1996 try_then_request_module(xt_find_revision(AF_INET, rev.name,
1997 rev.revision,
1998 target, &ret),
1999 "ipt_%s", rev.name);
2000 break;
2003 default:
2004 duprintf("do_ipt_get_ctl: unknown request %i\n", cmd);
2005 ret = -EINVAL;
2008 return ret;
2011 int ipt_register_table(struct xt_table *table, const struct ipt_replace *repl)
2013 int ret;
2014 struct xt_table_info *newinfo;
2015 static struct xt_table_info bootstrap
2016 = { 0, 0, 0, { 0 }, { 0 }, { } };
2017 void *loc_cpu_entry;
2019 newinfo = xt_alloc_table_info(repl->size);
2020 if (!newinfo)
2021 return -ENOMEM;
2023 /* choose the copy on our node/cpu
2024 * but dont care of preemption
2026 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
2027 memcpy(loc_cpu_entry, repl->entries, repl->size);
2029 ret = translate_table(table->name, table->valid_hooks,
2030 newinfo, loc_cpu_entry, repl->size,
2031 repl->num_entries,
2032 repl->hook_entry,
2033 repl->underflow);
2034 if (ret != 0) {
2035 xt_free_table_info(newinfo);
2036 return ret;
2039 ret = xt_register_table(table, &bootstrap, newinfo);
2040 if (ret != 0) {
2041 xt_free_table_info(newinfo);
2042 return ret;
2045 return 0;
2048 void ipt_unregister_table(struct ipt_table *table)
2050 struct xt_table_info *private;
2051 void *loc_cpu_entry;
2053 private = xt_unregister_table(table);
2055 /* Decrease module usage counts and free resources */
2056 loc_cpu_entry = private->entries[raw_smp_processor_id()];
2057 IPT_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
2058 xt_free_table_info(private);
2061 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
2062 static inline int
2063 icmp_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
2064 u_int8_t type, u_int8_t code,
2065 int invert)
2067 return ((test_type == 0xFF) || (type == test_type && code >= min_code && code <= max_code))
2068 ^ invert;
2071 static int
2072 icmp_match(const struct sk_buff *skb,
2073 const struct net_device *in,
2074 const struct net_device *out,
2075 const struct xt_match *match,
2076 const void *matchinfo,
2077 int offset,
2078 unsigned int protoff,
2079 int *hotdrop)
2081 struct icmphdr _icmph, *ic;
2082 const struct ipt_icmp *icmpinfo = matchinfo;
2084 /* Must not be a fragment. */
2085 if (offset)
2086 return 0;
2088 ic = skb_header_pointer(skb, protoff, sizeof(_icmph), &_icmph);
2089 if (ic == NULL) {
2090 /* We've been asked to examine this packet, and we
2091 * can't. Hence, no choice but to drop.
2093 duprintf("Dropping evil ICMP tinygram.\n");
2094 *hotdrop = 1;
2095 return 0;
2098 return icmp_type_code_match(icmpinfo->type,
2099 icmpinfo->code[0],
2100 icmpinfo->code[1],
2101 ic->type, ic->code,
2102 !!(icmpinfo->invflags&IPT_ICMP_INV));
2105 /* Called when user tries to insert an entry of this type. */
2106 static int
2107 icmp_checkentry(const char *tablename,
2108 const void *info,
2109 const struct xt_match *match,
2110 void *matchinfo,
2111 unsigned int hook_mask)
2113 const struct ipt_icmp *icmpinfo = matchinfo;
2115 /* Must specify no unknown invflags */
2116 return !(icmpinfo->invflags & ~IPT_ICMP_INV);
2119 /* The built-in targets: standard (NULL) and error. */
2120 static struct ipt_target ipt_standard_target = {
2121 .name = IPT_STANDARD_TARGET,
2122 .targetsize = sizeof(int),
2123 .family = AF_INET,
2124 #ifdef CONFIG_COMPAT
2125 .compatsize = sizeof(compat_int_t),
2126 .compat_from_user = compat_standard_from_user,
2127 .compat_to_user = compat_standard_to_user,
2128 #endif
2131 static struct ipt_target ipt_error_target = {
2132 .name = IPT_ERROR_TARGET,
2133 .target = ipt_error,
2134 .targetsize = IPT_FUNCTION_MAXNAMELEN,
2135 .family = AF_INET,
2138 static struct nf_sockopt_ops ipt_sockopts = {
2139 .pf = PF_INET,
2140 .set_optmin = IPT_BASE_CTL,
2141 .set_optmax = IPT_SO_SET_MAX+1,
2142 .set = do_ipt_set_ctl,
2143 #ifdef CONFIG_COMPAT
2144 .compat_set = compat_do_ipt_set_ctl,
2145 #endif
2146 .get_optmin = IPT_BASE_CTL,
2147 .get_optmax = IPT_SO_GET_MAX+1,
2148 .get = do_ipt_get_ctl,
2149 #ifdef CONFIG_COMPAT
2150 .compat_get = compat_do_ipt_get_ctl,
2151 #endif
2154 static struct ipt_match icmp_matchstruct = {
2155 .name = "icmp",
2156 .match = icmp_match,
2157 .matchsize = sizeof(struct ipt_icmp),
2158 .proto = IPPROTO_ICMP,
2159 .family = AF_INET,
2160 .checkentry = icmp_checkentry,
2163 static int __init ip_tables_init(void)
2165 int ret;
2167 ret = xt_proto_init(AF_INET);
2168 if (ret < 0)
2169 goto err1;
2171 /* Noone else will be downing sem now, so we won't sleep */
2172 ret = xt_register_target(&ipt_standard_target);
2173 if (ret < 0)
2174 goto err2;
2175 ret = xt_register_target(&ipt_error_target);
2176 if (ret < 0)
2177 goto err3;
2178 ret = xt_register_match(&icmp_matchstruct);
2179 if (ret < 0)
2180 goto err4;
2182 /* Register setsockopt */
2183 ret = nf_register_sockopt(&ipt_sockopts);
2184 if (ret < 0)
2185 goto err5;
2187 printk("ip_tables: (C) 2000-2006 Netfilter Core Team\n");
2188 return 0;
2190 err5:
2191 xt_unregister_match(&icmp_matchstruct);
2192 err4:
2193 xt_unregister_target(&ipt_error_target);
2194 err3:
2195 xt_unregister_target(&ipt_standard_target);
2196 err2:
2197 xt_proto_fini(AF_INET);
2198 err1:
2199 return ret;
2202 static void __exit ip_tables_fini(void)
2204 nf_unregister_sockopt(&ipt_sockopts);
2206 xt_unregister_match(&icmp_matchstruct);
2207 xt_unregister_target(&ipt_error_target);
2208 xt_unregister_target(&ipt_standard_target);
2210 xt_proto_fini(AF_INET);
2213 EXPORT_SYMBOL(ipt_register_table);
2214 EXPORT_SYMBOL(ipt_unregister_table);
2215 EXPORT_SYMBOL(ipt_do_table);
2216 module_init(ip_tables_init);
2217 module_exit(ip_tables_fini);