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