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