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