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