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