]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - net/ipv4/netfilter/ip_tables.c
[NETFILTER]: Introduce NF_INET_ hook values
[mirror_ubuntu-bionic-kernel.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
1093static int compat_calc_entry(struct ipt_entry *e, struct xt_table_info *info,
1094 void *base, struct xt_table_info *newinfo)
1095{
1096 struct ipt_entry_target *t;
e5b5ef7d 1097 unsigned int entry_offset;
2722971c
DM
1098 int off, i, ret;
1099
1100 off = 0;
1101 entry_offset = (void *)e - base;
1102 IPT_MATCH_ITERATE(e, compat_calc_match, &off);
1103 t = ipt_get_target(e);
9fa492cd 1104 off += xt_compat_target_offset(t->u.kernel.target);
2722971c
DM
1105 newinfo->size -= off;
1106 ret = compat_add_offset(entry_offset, off);
1107 if (ret)
1108 return ret;
1109
6e23ae2a 1110 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
2722971c
DM
1111 if (info->hook_entry[i] && (e < (struct ipt_entry *)
1112 (base + info->hook_entry[i])))
1113 newinfo->hook_entry[i] -= off;
1114 if (info->underflow[i] && (e < (struct ipt_entry *)
1115 (base + info->underflow[i])))
1116 newinfo->underflow[i] -= off;
1117 }
1118 return 0;
1119}
1120
1121static int compat_table_info(struct xt_table_info *info,
1122 struct xt_table_info *newinfo)
1123{
1124 void *loc_cpu_entry;
1125 int i;
1126
1127 if (!newinfo || !info)
1128 return -EINVAL;
1129
1130 memset(newinfo, 0, sizeof(struct xt_table_info));
1131 newinfo->size = info->size;
1132 newinfo->number = info->number;
6e23ae2a 1133 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
2722971c
DM
1134 newinfo->hook_entry[i] = info->hook_entry[i];
1135 newinfo->underflow[i] = info->underflow[i];
1136 }
1137 loc_cpu_entry = info->entries[raw_smp_processor_id()];
1138 return IPT_ENTRY_ITERATE(loc_cpu_entry, info->size,
1139 compat_calc_entry, info, loc_cpu_entry, newinfo);
1140}
1141#endif
1142
1143static int get_info(void __user *user, int *len, int compat)
1144{
1145 char name[IPT_TABLE_MAXNAMELEN];
e60a13e0 1146 struct xt_table *t;
2722971c
DM
1147 int ret;
1148
1149 if (*len != sizeof(struct ipt_getinfo)) {
1150 duprintf("length %u != %u\n", *len,
1151 (unsigned int)sizeof(struct ipt_getinfo));
1152 return -EINVAL;
1153 }
1154
1155 if (copy_from_user(name, user, sizeof(name)) != 0)
1156 return -EFAULT;
1157
1158 name[IPT_TABLE_MAXNAMELEN-1] = '\0';
1159#ifdef CONFIG_COMPAT
1160 if (compat)
1161 xt_compat_lock(AF_INET);
1162#endif
1163 t = try_then_request_module(xt_find_table_lock(AF_INET, name),
1164 "iptable_%s", name);
1165 if (t && !IS_ERR(t)) {
1166 struct ipt_getinfo info;
1167 struct xt_table_info *private = t->private;
1168
1169#ifdef CONFIG_COMPAT
1170 if (compat) {
1171 struct xt_table_info tmp;
1172 ret = compat_table_info(private, &tmp);
1173 compat_flush_offsets();
1174 private = &tmp;
1175 }
1176#endif
1177 info.valid_hooks = t->valid_hooks;
1178 memcpy(info.hook_entry, private->hook_entry,
1179 sizeof(info.hook_entry));
1180 memcpy(info.underflow, private->underflow,
1181 sizeof(info.underflow));
1182 info.num_entries = private->number;
1183 info.size = private->size;
1184 strcpy(info.name, name);
1185
1186 if (copy_to_user(user, &info, *len) != 0)
1187 ret = -EFAULT;
1188 else
1189 ret = 0;
1190
1191 xt_table_unlock(t);
1192 module_put(t->me);
1193 } else
1194 ret = t ? PTR_ERR(t) : -ENOENT;
1195#ifdef CONFIG_COMPAT
1196 if (compat)
1197 xt_compat_unlock(AF_INET);
1198#endif
1199 return ret;
1200}
1201
1202static int
1203get_entries(struct ipt_get_entries __user *uptr, int *len)
1204{
1205 int ret;
1206 struct ipt_get_entries get;
e60a13e0 1207 struct xt_table *t;
2722971c
DM
1208
1209 if (*len < sizeof(get)) {
1210 duprintf("get_entries: %u < %d\n", *len,
1211 (unsigned int)sizeof(get));
1212 return -EINVAL;
1213 }
1214 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1215 return -EFAULT;
1216 if (*len != sizeof(struct ipt_get_entries) + get.size) {
1217 duprintf("get_entries: %u != %u\n", *len,
1218 (unsigned int)(sizeof(struct ipt_get_entries) +
1219 get.size));
1220 return -EINVAL;
1221 }
1222
1223 t = xt_find_table_lock(AF_INET, get.name);
1224 if (t && !IS_ERR(t)) {
1225 struct xt_table_info *private = t->private;
1226 duprintf("t->private->number = %u\n",
1227 private->number);
1228 if (get.size == private->size)
1229 ret = copy_entries_to_user(private->size,
1230 t, uptr->entrytable);
1231 else {
1232 duprintf("get_entries: I've got %u not %u!\n",
1233 private->size,
1234 get.size);
1235 ret = -EINVAL;
1236 }
1237 module_put(t->me);
1238 xt_table_unlock(t);
1239 } else
1240 ret = t ? PTR_ERR(t) : -ENOENT;
1241
1242 return ret;
1243}
1244
1245static int
1246__do_replace(const char *name, unsigned int valid_hooks,
1247 struct xt_table_info *newinfo, unsigned int num_counters,
1248 void __user *counters_ptr)
1249{
1250 int ret;
e60a13e0 1251 struct xt_table *t;
2722971c
DM
1252 struct xt_table_info *oldinfo;
1253 struct xt_counters *counters;
1254 void *loc_cpu_old_entry;
1255
1256 ret = 0;
1257 counters = vmalloc(num_counters * sizeof(struct xt_counters));
1258 if (!counters) {
1259 ret = -ENOMEM;
1260 goto out;
1261 }
1262
1263 t = try_then_request_module(xt_find_table_lock(AF_INET, name),
1264 "iptable_%s", name);
1265 if (!t || IS_ERR(t)) {
1266 ret = t ? PTR_ERR(t) : -ENOENT;
1267 goto free_newinfo_counters_untrans;
1268 }
1269
1270 /* You lied! */
1271 if (valid_hooks != t->valid_hooks) {
1272 duprintf("Valid hook crap: %08X vs %08X\n",
1273 valid_hooks, t->valid_hooks);
1274 ret = -EINVAL;
1275 goto put_module;
1276 }
1277
1278 oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);
1279 if (!oldinfo)
1280 goto put_module;
1281
1282 /* Update module usage count based on number of rules */
1283 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1284 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1285 if ((oldinfo->number > oldinfo->initial_entries) ||
1286 (newinfo->number <= oldinfo->initial_entries))
1287 module_put(t->me);
1288 if ((oldinfo->number > oldinfo->initial_entries) &&
1289 (newinfo->number <= oldinfo->initial_entries))
1290 module_put(t->me);
1291
1292 /* Get the old counters. */
1293 get_counters(oldinfo, counters);
1294 /* Decrease module usage counts and free resource */
1295 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1296 IPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
1297 xt_free_table_info(oldinfo);
1298 if (copy_to_user(counters_ptr, counters,
1299 sizeof(struct xt_counters) * num_counters) != 0)
1300 ret = -EFAULT;
1301 vfree(counters);
1302 xt_table_unlock(t);
1303 return ret;
1304
1305 put_module:
1306 module_put(t->me);
1307 xt_table_unlock(t);
1308 free_newinfo_counters_untrans:
1309 vfree(counters);
1310 out:
1311 return ret;
1312}
1313
1314static int
1315do_replace(void __user *user, unsigned int len)
1316{
1317 int ret;
1318 struct ipt_replace tmp;
1319 struct xt_table_info *newinfo;
1320 void *loc_cpu_entry;
1321
1322 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1323 return -EFAULT;
1324
1325 /* Hack: Causes ipchains to give correct error msg --RR */
1326 if (len != sizeof(tmp) + tmp.size)
1327 return -ENOPROTOOPT;
1328
1329 /* overflow check */
1330 if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
1331 SMP_CACHE_BYTES)
1332 return -ENOMEM;
1333 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1334 return -ENOMEM;
1335
1336 newinfo = xt_alloc_table_info(tmp.size);
1337 if (!newinfo)
1338 return -ENOMEM;
1339
1340 /* choose the copy that is our node/cpu */
1341 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1342 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1343 tmp.size) != 0) {
1344 ret = -EFAULT;
1345 goto free_newinfo;
1346 }
1347
1348 ret = translate_table(tmp.name, tmp.valid_hooks,
1349 newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
1350 tmp.hook_entry, tmp.underflow);
1351 if (ret != 0)
1352 goto free_newinfo;
1353
1354 duprintf("ip_tables: Translated table\n");
1355
1356 ret = __do_replace(tmp.name, tmp.valid_hooks,
1357 newinfo, tmp.num_counters,
1358 tmp.counters);
1359 if (ret)
1360 goto free_newinfo_untrans;
1361 return 0;
1362
1363 free_newinfo_untrans:
1364 IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1365 free_newinfo:
1366 xt_free_table_info(newinfo);
1367 return ret;
1368}
1369
1370/* We're lazy, and add to the first CPU; overflow works its fey magic
1371 * and everything is OK. */
1372static inline int
1373add_counter_to_entry(struct ipt_entry *e,
1374 const struct xt_counters addme[],
1375 unsigned int *i)
1376{
1377#if 0
1378 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1379 *i,
1380 (long unsigned int)e->counters.pcnt,
1381 (long unsigned int)e->counters.bcnt,
1382 (long unsigned int)addme[*i].pcnt,
1383 (long unsigned int)addme[*i].bcnt);
1384#endif
1385
1386 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1387
1388 (*i)++;
1389 return 0;
1390}
1391
1392static int
1393do_add_counters(void __user *user, unsigned int len, int compat)
1394{
1395 unsigned int i;
1396 struct xt_counters_info tmp;
1397 struct xt_counters *paddc;
1398 unsigned int num_counters;
1399 char *name;
1400 int size;
1401 void *ptmp;
e60a13e0 1402 struct xt_table *t;
2722971c
DM
1403 struct xt_table_info *private;
1404 int ret = 0;
1405 void *loc_cpu_entry;
1406#ifdef CONFIG_COMPAT
1407 struct compat_xt_counters_info compat_tmp;
1408
1409 if (compat) {
1410 ptmp = &compat_tmp;
1411 size = sizeof(struct compat_xt_counters_info);
1412 } else
1413#endif
1414 {
1415 ptmp = &tmp;
1416 size = sizeof(struct xt_counters_info);
1417 }
1418
1419 if (copy_from_user(ptmp, user, size) != 0)
1420 return -EFAULT;
1421
1422#ifdef CONFIG_COMPAT
1423 if (compat) {
1424 num_counters = compat_tmp.num_counters;
1425 name = compat_tmp.name;
1426 } else
1427#endif
1428 {
1429 num_counters = tmp.num_counters;
1430 name = tmp.name;
1431 }
1432
1433 if (len != size + num_counters * sizeof(struct xt_counters))
1434 return -EINVAL;
1435
1436 paddc = vmalloc_node(len - size, numa_node_id());
1437 if (!paddc)
1438 return -ENOMEM;
1439
1440 if (copy_from_user(paddc, user + size, len - size) != 0) {
1441 ret = -EFAULT;
1442 goto free;
1443 }
1444
1445 t = xt_find_table_lock(AF_INET, name);
1446 if (!t || IS_ERR(t)) {
1447 ret = t ? PTR_ERR(t) : -ENOENT;
1448 goto free;
1449 }
1450
1451 write_lock_bh(&t->lock);
1452 private = t->private;
1453 if (private->number != num_counters) {
1454 ret = -EINVAL;
1455 goto unlock_up_free;
1456 }
1457
1458 i = 0;
1459 /* Choose the copy that is on our node */
1460 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1461 IPT_ENTRY_ITERATE(loc_cpu_entry,
1462 private->size,
1463 add_counter_to_entry,
1464 paddc,
1465 &i);
1466 unlock_up_free:
1467 write_unlock_bh(&t->lock);
1468 xt_table_unlock(t);
1469 module_put(t->me);
1470 free:
1471 vfree(paddc);
1472
1473 return ret;
1474}
1475
1476#ifdef CONFIG_COMPAT
1477struct compat_ipt_replace {
1478 char name[IPT_TABLE_MAXNAMELEN];
1479 u32 valid_hooks;
1480 u32 num_entries;
1481 u32 size;
6e23ae2a
PM
1482 u32 hook_entry[NF_INET_NUMHOOKS];
1483 u32 underflow[NF_INET_NUMHOOKS];
2722971c
DM
1484 u32 num_counters;
1485 compat_uptr_t counters; /* struct ipt_counters * */
1486 struct compat_ipt_entry entries[0];
1487};
1488
1489static inline int compat_copy_match_to_user(struct ipt_entry_match *m,
3e597c60 1490 void __user **dstptr, compat_uint_t *size)
2722971c 1491{
9fa492cd 1492 return xt_compat_match_to_user(m, dstptr, size);
2722971c
DM
1493}
1494
a18aa31b
PM
1495static int
1496compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr,
1497 compat_uint_t *size, struct xt_counters *counters,
1498 unsigned int *i)
2722971c 1499{
3e597c60 1500 struct ipt_entry_target *t;
2722971c
DM
1501 struct compat_ipt_entry __user *ce;
1502 u_int16_t target_offset, next_offset;
1503 compat_uint_t origsize;
1504 int ret;
1505
1506 ret = -EFAULT;
1507 origsize = *size;
1508 ce = (struct compat_ipt_entry __user *)*dstptr;
7800007c 1509 if (copy_to_user(ce, e, sizeof(struct ipt_entry)))
2722971c
DM
1510 goto out;
1511
a18aa31b
PM
1512 if (copy_to_user(&ce->counters, &counters[*i], sizeof(counters[*i])))
1513 goto out;
1514
2722971c
DM
1515 *dstptr += sizeof(struct compat_ipt_entry);
1516 ret = IPT_MATCH_ITERATE(e, compat_copy_match_to_user, dstptr, size);
1517 target_offset = e->target_offset - (origsize - *size);
1518 if (ret)
1519 goto out;
1520 t = ipt_get_target(e);
9fa492cd 1521 ret = xt_compat_target_to_user(t, dstptr, size);
2722971c
DM
1522 if (ret)
1523 goto out;
1524 ret = -EFAULT;
1525 next_offset = e->next_offset - (origsize - *size);
7800007c 1526 if (put_user(target_offset, &ce->target_offset))
2722971c 1527 goto out;
7800007c 1528 if (put_user(next_offset, &ce->next_offset))
2722971c 1529 goto out;
a18aa31b
PM
1530
1531 (*i)++;
2722971c
DM
1532 return 0;
1533out:
1534 return ret;
1535}
1536
1537static inline int
4c1b52bc 1538compat_find_calc_match(struct ipt_entry_match *m,
2722971c
DM
1539 const char *name,
1540 const struct ipt_ip *ip,
1541 unsigned int hookmask,
1542 int *size, int *i)
1543{
6709dbbb 1544 struct xt_match *match;
2722971c
DM
1545
1546 match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
1547 m->u.user.revision),
1548 "ipt_%s", m->u.user.name);
1549 if (IS_ERR(match) || !match) {
1550 duprintf("compat_check_calc_match: `%s' not found\n",
1551 m->u.user.name);
1552 return match ? PTR_ERR(match) : -ENOENT;
1553 }
1554 m->u.kernel.match = match;
9fa492cd 1555 *size += xt_compat_match_offset(match);
2722971c
DM
1556
1557 (*i)++;
1558 return 0;
1559}
1560
4c1b52bc
DM
1561static inline int
1562compat_release_match(struct ipt_entry_match *m, unsigned int *i)
1563{
1564 if (i && (*i)-- == 0)
1565 return 1;
1566
1567 module_put(m->u.kernel.match->me);
1568 return 0;
1569}
1570
1571static inline int
1572compat_release_entry(struct ipt_entry *e, unsigned int *i)
1573{
1574 struct ipt_entry_target *t;
1575
1576 if (i && (*i)-- == 0)
1577 return 1;
1578
1579 /* Cleanup all matches */
1580 IPT_MATCH_ITERATE(e, compat_release_match, NULL);
1581 t = ipt_get_target(e);
1582 module_put(t->u.kernel.target->me);
1583 return 0;
1584}
1585
2722971c
DM
1586static inline int
1587check_compat_entry_size_and_hooks(struct ipt_entry *e,
1588 struct xt_table_info *newinfo,
1589 unsigned int *size,
1590 unsigned char *base,
1591 unsigned char *limit,
1592 unsigned int *hook_entries,
1593 unsigned int *underflows,
1594 unsigned int *i,
1595 const char *name)
1596{
1597 struct ipt_entry_target *t;
6709dbbb 1598 struct xt_target *target;
e5b5ef7d 1599 unsigned int entry_offset;
2722971c
DM
1600 int ret, off, h, j;
1601
1602 duprintf("check_compat_entry_size_and_hooks %p\n", e);
1603 if ((unsigned long)e % __alignof__(struct compat_ipt_entry) != 0
1604 || (unsigned char *)e + sizeof(struct compat_ipt_entry) >= limit) {
1605 duprintf("Bad offset %p, limit = %p\n", e, limit);
1606 return -EINVAL;
1607 }
1608
1609 if (e->next_offset < sizeof(struct compat_ipt_entry) +
1610 sizeof(struct compat_xt_entry_target)) {
1611 duprintf("checking: element %p size %u\n",
1612 e, e->next_offset);
1613 return -EINVAL;
1614 }
1615
a96be246
DM
1616 ret = check_entry(e, name);
1617 if (ret)
1618 return ret;
590bdf7f 1619
2722971c
DM
1620 off = 0;
1621 entry_offset = (void *)e - (void *)base;
1622 j = 0;
4c1b52bc 1623 ret = IPT_MATCH_ITERATE(e, compat_find_calc_match, name, &e->ip,
2722971c
DM
1624 e->comefrom, &off, &j);
1625 if (ret != 0)
4c1b52bc 1626 goto release_matches;
2722971c
DM
1627
1628 t = ipt_get_target(e);
1629 target = try_then_request_module(xt_find_target(AF_INET,
1630 t->u.user.name,
1631 t->u.user.revision),
1632 "ipt_%s", t->u.user.name);
1633 if (IS_ERR(target) || !target) {
a96be246
DM
1634 duprintf("check_compat_entry_size_and_hooks: `%s' not found\n",
1635 t->u.user.name);
2722971c 1636 ret = target ? PTR_ERR(target) : -ENOENT;
4c1b52bc 1637 goto release_matches;
2722971c
DM
1638 }
1639 t->u.kernel.target = target;
1640
9fa492cd 1641 off += xt_compat_target_offset(target);
2722971c
DM
1642 *size += off;
1643 ret = compat_add_offset(entry_offset, off);
1644 if (ret)
1645 goto out;
1646
1647 /* Check hooks & underflows */
6e23ae2a 1648 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
2722971c
DM
1649 if ((unsigned char *)e - base == hook_entries[h])
1650 newinfo->hook_entry[h] = hook_entries[h];
1651 if ((unsigned char *)e - base == underflows[h])
1652 newinfo->underflow[h] = underflows[h];
1653 }
1654
1655 /* Clear counters and comefrom */
1656 e->counters = ((struct ipt_counters) { 0, 0 });
1657 e->comefrom = 0;
1658
1659 (*i)++;
1660 return 0;
bec71b16 1661
2722971c 1662out:
bec71b16 1663 module_put(t->u.kernel.target->me);
4c1b52bc
DM
1664release_matches:
1665 IPT_MATCH_ITERATE(e, compat_release_match, &j);
2722971c
DM
1666 return ret;
1667}
1668
1669static inline int compat_copy_match_from_user(struct ipt_entry_match *m,
1670 void **dstptr, compat_uint_t *size, const char *name,
920b868a 1671 const struct ipt_ip *ip, unsigned int hookmask)
2722971c 1672{
9fa492cd 1673 xt_compat_match_from_user(m, dstptr, size);
f6677f43 1674 return 0;
2722971c
DM
1675}
1676
1677static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
1678 unsigned int *size, const char *name,
1679 struct xt_table_info *newinfo, unsigned char *base)
1680{
1681 struct ipt_entry_target *t;
6709dbbb 1682 struct xt_target *target;
2722971c
DM
1683 struct ipt_entry *de;
1684 unsigned int origsize;
920b868a 1685 int ret, h;
2722971c
DM
1686
1687 ret = 0;
1688 origsize = *size;
1689 de = (struct ipt_entry *)*dstptr;
1690 memcpy(de, e, sizeof(struct ipt_entry));
1691
1692 *dstptr += sizeof(struct compat_ipt_entry);
1693 ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size,
920b868a 1694 name, &de->ip, de->comefrom);
2722971c 1695 if (ret)
f6677f43 1696 return ret;
2722971c
DM
1697 de->target_offset = e->target_offset - (origsize - *size);
1698 t = ipt_get_target(e);
1699 target = t->u.kernel.target;
9fa492cd 1700 xt_compat_target_from_user(t, dstptr, size);
2722971c
DM
1701
1702 de->next_offset = e->next_offset - (origsize - *size);
6e23ae2a 1703 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
2722971c
DM
1704 if ((unsigned char *)de - base < newinfo->hook_entry[h])
1705 newinfo->hook_entry[h] -= origsize - *size;
1706 if ((unsigned char *)de - base < newinfo->underflow[h])
1707 newinfo->underflow[h] -= origsize - *size;
1708 }
f6677f43
DM
1709 return ret;
1710}
1711
4c1b52bc
DM
1712static inline int compat_check_entry(struct ipt_entry *e, const char *name,
1713 unsigned int *i)
f6677f43 1714{
4c1b52bc 1715 int j, ret;
f6677f43 1716
4c1b52bc
DM
1717 j = 0;
1718 ret = IPT_MATCH_ITERATE(e, check_match, name, &e->ip, e->comefrom, &j);
f6677f43 1719 if (ret)
4c1b52bc
DM
1720 goto cleanup_matches;
1721
1722 ret = check_target(e, name);
1723 if (ret)
1724 goto cleanup_matches;
f6677f43 1725
4c1b52bc
DM
1726 (*i)++;
1727 return 0;
1728
1729 cleanup_matches:
1730 IPT_MATCH_ITERATE(e, cleanup_match, &j);
1731 return ret;
f6677f43
DM
1732}
1733
1da177e4 1734static int
2722971c
DM
1735translate_compat_table(const char *name,
1736 unsigned int valid_hooks,
1737 struct xt_table_info **pinfo,
1738 void **pentry0,
1739 unsigned int total_size,
1740 unsigned int number,
1741 unsigned int *hook_entries,
1742 unsigned int *underflows)
1da177e4 1743{
920b868a 1744 unsigned int i, j;
2722971c
DM
1745 struct xt_table_info *newinfo, *info;
1746 void *pos, *entry0, *entry1;
1747 unsigned int size;
1da177e4 1748 int ret;
1da177e4 1749
2722971c
DM
1750 info = *pinfo;
1751 entry0 = *pentry0;
1752 size = total_size;
1753 info->number = number;
1754
1755 /* Init all hooks to impossible value. */
6e23ae2a 1756 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
2722971c
DM
1757 info->hook_entry[i] = 0xFFFFFFFF;
1758 info->underflow[i] = 0xFFFFFFFF;
1759 }
1760
1761 duprintf("translate_compat_table: size %u\n", info->size);
920b868a 1762 j = 0;
2722971c
DM
1763 xt_compat_lock(AF_INET);
1764 /* Walk through entries, checking offsets. */
1765 ret = IPT_ENTRY_ITERATE(entry0, total_size,
1766 check_compat_entry_size_and_hooks,
1767 info, &size, entry0,
1768 entry0 + total_size,
920b868a 1769 hook_entries, underflows, &j, name);
2722971c
DM
1770 if (ret != 0)
1771 goto out_unlock;
1772
1773 ret = -EINVAL;
920b868a 1774 if (j != number) {
2722971c 1775 duprintf("translate_compat_table: %u not %u entries\n",
920b868a 1776 j, number);
2722971c
DM
1777 goto out_unlock;
1778 }
1779
1780 /* Check hooks all assigned */
6e23ae2a 1781 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
2722971c
DM
1782 /* Only hooks which are valid */
1783 if (!(valid_hooks & (1 << i)))
1784 continue;
1785 if (info->hook_entry[i] == 0xFFFFFFFF) {
1786 duprintf("Invalid hook entry %u %u\n",
1787 i, hook_entries[i]);
1788 goto out_unlock;
1da177e4 1789 }
2722971c
DM
1790 if (info->underflow[i] == 0xFFFFFFFF) {
1791 duprintf("Invalid underflow %u %u\n",
1792 i, underflows[i]);
1793 goto out_unlock;
1794 }
1795 }
1796
1797 ret = -ENOMEM;
1798 newinfo = xt_alloc_table_info(size);
1799 if (!newinfo)
1800 goto out_unlock;
1801
1802 newinfo->number = number;
6e23ae2a 1803 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
2722971c
DM
1804 newinfo->hook_entry[i] = info->hook_entry[i];
1805 newinfo->underflow[i] = info->underflow[i];
1806 }
1807 entry1 = newinfo->entries[raw_smp_processor_id()];
1808 pos = entry1;
1809 size = total_size;
1810 ret = IPT_ENTRY_ITERATE(entry0, total_size,
1811 compat_copy_entry_from_user, &pos, &size,
1812 name, newinfo, entry1);
1813 compat_flush_offsets();
1814 xt_compat_unlock(AF_INET);
1815 if (ret)
1816 goto free_newinfo;
1817
1818 ret = -ELOOP;
1819 if (!mark_source_chains(newinfo, valid_hooks, entry1))
1820 goto free_newinfo;
1821
4c1b52bc 1822 i = 0;
f6677f43 1823 ret = IPT_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry,
4c1b52bc
DM
1824 name, &i);
1825 if (ret) {
1826 j -= i;
1827 IPT_ENTRY_ITERATE_CONTINUE(entry1, newinfo->size, i,
1828 compat_release_entry, &j);
1829 IPT_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, &i);
1830 xt_free_table_info(newinfo);
1831 return ret;
1832 }
f6677f43 1833
2722971c 1834 /* And one copy for every other CPU */
fb1bb34d 1835 for_each_possible_cpu(i)
2722971c
DM
1836 if (newinfo->entries[i] && newinfo->entries[i] != entry1)
1837 memcpy(newinfo->entries[i], entry1, newinfo->size);
1838
1839 *pinfo = newinfo;
1840 *pentry0 = entry1;
1841 xt_free_table_info(info);
1842 return 0;
1da177e4 1843
2722971c
DM
1844free_newinfo:
1845 xt_free_table_info(newinfo);
1846out:
4c1b52bc 1847 IPT_ENTRY_ITERATE(entry0, total_size, compat_release_entry, &j);
1da177e4 1848 return ret;
2722971c 1849out_unlock:
ef4512e7 1850 compat_flush_offsets();
2722971c
DM
1851 xt_compat_unlock(AF_INET);
1852 goto out;
1da177e4
LT
1853}
1854
1855static int
2722971c 1856compat_do_replace(void __user *user, unsigned int len)
1da177e4
LT
1857{
1858 int ret;
2722971c
DM
1859 struct compat_ipt_replace tmp;
1860 struct xt_table_info *newinfo;
1861 void *loc_cpu_entry;
1da177e4
LT
1862
1863 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1864 return -EFAULT;
1865
1866 /* Hack: Causes ipchains to give correct error msg --RR */
1867 if (len != sizeof(tmp) + tmp.size)
1868 return -ENOPROTOOPT;
1869
ee4bb818
KK
1870 /* overflow check */
1871 if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
1872 SMP_CACHE_BYTES)
1873 return -ENOMEM;
1874 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1875 return -ENOMEM;
1876
2e4e6a17 1877 newinfo = xt_alloc_table_info(tmp.size);
1da177e4
LT
1878 if (!newinfo)
1879 return -ENOMEM;
1880
31836064
ED
1881 /* choose the copy that is our node/cpu */
1882 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1883 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1da177e4
LT
1884 tmp.size) != 0) {
1885 ret = -EFAULT;
1886 goto free_newinfo;
1887 }
1888
2722971c
DM
1889 ret = translate_compat_table(tmp.name, tmp.valid_hooks,
1890 &newinfo, &loc_cpu_entry, tmp.size,
1891 tmp.num_entries, tmp.hook_entry, tmp.underflow);
1892 if (ret != 0)
1da177e4 1893 goto free_newinfo;
1da177e4 1894
2722971c 1895 duprintf("compat_do_replace: Translated table\n");
1da177e4 1896
2722971c
DM
1897 ret = __do_replace(tmp.name, tmp.valid_hooks,
1898 newinfo, tmp.num_counters,
1899 compat_ptr(tmp.counters));
1900 if (ret)
1901 goto free_newinfo_untrans;
1902 return 0;
1da177e4 1903
2722971c
DM
1904 free_newinfo_untrans:
1905 IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1906 free_newinfo:
1907 xt_free_table_info(newinfo);
1908 return ret;
1909}
1da177e4 1910
2722971c
DM
1911static int
1912compat_do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user,
1913 unsigned int len)
1914{
1915 int ret;
1da177e4 1916
2722971c
DM
1917 if (!capable(CAP_NET_ADMIN))
1918 return -EPERM;
1da177e4 1919
2722971c
DM
1920 switch (cmd) {
1921 case IPT_SO_SET_REPLACE:
1922 ret = compat_do_replace(user, len);
1923 break;
1da177e4 1924
2722971c
DM
1925 case IPT_SO_SET_ADD_COUNTERS:
1926 ret = do_add_counters(user, len, 1);
1927 break;
1928
1929 default:
1930 duprintf("do_ipt_set_ctl: unknown request %i\n", cmd);
1931 ret = -EINVAL;
1932 }
1da177e4 1933
1da177e4
LT
1934 return ret;
1935}
1936
2722971c 1937struct compat_ipt_get_entries
1da177e4 1938{
2722971c
DM
1939 char name[IPT_TABLE_MAXNAMELEN];
1940 compat_uint_t size;
1941 struct compat_ipt_entry entrytable[0];
1942};
1da177e4 1943
2722971c 1944static int compat_copy_entries_to_user(unsigned int total_size,
e60a13e0 1945 struct xt_table *table, void __user *userptr)
2722971c 1946{
2722971c
DM
1947 struct xt_counters *counters;
1948 struct xt_table_info *private = table->private;
1949 void __user *pos;
1950 unsigned int size;
1951 int ret = 0;
1952 void *loc_cpu_entry;
a18aa31b 1953 unsigned int i = 0;
1da177e4 1954
2722971c
DM
1955 counters = alloc_counters(table);
1956 if (IS_ERR(counters))
1957 return PTR_ERR(counters);
1958
1959 /* choose the copy that is on our node/cpu, ...
1960 * This choice is lazy (because current thread is
1961 * allowed to migrate to another cpu)
1962 */
1963 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1964 pos = userptr;
1965 size = total_size;
1966 ret = IPT_ENTRY_ITERATE(loc_cpu_entry, total_size,
a18aa31b
PM
1967 compat_copy_entry_to_user,
1968 &pos, &size, counters, &i);
2722971c 1969
2722971c
DM
1970 vfree(counters);
1971 return ret;
1da177e4
LT
1972}
1973
1974static int
2722971c 1975compat_get_entries(struct compat_ipt_get_entries __user *uptr, int *len)
1da177e4 1976{
2722971c
DM
1977 int ret;
1978 struct compat_ipt_get_entries get;
e60a13e0 1979 struct xt_table *t;
1da177e4 1980
1da177e4 1981
2722971c
DM
1982 if (*len < sizeof(get)) {
1983 duprintf("compat_get_entries: %u < %u\n",
1984 *len, (unsigned int)sizeof(get));
1da177e4 1985 return -EINVAL;
2722971c 1986 }
1da177e4 1987
2722971c
DM
1988 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1989 return -EFAULT;
1da177e4 1990
2722971c
DM
1991 if (*len != sizeof(struct compat_ipt_get_entries) + get.size) {
1992 duprintf("compat_get_entries: %u != %u\n", *len,
1993 (unsigned int)(sizeof(struct compat_ipt_get_entries) +
1994 get.size));
1995 return -EINVAL;
1da177e4
LT
1996 }
1997
2722971c
DM
1998 xt_compat_lock(AF_INET);
1999 t = xt_find_table_lock(AF_INET, get.name);
2000 if (t && !IS_ERR(t)) {
2001 struct xt_table_info *private = t->private;
2002 struct xt_table_info info;
2003 duprintf("t->private->number = %u\n",
2004 private->number);
2005 ret = compat_table_info(private, &info);
2006 if (!ret && get.size == info.size) {
2007 ret = compat_copy_entries_to_user(private->size,
2008 t, uptr->entrytable);
2009 } else if (!ret) {
2010 duprintf("compat_get_entries: I've got %u not %u!\n",
2011 private->size,
2012 get.size);
2013 ret = -EINVAL;
2014 }
2015 compat_flush_offsets();
2016 module_put(t->me);
2017 xt_table_unlock(t);
2018 } else
1da177e4 2019 ret = t ? PTR_ERR(t) : -ENOENT;
1da177e4 2020
2722971c
DM
2021 xt_compat_unlock(AF_INET);
2022 return ret;
2023}
1da177e4 2024
79030ed0
PM
2025static int do_ipt_get_ctl(struct sock *, int, void __user *, int *);
2026
2722971c
DM
2027static int
2028compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
2029{
2030 int ret;
1da177e4 2031
82fac054
BS
2032 if (!capable(CAP_NET_ADMIN))
2033 return -EPERM;
2034
2722971c
DM
2035 switch (cmd) {
2036 case IPT_SO_GET_INFO:
2037 ret = get_info(user, len, 1);
2038 break;
2039 case IPT_SO_GET_ENTRIES:
2040 ret = compat_get_entries(user, len);
2041 break;
2042 default:
79030ed0 2043 ret = do_ipt_get_ctl(sk, cmd, user, len);
2722971c 2044 }
1da177e4
LT
2045 return ret;
2046}
2722971c 2047#endif
1da177e4
LT
2048
2049static int
2050do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
2051{
2052 int ret;
2053
2054 if (!capable(CAP_NET_ADMIN))
2055 return -EPERM;
2056
2057 switch (cmd) {
2058 case IPT_SO_SET_REPLACE:
2059 ret = do_replace(user, len);
2060 break;
2061
2062 case IPT_SO_SET_ADD_COUNTERS:
2722971c 2063 ret = do_add_counters(user, len, 0);
1da177e4
LT
2064 break;
2065
2066 default:
2067 duprintf("do_ipt_set_ctl: unknown request %i\n", cmd);
2068 ret = -EINVAL;
2069 }
2070
2071 return ret;
2072}
2073
2074static int
2075do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
2076{
2077 int ret;
2078
2079 if (!capable(CAP_NET_ADMIN))
2080 return -EPERM;
2081
2082 switch (cmd) {
2722971c
DM
2083 case IPT_SO_GET_INFO:
2084 ret = get_info(user, len, 0);
2085 break;
1da177e4 2086
2722971c
DM
2087 case IPT_SO_GET_ENTRIES:
2088 ret = get_entries(user, len);
1da177e4 2089 break;
1da177e4
LT
2090
2091 case IPT_SO_GET_REVISION_MATCH:
2092 case IPT_SO_GET_REVISION_TARGET: {
2093 struct ipt_get_revision rev;
2e4e6a17 2094 int target;
1da177e4
LT
2095
2096 if (*len != sizeof(rev)) {
2097 ret = -EINVAL;
2098 break;
2099 }
2100 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
2101 ret = -EFAULT;
2102 break;
2103 }
2104
2105 if (cmd == IPT_SO_GET_REVISION_TARGET)
2e4e6a17 2106 target = 1;
1da177e4 2107 else
2e4e6a17 2108 target = 0;
1da177e4 2109
2e4e6a17
HW
2110 try_then_request_module(xt_find_revision(AF_INET, rev.name,
2111 rev.revision,
2112 target, &ret),
1da177e4
LT
2113 "ipt_%s", rev.name);
2114 break;
2115 }
2116
2117 default:
2118 duprintf("do_ipt_get_ctl: unknown request %i\n", cmd);
2119 ret = -EINVAL;
2120 }
2121
2122 return ret;
2123}
2124
2e4e6a17 2125int ipt_register_table(struct xt_table *table, const struct ipt_replace *repl)
1da177e4
LT
2126{
2127 int ret;
2e4e6a17
HW
2128 struct xt_table_info *newinfo;
2129 static struct xt_table_info bootstrap
1da177e4 2130 = { 0, 0, 0, { 0 }, { 0 }, { } };
31836064 2131 void *loc_cpu_entry;
1da177e4 2132
2e4e6a17 2133 newinfo = xt_alloc_table_info(repl->size);
1da177e4
LT
2134 if (!newinfo)
2135 return -ENOMEM;
2136
31836064
ED
2137 /* choose the copy on our node/cpu
2138 * but dont care of preemption
2139 */
2140 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
2141 memcpy(loc_cpu_entry, repl->entries, repl->size);
1da177e4
LT
2142
2143 ret = translate_table(table->name, table->valid_hooks,
31836064 2144 newinfo, loc_cpu_entry, repl->size,
1da177e4
LT
2145 repl->num_entries,
2146 repl->hook_entry,
2147 repl->underflow);
2148 if (ret != 0) {
2e4e6a17 2149 xt_free_table_info(newinfo);
1da177e4
LT
2150 return ret;
2151 }
2152
da298d3a
PM
2153 ret = xt_register_table(table, &bootstrap, newinfo);
2154 if (ret != 0) {
2e4e6a17 2155 xt_free_table_info(newinfo);
1da177e4
LT
2156 return ret;
2157 }
2158
2e4e6a17 2159 return 0;
1da177e4
LT
2160}
2161
e60a13e0 2162void ipt_unregister_table(struct xt_table *table)
1da177e4 2163{
2e4e6a17 2164 struct xt_table_info *private;
31836064
ED
2165 void *loc_cpu_entry;
2166
e905a9ed 2167 private = xt_unregister_table(table);
1da177e4
LT
2168
2169 /* Decrease module usage counts and free resources */
2e4e6a17
HW
2170 loc_cpu_entry = private->entries[raw_smp_processor_id()];
2171 IPT_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
2172 xt_free_table_info(private);
1da177e4
LT
2173}
2174
2175/* Returns 1 if the type and code is matched by the range, 0 otherwise */
1d93a9cb 2176static inline bool
1da177e4
LT
2177icmp_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
2178 u_int8_t type, u_int8_t code,
1d93a9cb 2179 bool invert)
1da177e4
LT
2180{
2181 return ((test_type == 0xFF) || (type == test_type && code >= min_code && code <= max_code))
2182 ^ invert;
2183}
2184
1d93a9cb 2185static bool
1da177e4
LT
2186icmp_match(const struct sk_buff *skb,
2187 const struct net_device *in,
2188 const struct net_device *out,
c4986734 2189 const struct xt_match *match,
1da177e4
LT
2190 const void *matchinfo,
2191 int offset,
2e4e6a17 2192 unsigned int protoff,
cff533ac 2193 bool *hotdrop)
1da177e4
LT
2194{
2195 struct icmphdr _icmph, *ic;
2196 const struct ipt_icmp *icmpinfo = matchinfo;
2197
2198 /* Must not be a fragment. */
2199 if (offset)
1d93a9cb 2200 return false;
1da177e4 2201
2e4e6a17 2202 ic = skb_header_pointer(skb, protoff, sizeof(_icmph), &_icmph);
1da177e4
LT
2203 if (ic == NULL) {
2204 /* We've been asked to examine this packet, and we
2205 * can't. Hence, no choice but to drop.
2206 */
2207 duprintf("Dropping evil ICMP tinygram.\n");
cff533ac 2208 *hotdrop = true;
1d93a9cb 2209 return false;
1da177e4
LT
2210 }
2211
2212 return icmp_type_code_match(icmpinfo->type,
2213 icmpinfo->code[0],
2214 icmpinfo->code[1],
2215 ic->type, ic->code,
2216 !!(icmpinfo->invflags&IPT_ICMP_INV));
2217}
2218
2219/* Called when user tries to insert an entry of this type. */
ccb79bdc 2220static bool
1da177e4 2221icmp_checkentry(const char *tablename,
2e4e6a17 2222 const void *info,
c4986734 2223 const struct xt_match *match,
1da177e4 2224 void *matchinfo,
1da177e4
LT
2225 unsigned int hook_mask)
2226{
2227 const struct ipt_icmp *icmpinfo = matchinfo;
2228
1d5cd909
PM
2229 /* Must specify no unknown invflags */
2230 return !(icmpinfo->invflags & ~IPT_ICMP_INV);
1da177e4
LT
2231}
2232
2233/* The built-in targets: standard (NULL) and error. */
9f15c530 2234static struct xt_target ipt_standard_target __read_mostly = {
1da177e4 2235 .name = IPT_STANDARD_TARGET,
1d5cd909 2236 .targetsize = sizeof(int),
a45049c5 2237 .family = AF_INET,
2722971c 2238#ifdef CONFIG_COMPAT
9fa492cd
PM
2239 .compatsize = sizeof(compat_int_t),
2240 .compat_from_user = compat_standard_from_user,
2241 .compat_to_user = compat_standard_to_user,
2722971c 2242#endif
1da177e4
LT
2243};
2244
9f15c530 2245static struct xt_target ipt_error_target __read_mostly = {
1da177e4
LT
2246 .name = IPT_ERROR_TARGET,
2247 .target = ipt_error,
1d5cd909 2248 .targetsize = IPT_FUNCTION_MAXNAMELEN,
a45049c5 2249 .family = AF_INET,
1da177e4
LT
2250};
2251
2252static struct nf_sockopt_ops ipt_sockopts = {
2253 .pf = PF_INET,
2254 .set_optmin = IPT_BASE_CTL,
2255 .set_optmax = IPT_SO_SET_MAX+1,
2256 .set = do_ipt_set_ctl,
2722971c
DM
2257#ifdef CONFIG_COMPAT
2258 .compat_set = compat_do_ipt_set_ctl,
2259#endif
1da177e4
LT
2260 .get_optmin = IPT_BASE_CTL,
2261 .get_optmax = IPT_SO_GET_MAX+1,
2262 .get = do_ipt_get_ctl,
2722971c
DM
2263#ifdef CONFIG_COMPAT
2264 .compat_get = compat_do_ipt_get_ctl,
2265#endif
16fcec35 2266 .owner = THIS_MODULE,
1da177e4
LT
2267};
2268
9f15c530 2269static struct xt_match icmp_matchstruct __read_mostly = {
1da177e4 2270 .name = "icmp",
1d5cd909
PM
2271 .match = icmp_match,
2272 .matchsize = sizeof(struct ipt_icmp),
2273 .proto = IPPROTO_ICMP,
a45049c5 2274 .family = AF_INET,
1d5cd909 2275 .checkentry = icmp_checkentry,
1da177e4
LT
2276};
2277
65b4b4e8 2278static int __init ip_tables_init(void)
1da177e4
LT
2279{
2280 int ret;
2281
0eff66e6
PM
2282 ret = xt_proto_init(AF_INET);
2283 if (ret < 0)
2284 goto err1;
2e4e6a17 2285
1da177e4 2286 /* Noone else will be downing sem now, so we won't sleep */
0eff66e6
PM
2287 ret = xt_register_target(&ipt_standard_target);
2288 if (ret < 0)
2289 goto err2;
2290 ret = xt_register_target(&ipt_error_target);
2291 if (ret < 0)
2292 goto err3;
2293 ret = xt_register_match(&icmp_matchstruct);
2294 if (ret < 0)
2295 goto err4;
1da177e4
LT
2296
2297 /* Register setsockopt */
2298 ret = nf_register_sockopt(&ipt_sockopts);
0eff66e6
PM
2299 if (ret < 0)
2300 goto err5;
1da177e4 2301
0236e667 2302 printk(KERN_INFO "ip_tables: (C) 2000-2006 Netfilter Core Team\n");
1da177e4 2303 return 0;
0eff66e6
PM
2304
2305err5:
2306 xt_unregister_match(&icmp_matchstruct);
2307err4:
2308 xt_unregister_target(&ipt_error_target);
2309err3:
2310 xt_unregister_target(&ipt_standard_target);
2311err2:
2312 xt_proto_fini(AF_INET);
2313err1:
2314 return ret;
1da177e4
LT
2315}
2316
65b4b4e8 2317static void __exit ip_tables_fini(void)
1da177e4
LT
2318{
2319 nf_unregister_sockopt(&ipt_sockopts);
2e4e6a17 2320
a45049c5
PNA
2321 xt_unregister_match(&icmp_matchstruct);
2322 xt_unregister_target(&ipt_error_target);
2323 xt_unregister_target(&ipt_standard_target);
2e4e6a17
HW
2324
2325 xt_proto_fini(AF_INET);
1da177e4
LT
2326}
2327
2328EXPORT_SYMBOL(ipt_register_table);
2329EXPORT_SYMBOL(ipt_unregister_table);
1da177e4 2330EXPORT_SYMBOL(ipt_do_table);
65b4b4e8
AM
2331module_init(ip_tables_init);
2332module_exit(ip_tables_fini);