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