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