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