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