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