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