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