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