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