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