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