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