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