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