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