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