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