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