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