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