1/* 2 * Packet matching code for ARP packets. 3 * 4 * Based heavily, if not almost entirely, upon ip_tables.c framework. 5 * 6 * Some ARP specific bits are: 7 * 8 * Copyright (C) 2002 David S. Miller (davem@redhat.com) 9 * Copyright (C) 2006-2009 Patrick McHardy <kaber@trash.net> 10 * 11 */ 12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 13#include <linux/kernel.h> 14#include <linux/skbuff.h> 15#include <linux/netdevice.h> 16#include <linux/capability.h> 17#include <linux/if_arp.h> 18#include <linux/kmod.h> 19#include <linux/vmalloc.h> 20#include <linux/proc_fs.h> 21#include <linux/module.h> 22#include <linux/init.h> 23#include <linux/mutex.h> 24#include <linux/err.h> 25#include <net/compat.h> 26#include <net/sock.h> 27#include <asm/uaccess.h> 28 29#include <linux/netfilter/x_tables.h> 30#include <linux/netfilter_arp/arp_tables.h> 31#include "../../netfilter/xt_repldata.h" 32 33MODULE_LICENSE("GPL"); 34MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); 35MODULE_DESCRIPTION("arptables core"); 36 37/*#define DEBUG_ARP_TABLES*/ 38/*#define DEBUG_ARP_TABLES_USER*/ 39 40#ifdef DEBUG_ARP_TABLES 41#define dprintf(format, args...) printk(format , ## args) 42#else 43#define dprintf(format, args...) 44#endif 45 46#ifdef DEBUG_ARP_TABLES_USER 47#define duprintf(format, args...) printk(format , ## args) 48#else 49#define duprintf(format, args...) 50#endif 51 52#ifdef CONFIG_NETFILTER_DEBUG 53#define ARP_NF_ASSERT(x) WARN_ON(!(x)) 54#else 55#define ARP_NF_ASSERT(x) 56#endif 57 58void *arpt_alloc_initial_table(const struct xt_table *info) 59{ 60 return xt_alloc_initial_table(arpt, ARPT); 61} 62EXPORT_SYMBOL_GPL(arpt_alloc_initial_table); 63 64static inline int arp_devaddr_compare(const struct arpt_devaddr_info *ap, 65 const char *hdr_addr, int len) 66{ 67 int i, ret; 68 69 if (len > ARPT_DEV_ADDR_LEN_MAX) 70 len = ARPT_DEV_ADDR_LEN_MAX; 71 72 ret = 0; 73 for (i = 0; i < len; i++) 74 ret |= (hdr_addr[i] ^ ap->addr[i]) & ap->mask[i]; 75 76 return ret != 0; 77} 78 79/* 80 * Unfortunately, _b and _mask are not aligned to an int (or long int) 81 * Some arches dont care, unrolling the loop is a win on them. 82 * For other arches, we only have a 16bit alignement. 83 */ 84static unsigned long ifname_compare(const char *_a, const char *_b, const char *_mask) 85{ 86#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 87 unsigned long ret = ifname_compare_aligned(_a, _b, _mask); 88#else 89 unsigned long ret = 0; 90 const u16 *a = (const u16 *)_a; 91 const u16 *b = (const u16 *)_b; 92 const u16 *mask = (const u16 *)_mask; 93 int i; 94 95 for (i = 0; i < IFNAMSIZ/sizeof(u16); i++) 96 ret |= (a[i] ^ b[i]) & mask[i]; 97#endif 98 return ret; 99} 100 101/* Returns whether packet matches rule or not. */ 102static inline int arp_packet_match(const struct arphdr *arphdr, 103 struct net_device *dev, 104 const char *indev, 105 const char *outdev, 106 const struct arpt_arp *arpinfo) 107{ 108 const char *arpptr = (char *)(arphdr + 1); 109 const char *src_devaddr, *tgt_devaddr; 110 __be32 src_ipaddr, tgt_ipaddr; 111 long ret; 112 113#define FWINV(bool, invflg) ((bool) ^ !!(arpinfo->invflags & (invflg))) 114 115 if (FWINV((arphdr->ar_op & arpinfo->arpop_mask) != arpinfo->arpop, 116 ARPT_INV_ARPOP)) { 117 dprintf("ARP operation field mismatch.\n"); 118 dprintf("ar_op: %04x info->arpop: %04x info->arpop_mask: %04x\n", 119 arphdr->ar_op, arpinfo->arpop, arpinfo->arpop_mask); 120 return 0; 121 } 122 123 if (FWINV((arphdr->ar_hrd & arpinfo->arhrd_mask) != arpinfo->arhrd, 124 ARPT_INV_ARPHRD)) { 125 dprintf("ARP hardware address format mismatch.\n"); 126 dprintf("ar_hrd: %04x info->arhrd: %04x info->arhrd_mask: %04x\n", 127 arphdr->ar_hrd, arpinfo->arhrd, arpinfo->arhrd_mask); 128 return 0; 129 } 130 131 if (FWINV((arphdr->ar_pro & arpinfo->arpro_mask) != arpinfo->arpro, 132 ARPT_INV_ARPPRO)) { 133 dprintf("ARP protocol address format mismatch.\n"); 134 dprintf("ar_pro: %04x info->arpro: %04x info->arpro_mask: %04x\n", 135 arphdr->ar_pro, arpinfo->arpro, arpinfo->arpro_mask); 136 return 0; 137 } 138 139 if (FWINV((arphdr->ar_hln & arpinfo->arhln_mask) != arpinfo->arhln, 140 ARPT_INV_ARPHLN)) { 141 dprintf("ARP hardware address length mismatch.\n"); 142 dprintf("ar_hln: %02x info->arhln: %02x info->arhln_mask: %02x\n", 143 arphdr->ar_hln, arpinfo->arhln, arpinfo->arhln_mask); 144 return 0; 145 } 146 147 src_devaddr = arpptr; 148 arpptr += dev->addr_len; 149 memcpy(&src_ipaddr, arpptr, sizeof(u32)); 150 arpptr += sizeof(u32); 151 tgt_devaddr = arpptr; 152 arpptr += dev->addr_len; 153 memcpy(&tgt_ipaddr, arpptr, sizeof(u32)); 154 155 if (FWINV(arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr, dev->addr_len), 156 ARPT_INV_SRCDEVADDR) || 157 FWINV(arp_devaddr_compare(&arpinfo->tgt_devaddr, tgt_devaddr, dev->addr_len), 158 ARPT_INV_TGTDEVADDR)) { 159 dprintf("Source or target device address mismatch.\n"); 160 161 return 0; 162 } 163 164 if (FWINV((src_ipaddr & arpinfo->smsk.s_addr) != arpinfo->src.s_addr, 165 ARPT_INV_SRCIP) || 166 FWINV(((tgt_ipaddr & arpinfo->tmsk.s_addr) != arpinfo->tgt.s_addr), 167 ARPT_INV_TGTIP)) { 168 dprintf("Source or target IP address mismatch.\n"); 169 170 dprintf("SRC: %pI4. Mask: %pI4. Target: %pI4.%s\n", 171 &src_ipaddr, 172 &arpinfo->smsk.s_addr, 173 &arpinfo->src.s_addr, 174 arpinfo->invflags & ARPT_INV_SRCIP ? " (INV)" : ""); 175 dprintf("TGT: %pI4 Mask: %pI4 Target: %pI4.%s\n", 176 &tgt_ipaddr, 177 &arpinfo->tmsk.s_addr, 178 &arpinfo->tgt.s_addr, 179 arpinfo->invflags & ARPT_INV_TGTIP ? " (INV)" : ""); 180 return 0; 181 } 182 183 /* Look for ifname matches. */ 184 ret = ifname_compare(indev, arpinfo->iniface, arpinfo->iniface_mask); 185 186 if (FWINV(ret != 0, ARPT_INV_VIA_IN)) { 187 dprintf("VIA in mismatch (%s vs %s).%s\n", 188 indev, arpinfo->iniface, 189 arpinfo->invflags&ARPT_INV_VIA_IN ?" (INV)":""); 190 return 0; 191 } 192 193 ret = ifname_compare(outdev, arpinfo->outiface, arpinfo->outiface_mask); 194 195 if (FWINV(ret != 0, ARPT_INV_VIA_OUT)) { 196 dprintf("VIA out mismatch (%s vs %s).%s\n", 197 outdev, arpinfo->outiface, 198 arpinfo->invflags&ARPT_INV_VIA_OUT ?" (INV)":""); 199 return 0; 200 } 201 202 return 1; 203#undef FWINV 204} 205 206static inline int arp_checkentry(const struct arpt_arp *arp) 207{ 208 if (arp->flags & ~ARPT_F_MASK) { 209 duprintf("Unknown flag bits set: %08X\n", 210 arp->flags & ~ARPT_F_MASK); 211 return 0; 212 } 213 if (arp->invflags & ~ARPT_INV_MASK) { 214 duprintf("Unknown invflag bits set: %08X\n", 215 arp->invflags & ~ARPT_INV_MASK); 216 return 0; 217 } 218 219 return 1; 220} 221 222static unsigned int 223arpt_error(struct sk_buff *skb, const struct xt_action_param *par) 224{ 225 net_err_ratelimited("arp_tables: error: '%s'\n", 226 (const char *)par->targinfo); 227 228 return NF_DROP; 229} 230 231static inline const struct xt_entry_target * 232arpt_get_target_c(const struct arpt_entry *e) 233{ 234 return arpt_get_target((struct arpt_entry *)e); 235} 236 237static inline struct arpt_entry * 238get_entry(const void *base, unsigned int offset) 239{ 240 return (struct arpt_entry *)(base + offset); 241} 242 243static inline __pure 244struct arpt_entry *arpt_next_entry(const struct arpt_entry *entry) 245{ 246 return (void *)entry + entry->next_offset; 247} 248 249unsigned int arpt_do_table(struct sk_buff *skb, 250 unsigned int hook, 251 const struct net_device *in, 252 const struct net_device *out, 253 struct xt_table *table) 254{ 255 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); 256 unsigned int verdict = NF_DROP; 257 const struct arphdr *arp; 258 struct arpt_entry *e, *back; 259 const char *indev, *outdev; 260 void *table_base; 261 const struct xt_table_info *private; 262 struct xt_action_param acpar; 263 unsigned int addend; 264 265 if (!pskb_may_pull(skb, arp_hdr_len(skb->dev))) 266 return NF_DROP; 267 268 indev = in ? in->name : nulldevname; 269 outdev = out ? out->name : nulldevname; 270 271 local_bh_disable(); 272 addend = xt_write_recseq_begin(); 273 private = table->private; 274 table_base = private->entries[smp_processor_id()]; 275 276 e = get_entry(table_base, private->hook_entry[hook]); 277 back = get_entry(table_base, private->underflow[hook]); 278 279 acpar.in = in; 280 acpar.out = out; 281 acpar.hooknum = hook; 282 acpar.family = NFPROTO_ARP; 283 acpar.hotdrop = false; 284 285 arp = arp_hdr(skb); 286 do { 287 const struct xt_entry_target *t; 288 289 if (!arp_packet_match(arp, skb->dev, indev, outdev, &e->arp)) { 290 e = arpt_next_entry(e); 291 continue; 292 } 293 294 ADD_COUNTER(e->counters, arp_hdr_len(skb->dev), 1); 295 296 t = arpt_get_target_c(e); 297 298 /* Standard target? */ 299 if (!t->u.kernel.target->target) { 300 int v; 301 302 v = ((struct xt_standard_target *)t)->verdict; 303 if (v < 0) { 304 /* Pop from stack? */ 305 if (v != XT_RETURN) { 306 verdict = (unsigned int)(-v) - 1; 307 break; 308 } 309 e = back; 310 back = get_entry(table_base, back->comefrom); 311 continue; 312 } 313 if (table_base + v 314 != arpt_next_entry(e)) { 315 /* Save old back ptr in next entry */ 316 struct arpt_entry *next = arpt_next_entry(e); 317 next->comefrom = (void *)back - table_base; 318 319 /* set back pointer to next entry */ 320 back = next; 321 } 322 323 e = get_entry(table_base, v); 324 continue; 325 } 326 327 /* Targets which reenter must return 328 * abs. verdicts 329 */ 330 acpar.target = t->u.kernel.target; 331 acpar.targinfo = t->data; 332 verdict = t->u.kernel.target->target(skb, &acpar); 333 334 /* Target might have changed stuff. */ 335 arp = arp_hdr(skb); 336 337 if (verdict == XT_CONTINUE) 338 e = arpt_next_entry(e); 339 else 340 /* Verdict */ 341 break; 342 } while (!acpar.hotdrop); 343 xt_write_recseq_end(addend); 344 local_bh_enable(); 345 346 if (acpar.hotdrop) 347 return NF_DROP; 348 else 349 return verdict; 350} 351 352/* All zeroes == unconditional rule. */ 353static inline bool unconditional(const struct arpt_arp *arp) 354{ 355 static const struct arpt_arp uncond; 356 357 return memcmp(arp, &uncond, sizeof(uncond)) == 0; 358} 359 360/* Figures out from what hook each rule can be called: returns 0 if 361 * there are loops. Puts hook bitmask in comefrom. 362 */ 363static int mark_source_chains(const struct xt_table_info *newinfo, 364 unsigned int valid_hooks, void *entry0) 365{ 366 unsigned int hook; 367 368 /* No recursion; use packet counter to save back ptrs (reset 369 * to 0 as we leave), and comefrom to save source hook bitmask. 370 */ 371 for (hook = 0; hook < NF_ARP_NUMHOOKS; hook++) { 372 unsigned int pos = newinfo->hook_entry[hook]; 373 struct arpt_entry *e 374 = (struct arpt_entry *)(entry0 + pos); 375 376 if (!(valid_hooks & (1 << hook))) 377 continue; 378 379 /* Set initial back pointer. */ 380 e->counters.pcnt = pos; 381 382 for (;;) { 383 const struct xt_standard_target *t 384 = (void *)arpt_get_target_c(e); 385 int visited = e->comefrom & (1 << hook); 386 387 if (e->comefrom & (1 << NF_ARP_NUMHOOKS)) { 388 pr_notice("arptables: loop hook %u pos %u %08X.\n", 389 hook, pos, e->comefrom); 390 return 0; 391 } 392 e->comefrom 393 |= ((1 << hook) | (1 << NF_ARP_NUMHOOKS)); 394 395 /* Unconditional return/END. */ 396 if ((e->target_offset == sizeof(struct arpt_entry) && 397 (strcmp(t->target.u.user.name, 398 XT_STANDARD_TARGET) == 0) && 399 t->verdict < 0 && unconditional(&e->arp)) || 400 visited) { 401 unsigned int oldpos, size; 402 403 if ((strcmp(t->target.u.user.name, 404 XT_STANDARD_TARGET) == 0) && 405 t->verdict < -NF_MAX_VERDICT - 1) { 406 duprintf("mark_source_chains: bad " 407 "negative verdict (%i)\n", 408 t->verdict); 409 return 0; 410 } 411 412 /* Return: backtrack through the last 413 * big jump. 414 */ 415 do { 416 e->comefrom ^= (1<<NF_ARP_NUMHOOKS); 417 oldpos = pos; 418 pos = e->counters.pcnt; 419 e->counters.pcnt = 0; 420 421 /* We're at the start. */ 422 if (pos == oldpos) 423 goto next; 424 425 e = (struct arpt_entry *) 426 (entry0 + pos); 427 } while (oldpos == pos + e->next_offset); 428 429 /* Move along one */ 430 size = e->next_offset; 431 e = (struct arpt_entry *) 432 (entry0 + pos + size); 433 e->counters.pcnt = pos; 434 pos += size; 435 } else { 436 int newpos = t->verdict; 437 438 if (strcmp(t->target.u.user.name, 439 XT_STANDARD_TARGET) == 0 && 440 newpos >= 0) { 441 if (newpos > newinfo->size - 442 sizeof(struct arpt_entry)) { 443 duprintf("mark_source_chains: " 444 "bad verdict (%i)\n", 445 newpos); 446 return 0; 447 } 448 449 /* This a jump; chase it. */ 450 duprintf("Jump rule %u -> %u\n", 451 pos, newpos); 452 } else { 453 /* ... this is a fallthru */ 454 newpos = pos + e->next_offset; 455 } 456 e = (struct arpt_entry *) 457 (entry0 + newpos); 458 e->counters.pcnt = pos; 459 pos = newpos; 460 } 461 } 462 next: 463 duprintf("Finished chain %u\n", hook); 464 } 465 return 1; 466} 467 468static inline int check_entry(const struct arpt_entry *e, const char *name) 469{ 470 const struct xt_entry_target *t; 471 472 if (!arp_checkentry(&e->arp)) { 473 duprintf("arp_tables: arp check failed %p %s.\n", e, name); 474 return -EINVAL; 475 } 476 477 if (e->target_offset + sizeof(struct xt_entry_target) > e->next_offset) 478 return -EINVAL; 479 480 t = arpt_get_target_c(e); 481 if (e->target_offset + t->u.target_size > e->next_offset) 482 return -EINVAL; 483 484 return 0; 485} 486 487static inline int check_target(struct arpt_entry *e, const char *name) 488{ 489 struct xt_entry_target *t = arpt_get_target(e); 490 int ret; 491 struct xt_tgchk_param par = { 492 .table = name, 493 .entryinfo = e, 494 .target = t->u.kernel.target, 495 .targinfo = t->data, 496 .hook_mask = e->comefrom, 497 .family = NFPROTO_ARP, 498 }; 499 500 ret = xt_check_target(&par, t->u.target_size - sizeof(*t), 0, false); 501 if (ret < 0) { 502 duprintf("arp_tables: check failed for `%s'.\n", 503 t->u.kernel.target->name); 504 return ret; 505 } 506 return 0; 507} 508 509static inline int 510find_check_entry(struct arpt_entry *e, const char *name, unsigned int size) 511{ 512 struct xt_entry_target *t; 513 struct xt_target *target; 514 int ret; 515 516 ret = check_entry(e, name); 517 if (ret) 518 return ret; 519 520 t = arpt_get_target(e); 521 target = xt_request_find_target(NFPROTO_ARP, t->u.user.name, 522 t->u.user.revision); 523 if (IS_ERR(target)) { 524 duprintf("find_check_entry: `%s' not found\n", t->u.user.name); 525 ret = PTR_ERR(target); 526 goto out; 527 } 528 t->u.kernel.target = target; 529 530 ret = check_target(e, name); 531 if (ret) 532 goto err; 533 return 0; 534err: 535 module_put(t->u.kernel.target->me); 536out: 537 return ret; 538} 539 540static bool check_underflow(const struct arpt_entry *e) 541{ 542 const struct xt_entry_target *t; 543 unsigned int verdict; 544 545 if (!unconditional(&e->arp)) 546 return false; 547 t = arpt_get_target_c(e); 548 if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0) 549 return false; 550 verdict = ((struct xt_standard_target *)t)->verdict; 551 verdict = -verdict - 1; 552 return verdict == NF_DROP || verdict == NF_ACCEPT; 553} 554 555static inline int check_entry_size_and_hooks(struct arpt_entry *e, 556 struct xt_table_info *newinfo, 557 const unsigned char *base, 558 const unsigned char *limit, 559 const unsigned int *hook_entries, 560 const unsigned int *underflows, 561 unsigned int valid_hooks) 562{ 563 unsigned int h; 564 565 if ((unsigned long)e % __alignof__(struct arpt_entry) != 0 || 566 (unsigned char *)e + sizeof(struct arpt_entry) >= limit) { 567 duprintf("Bad offset %p\n", e); 568 return -EINVAL; 569 } 570 571 if (e->next_offset 572 < sizeof(struct arpt_entry) + sizeof(struct xt_entry_target)) { 573 duprintf("checking: element %p size %u\n", 574 e, e->next_offset); 575 return -EINVAL; 576 } 577 578 /* Check hooks & underflows */ 579 for (h = 0; h < NF_ARP_NUMHOOKS; h++) { 580 if (!(valid_hooks & (1 << h))) 581 continue; 582 if ((unsigned char *)e - base == hook_entries[h]) 583 newinfo->hook_entry[h] = hook_entries[h]; 584 if ((unsigned char *)e - base == underflows[h]) { 585 if (!check_underflow(e)) { 586 pr_err("Underflows must be unconditional and " 587 "use the STANDARD target with " 588 "ACCEPT/DROP\n"); 589 return -EINVAL; 590 } 591 newinfo->underflow[h] = underflows[h]; 592 } 593 } 594 595 /* Clear counters and comefrom */ 596 e->counters = ((struct xt_counters) { 0, 0 }); 597 e->comefrom = 0; 598 return 0; 599} 600 601static inline void cleanup_entry(struct arpt_entry *e) 602{ 603 struct xt_tgdtor_param par; 604 struct xt_entry_target *t; 605 606 t = arpt_get_target(e); 607 par.target = t->u.kernel.target; 608 par.targinfo = t->data; 609 par.family = NFPROTO_ARP; 610 if (par.target->destroy != NULL) 611 par.target->destroy(&par); 612 module_put(par.target->me); 613} 614 615/* Checks and translates the user-supplied table segment (held in 616 * newinfo). 617 */ 618static int translate_table(struct xt_table_info *newinfo, void *entry0, 619 const struct arpt_replace *repl) 620{ 621 struct arpt_entry *iter; 622 unsigned int i; 623 int ret = 0; 624 625 newinfo->size = repl->size; 626 newinfo->number = repl->num_entries; 627 628 /* Init all hooks to impossible value. */ 629 for (i = 0; i < NF_ARP_NUMHOOKS; i++) { 630 newinfo->hook_entry[i] = 0xFFFFFFFF; 631 newinfo->underflow[i] = 0xFFFFFFFF; 632 } 633 634 duprintf("translate_table: size %u\n", newinfo->size); 635 i = 0; 636 637 /* Walk through entries, checking offsets. */ 638 xt_entry_foreach(iter, entry0, newinfo->size) { 639 ret = check_entry_size_and_hooks(iter, newinfo, entry0, 640 entry0 + repl->size, 641 repl->hook_entry, 642 repl->underflow, 643 repl->valid_hooks); 644 if (ret != 0) 645 break; 646 ++i; 647 if (strcmp(arpt_get_target(iter)->u.user.name, 648 XT_ERROR_TARGET) == 0) 649 ++newinfo->stacksize; 650 } 651 duprintf("translate_table: ARPT_ENTRY_ITERATE gives %d\n", ret); 652 if (ret != 0) 653 return ret; 654 655 if (i != repl->num_entries) { 656 duprintf("translate_table: %u not %u entries\n", 657 i, repl->num_entries); 658 return -EINVAL; 659 } 660 661 /* Check hooks all assigned */ 662 for (i = 0; i < NF_ARP_NUMHOOKS; i++) { 663 /* Only hooks which are valid */ 664 if (!(repl->valid_hooks & (1 << i))) 665 continue; 666 if (newinfo->hook_entry[i] == 0xFFFFFFFF) { 667 duprintf("Invalid hook entry %u %u\n", 668 i, repl->hook_entry[i]); 669 return -EINVAL; 670 } 671 if (newinfo->underflow[i] == 0xFFFFFFFF) { 672 duprintf("Invalid underflow %u %u\n", 673 i, repl->underflow[i]); 674 return -EINVAL; 675 } 676 } 677 678 if (!mark_source_chains(newinfo, repl->valid_hooks, entry0)) { 679 duprintf("Looping hook\n"); 680 return -ELOOP; 681 } 682 683 /* Finally, each sanity check must pass */ 684 i = 0; 685 xt_entry_foreach(iter, entry0, newinfo->size) { 686 ret = find_check_entry(iter, repl->name, repl->size); 687 if (ret != 0) 688 break; 689 ++i; 690 } 691 692 if (ret != 0) { 693 xt_entry_foreach(iter, entry0, newinfo->size) { 694 if (i-- == 0) 695 break; 696 cleanup_entry(iter); 697 } 698 return ret; 699 } 700 701 /* And one copy for every other CPU */ 702 for_each_possible_cpu(i) { 703 if (newinfo->entries[i] && newinfo->entries[i] != entry0) 704 memcpy(newinfo->entries[i], entry0, newinfo->size); 705 } 706 707 return ret; 708} 709 710static void get_counters(const struct xt_table_info *t, 711 struct xt_counters counters[]) 712{ 713 struct arpt_entry *iter; 714 unsigned int cpu; 715 unsigned int i; 716 717 for_each_possible_cpu(cpu) { 718 seqcount_t *s = &per_cpu(xt_recseq, cpu); 719 720 i = 0; 721 xt_entry_foreach(iter, t->entries[cpu], t->size) { 722 u64 bcnt, pcnt; 723 unsigned int start; 724 725 do { 726 start = read_seqcount_begin(s); 727 bcnt = iter->counters.bcnt; 728 pcnt = iter->counters.pcnt; 729 } while (read_seqcount_retry(s, start)); 730 731 ADD_COUNTER(counters[i], bcnt, pcnt); 732 ++i; 733 } 734 } 735} 736 737static struct xt_counters *alloc_counters(const struct xt_table *table) 738{ 739 unsigned int countersize; 740 struct xt_counters *counters; 741 const struct xt_table_info *private = table->private; 742 743 /* We need atomic snapshot of counters: rest doesn't change 744 * (other than comefrom, which userspace doesn't care 745 * about). 746 */ 747 countersize = sizeof(struct xt_counters) * private->number; 748 counters = vzalloc(countersize); 749 750 if (counters == NULL) 751 return ERR_PTR(-ENOMEM); 752 753 get_counters(private, counters); 754 755 return counters; 756} 757 758static int copy_entries_to_user(unsigned int total_size, 759 const struct xt_table *table, 760 void __user *userptr) 761{ 762 unsigned int off, num; 763 const struct arpt_entry *e; 764 struct xt_counters *counters; 765 struct xt_table_info *private = table->private; 766 int ret = 0; 767 void *loc_cpu_entry; 768 769 counters = alloc_counters(table); 770 if (IS_ERR(counters)) 771 return PTR_ERR(counters); 772 773 loc_cpu_entry = private->entries[raw_smp_processor_id()]; 774 /* ... then copy entire thing ... */ 775 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) { 776 ret = -EFAULT; 777 goto free_counters; 778 } 779 780 /* FIXME: use iterator macros --RR */ 781 /* ... then go back and fix counters and names */ 782 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){ 783 const struct xt_entry_target *t; 784 785 e = (struct arpt_entry *)(loc_cpu_entry + off); 786 if (copy_to_user(userptr + off 787 + offsetof(struct arpt_entry, counters), 788 &counters[num], 789 sizeof(counters[num])) != 0) { 790 ret = -EFAULT; 791 goto free_counters; 792 } 793 794 t = arpt_get_target_c(e); 795 if (copy_to_user(userptr + off + e->target_offset 796 + offsetof(struct xt_entry_target, 797 u.user.name), 798 t->u.kernel.target->name, 799 strlen(t->u.kernel.target->name)+1) != 0) { 800 ret = -EFAULT; 801 goto free_counters; 802 } 803 } 804 805 free_counters: 806 vfree(counters); 807 return ret; 808} 809 810#ifdef CONFIG_COMPAT 811static void compat_standard_from_user(void *dst, const void *src) 812{ 813 int v = *(compat_int_t *)src; 814 815 if (v > 0) 816 v += xt_compat_calc_jump(NFPROTO_ARP, v); 817 memcpy(dst, &v, sizeof(v)); 818} 819 820static int compat_standard_to_user(void __user *dst, const void *src) 821{ 822 compat_int_t cv = *(int *)src; 823 824 if (cv > 0) 825 cv -= xt_compat_calc_jump(NFPROTO_ARP, cv); 826 return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0; 827} 828 829static int compat_calc_entry(const struct arpt_entry *e, 830 const struct xt_table_info *info, 831 const void *base, struct xt_table_info *newinfo) 832{ 833 const struct xt_entry_target *t; 834 unsigned int entry_offset; 835 int off, i, ret; 836 837 off = sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry); 838 entry_offset = (void *)e - base; 839 840 t = arpt_get_target_c(e); 841 off += xt_compat_target_offset(t->u.kernel.target); 842 newinfo->size -= off; 843 ret = xt_compat_add_offset(NFPROTO_ARP, entry_offset, off); 844 if (ret) 845 return ret; 846 847 for (i = 0; i < NF_ARP_NUMHOOKS; i++) { 848 if (info->hook_entry[i] && 849 (e < (struct arpt_entry *)(base + info->hook_entry[i]))) 850 newinfo->hook_entry[i] -= off; 851 if (info->underflow[i] && 852 (e < (struct arpt_entry *)(base + info->underflow[i]))) 853 newinfo->underflow[i] -= off; 854 } 855 return 0; 856} 857 858static int compat_table_info(const struct xt_table_info *info, 859 struct xt_table_info *newinfo) 860{ 861 struct arpt_entry *iter; 862 void *loc_cpu_entry; 863 int ret; 864 865 if (!newinfo || !info) 866 return -EINVAL; 867 868 /* we dont care about newinfo->entries[] */ 869 memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); 870 newinfo->initial_entries = 0; 871 loc_cpu_entry = info->entries[raw_smp_processor_id()]; 872 xt_compat_init_offsets(NFPROTO_ARP, info->number); 873 xt_entry_foreach(iter, loc_cpu_entry, info->size) { 874 ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo); 875 if (ret != 0) 876 return ret; 877 } 878 return 0; 879} 880#endif 881 882static int get_info(struct net *net, void __user *user, 883 const int *len, int compat) 884{ 885 char name[XT_TABLE_MAXNAMELEN]; 886 struct xt_table *t; 887 int ret; 888 889 if (*len != sizeof(struct arpt_getinfo)) { 890 duprintf("length %u != %Zu\n", *len, 891 sizeof(struct arpt_getinfo)); 892 return -EINVAL; 893 } 894 895 if (copy_from_user(name, user, sizeof(name)) != 0) 896 return -EFAULT; 897 898 name[XT_TABLE_MAXNAMELEN-1] = '\0'; 899#ifdef CONFIG_COMPAT 900 if (compat) 901 xt_compat_lock(NFPROTO_ARP); 902#endif 903 t = try_then_request_module(xt_find_table_lock(net, NFPROTO_ARP, name), 904 "arptable_%s", name); 905 if (!IS_ERR_OR_NULL(t)) { 906 struct arpt_getinfo info; 907 const struct xt_table_info *private = t->private; 908#ifdef CONFIG_COMPAT 909 struct xt_table_info tmp; 910 911 if (compat) { 912 ret = compat_table_info(private, &tmp); 913 xt_compat_flush_offsets(NFPROTO_ARP); 914 private = &tmp; 915 } 916#endif 917 memset(&info, 0, sizeof(info)); 918 info.valid_hooks = t->valid_hooks; 919 memcpy(info.hook_entry, private->hook_entry, 920 sizeof(info.hook_entry)); 921 memcpy(info.underflow, private->underflow, 922 sizeof(info.underflow)); 923 info.num_entries = private->number; 924 info.size = private->size; 925 strcpy(info.name, name); 926 927 if (copy_to_user(user, &info, *len) != 0) 928 ret = -EFAULT; 929 else 930 ret = 0; 931 xt_table_unlock(t); 932 module_put(t->me); 933 } else 934 ret = t ? PTR_ERR(t) : -ENOENT; 935#ifdef CONFIG_COMPAT 936 if (compat) 937 xt_compat_unlock(NFPROTO_ARP); 938#endif 939 return ret; 940} 941 942static int get_entries(struct net *net, struct arpt_get_entries __user *uptr, 943 const int *len) 944{ 945 int ret; 946 struct arpt_get_entries get; 947 struct xt_table *t; 948 949 if (*len < sizeof(get)) { 950 duprintf("get_entries: %u < %Zu\n", *len, sizeof(get)); 951 return -EINVAL; 952 } 953 if (copy_from_user(&get, uptr, sizeof(get)) != 0) 954 return -EFAULT; 955 if (*len != sizeof(struct arpt_get_entries) + get.size) { 956 duprintf("get_entries: %u != %Zu\n", *len, 957 sizeof(struct arpt_get_entries) + get.size); 958 return -EINVAL; 959 } 960 961 t = xt_find_table_lock(net, NFPROTO_ARP, get.name); 962 if (!IS_ERR_OR_NULL(t)) { 963 const struct xt_table_info *private = t->private; 964 965 duprintf("t->private->number = %u\n", 966 private->number); 967 if (get.size == private->size) 968 ret = copy_entries_to_user(private->size, 969 t, uptr->entrytable); 970 else { 971 duprintf("get_entries: I've got %u not %u!\n", 972 private->size, get.size); 973 ret = -EAGAIN; 974 } 975 module_put(t->me); 976 xt_table_unlock(t); 977 } else 978 ret = t ? PTR_ERR(t) : -ENOENT; 979 980 return ret; 981} 982 983static int __do_replace(struct net *net, const char *name, 984 unsigned int valid_hooks, 985 struct xt_table_info *newinfo, 986 unsigned int num_counters, 987 void __user *counters_ptr) 988{ 989 int ret; 990 struct xt_table *t; 991 struct xt_table_info *oldinfo; 992 struct xt_counters *counters; 993 void *loc_cpu_old_entry; 994 struct arpt_entry *iter; 995 996 ret = 0; 997 counters = vzalloc(num_counters * sizeof(struct xt_counters)); 998 if (!counters) { 999 ret = -ENOMEM; 1000 goto out; 1001 } 1002 1003 t = try_then_request_module(xt_find_table_lock(net, NFPROTO_ARP, name), 1004 "arptable_%s", name); 1005 if (IS_ERR_OR_NULL(t)) { 1006 ret = t ? PTR_ERR(t) : -ENOENT; 1007 goto free_newinfo_counters_untrans; 1008 } 1009 1010 /* You lied! */ 1011 if (valid_hooks != t->valid_hooks) { 1012 duprintf("Valid hook crap: %08X vs %08X\n", 1013 valid_hooks, t->valid_hooks); 1014 ret = -EINVAL; 1015 goto put_module; 1016 } 1017 1018 oldinfo = xt_replace_table(t, num_counters, newinfo, &ret); 1019 if (!oldinfo) 1020 goto put_module; 1021 1022 /* Update module usage count based on number of rules */ 1023 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n", 1024 oldinfo->number, oldinfo->initial_entries, newinfo->number); 1025 if ((oldinfo->number > oldinfo->initial_entries) || 1026 (newinfo->number <= oldinfo->initial_entries)) 1027 module_put(t->me); 1028 if ((oldinfo->number > oldinfo->initial_entries) && 1029 (newinfo->number <= oldinfo->initial_entries)) 1030 module_put(t->me); 1031 1032 /* Get the old counters, and synchronize with replace */ 1033 get_counters(oldinfo, counters); 1034 1035 /* Decrease module usage counts and free resource */ 1036 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; 1037 xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size) 1038 cleanup_entry(iter); 1039 1040 xt_free_table_info(oldinfo); 1041 if (copy_to_user(counters_ptr, counters, 1042 sizeof(struct xt_counters) * num_counters) != 0) 1043 ret = -EFAULT; 1044 vfree(counters); 1045 xt_table_unlock(t); 1046 return ret; 1047 1048 put_module: 1049 module_put(t->me); 1050 xt_table_unlock(t); 1051 free_newinfo_counters_untrans: 1052 vfree(counters); 1053 out: 1054 return ret; 1055} 1056 1057static int do_replace(struct net *net, const void __user *user, 1058 unsigned int len) 1059{ 1060 int ret; 1061 struct arpt_replace tmp; 1062 struct xt_table_info *newinfo; 1063 void *loc_cpu_entry; 1064 struct arpt_entry *iter; 1065 1066 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) 1067 return -EFAULT; 1068 1069 /* overflow check */ 1070 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters)) 1071 return -ENOMEM; 1072 tmp.name[sizeof(tmp.name)-1] = 0; 1073 1074 newinfo = xt_alloc_table_info(tmp.size); 1075 if (!newinfo) 1076 return -ENOMEM; 1077 1078 /* choose the copy that is on our node/cpu */ 1079 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; 1080 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp), 1081 tmp.size) != 0) { 1082 ret = -EFAULT; 1083 goto free_newinfo; 1084 } 1085 1086 ret = translate_table(newinfo, loc_cpu_entry, &tmp); 1087 if (ret != 0) 1088 goto free_newinfo; 1089 1090 duprintf("arp_tables: Translated table\n"); 1091 1092 ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo, 1093 tmp.num_counters, tmp.counters); 1094 if (ret) 1095 goto free_newinfo_untrans; 1096 return 0; 1097 1098 free_newinfo_untrans: 1099 xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) 1100 cleanup_entry(iter); 1101 free_newinfo: 1102 xt_free_table_info(newinfo); 1103 return ret; 1104} 1105 1106static int do_add_counters(struct net *net, const void __user *user, 1107 unsigned int len, int compat) 1108{ 1109 unsigned int i, curcpu; 1110 struct xt_counters_info tmp; 1111 struct xt_counters *paddc; 1112 unsigned int num_counters; 1113 const char *name; 1114 int size; 1115 void *ptmp; 1116 struct xt_table *t; 1117 const struct xt_table_info *private; 1118 int ret = 0; 1119 void *loc_cpu_entry; 1120 struct arpt_entry *iter; 1121 unsigned int addend; 1122#ifdef CONFIG_COMPAT 1123 struct compat_xt_counters_info compat_tmp; 1124 1125 if (compat) { 1126 ptmp = &compat_tmp; 1127 size = sizeof(struct compat_xt_counters_info); 1128 } else 1129#endif 1130 { 1131 ptmp = &tmp; 1132 size = sizeof(struct xt_counters_info); 1133 } 1134 1135 if (copy_from_user(ptmp, user, size) != 0) 1136 return -EFAULT; 1137 1138#ifdef CONFIG_COMPAT 1139 if (compat) { 1140 num_counters = compat_tmp.num_counters; 1141 name = compat_tmp.name; 1142 } else 1143#endif 1144 { 1145 num_counters = tmp.num_counters; 1146 name = tmp.name; 1147 } 1148 1149 if (len != size + num_counters * sizeof(struct xt_counters)) 1150 return -EINVAL; 1151 1152 paddc = vmalloc(len - size); 1153 if (!paddc) 1154 return -ENOMEM; 1155 1156 if (copy_from_user(paddc, user + size, len - size) != 0) { 1157 ret = -EFAULT; 1158 goto free; 1159 } 1160 1161 t = xt_find_table_lock(net, NFPROTO_ARP, name); 1162 if (IS_ERR_OR_NULL(t)) { 1163 ret = t ? PTR_ERR(t) : -ENOENT; 1164 goto free; 1165 } 1166 1167 local_bh_disable(); 1168 private = t->private; 1169 if (private->number != num_counters) { 1170 ret = -EINVAL; 1171 goto unlock_up_free; 1172 } 1173 1174 i = 0; 1175 /* Choose the copy that is on our node */ 1176 curcpu = smp_processor_id(); 1177 loc_cpu_entry = private->entries[curcpu]; 1178 addend = xt_write_recseq_begin(); 1179 xt_entry_foreach(iter, loc_cpu_entry, private->size) { 1180 ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt); 1181 ++i; 1182 } 1183 xt_write_recseq_end(addend); 1184 unlock_up_free: 1185 local_bh_enable(); 1186 xt_table_unlock(t); 1187 module_put(t->me); 1188 free: 1189 vfree(paddc); 1190 1191 return ret; 1192} 1193 1194#ifdef CONFIG_COMPAT 1195static inline void compat_release_entry(struct compat_arpt_entry *e) 1196{ 1197 struct xt_entry_target *t; 1198 1199 t = compat_arpt_get_target(e); 1200 module_put(t->u.kernel.target->me); 1201} 1202 1203static inline int 1204check_compat_entry_size_and_hooks(struct compat_arpt_entry *e, 1205 struct xt_table_info *newinfo, 1206 unsigned int *size, 1207 const unsigned char *base, 1208 const unsigned char *limit, 1209 const unsigned int *hook_entries, 1210 const unsigned int *underflows, 1211 const char *name) 1212{ 1213 struct xt_entry_target *t; 1214 struct xt_target *target; 1215 unsigned int entry_offset; 1216 int ret, off, h; 1217 1218 duprintf("check_compat_entry_size_and_hooks %p\n", e); 1219 if ((unsigned long)e % __alignof__(struct compat_arpt_entry) != 0 || 1220 (unsigned char *)e + sizeof(struct compat_arpt_entry) >= limit) { 1221 duprintf("Bad offset %p, limit = %p\n", e, limit); 1222 return -EINVAL; 1223 } 1224 1225 if (e->next_offset < sizeof(struct compat_arpt_entry) + 1226 sizeof(struct compat_xt_entry_target)) { 1227 duprintf("checking: element %p size %u\n", 1228 e, e->next_offset); 1229 return -EINVAL; 1230 } 1231 1232 /* For purposes of check_entry casting the compat entry is fine */ 1233 ret = check_entry((struct arpt_entry *)e, name); 1234 if (ret) 1235 return ret; 1236 1237 off = sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry); 1238 entry_offset = (void *)e - (void *)base; 1239 1240 t = compat_arpt_get_target(e); 1241 target = xt_request_find_target(NFPROTO_ARP, t->u.user.name, 1242 t->u.user.revision); 1243 if (IS_ERR(target)) { 1244 duprintf("check_compat_entry_size_and_hooks: `%s' not found\n", 1245 t->u.user.name); 1246 ret = PTR_ERR(target); 1247 goto out; 1248 } 1249 t->u.kernel.target = target; 1250 1251 off += xt_compat_target_offset(target); 1252 *size += off; 1253 ret = xt_compat_add_offset(NFPROTO_ARP, entry_offset, off); 1254 if (ret) 1255 goto release_target; 1256 1257 /* Check hooks & underflows */ 1258 for (h = 0; h < NF_ARP_NUMHOOKS; h++) { 1259 if ((unsigned char *)e - base == hook_entries[h]) 1260 newinfo->hook_entry[h] = hook_entries[h]; 1261 if ((unsigned char *)e - base == underflows[h]) 1262 newinfo->underflow[h] = underflows[h]; 1263 } 1264 1265 /* Clear counters and comefrom */ 1266 memset(&e->counters, 0, sizeof(e->counters)); 1267 e->comefrom = 0; 1268 return 0; 1269 1270release_target: 1271 module_put(t->u.kernel.target->me); 1272out: 1273 return ret; 1274} 1275 1276static int 1277compat_copy_entry_from_user(struct compat_arpt_entry *e, void **dstptr, 1278 unsigned int *size, const char *name, 1279 struct xt_table_info *newinfo, unsigned char *base) 1280{ 1281 struct xt_entry_target *t; 1282 struct xt_target *target; 1283 struct arpt_entry *de; 1284 unsigned int origsize; 1285 int ret, h; 1286 1287 ret = 0; 1288 origsize = *size; 1289 de = (struct arpt_entry *)*dstptr; 1290 memcpy(de, e, sizeof(struct arpt_entry)); 1291 memcpy(&de->counters, &e->counters, sizeof(e->counters)); 1292 1293 *dstptr += sizeof(struct arpt_entry); 1294 *size += sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry); 1295 1296 de->target_offset = e->target_offset - (origsize - *size); 1297 t = compat_arpt_get_target(e); 1298 target = t->u.kernel.target; 1299 xt_compat_target_from_user(t, dstptr, size); 1300 1301 de->next_offset = e->next_offset - (origsize - *size); 1302 for (h = 0; h < NF_ARP_NUMHOOKS; h++) { 1303 if ((unsigned char *)de - base < newinfo->hook_entry[h]) 1304 newinfo->hook_entry[h] -= origsize - *size; 1305 if ((unsigned char *)de - base < newinfo->underflow[h]) 1306 newinfo->underflow[h] -= origsize - *size; 1307 } 1308 return ret; 1309} 1310 1311static int translate_compat_table(const char *name, 1312 unsigned int valid_hooks, 1313 struct xt_table_info **pinfo, 1314 void **pentry0, 1315 unsigned int total_size, 1316 unsigned int number, 1317 unsigned int *hook_entries, 1318 unsigned int *underflows) 1319{ 1320 unsigned int i, j; 1321 struct xt_table_info *newinfo, *info; 1322 void *pos, *entry0, *entry1; 1323 struct compat_arpt_entry *iter0; 1324 struct arpt_entry *iter1; 1325 unsigned int size; 1326 int ret = 0; 1327 1328 info = *pinfo; 1329 entry0 = *pentry0; 1330 size = total_size; 1331 info->number = number; 1332 1333 /* Init all hooks to impossible value. */ 1334 for (i = 0; i < NF_ARP_NUMHOOKS; i++) { 1335 info->hook_entry[i] = 0xFFFFFFFF; 1336 info->underflow[i] = 0xFFFFFFFF; 1337 } 1338 1339 duprintf("translate_compat_table: size %u\n", info->size); 1340 j = 0; 1341 xt_compat_lock(NFPROTO_ARP); 1342 xt_compat_init_offsets(NFPROTO_ARP, number); 1343 /* Walk through entries, checking offsets. */ 1344 xt_entry_foreach(iter0, entry0, total_size) { 1345 ret = check_compat_entry_size_and_hooks(iter0, info, &size, 1346 entry0, 1347 entry0 + total_size, 1348 hook_entries, 1349 underflows, 1350 name); 1351 if (ret != 0) 1352 goto out_unlock; 1353 ++j; 1354 } 1355 1356 ret = -EINVAL; 1357 if (j != number) { 1358 duprintf("translate_compat_table: %u not %u entries\n", 1359 j, number); 1360 goto out_unlock; 1361 } 1362 1363 /* Check hooks all assigned */ 1364 for (i = 0; i < NF_ARP_NUMHOOKS; i++) { 1365 /* Only hooks which are valid */ 1366 if (!(valid_hooks & (1 << i))) 1367 continue; 1368 if (info->hook_entry[i] == 0xFFFFFFFF) { 1369 duprintf("Invalid hook entry %u %u\n", 1370 i, hook_entries[i]); 1371 goto out_unlock; 1372 } 1373 if (info->underflow[i] == 0xFFFFFFFF) { 1374 duprintf("Invalid underflow %u %u\n", 1375 i, underflows[i]); 1376 goto out_unlock; 1377 } 1378 } 1379 1380 ret = -ENOMEM; 1381 newinfo = xt_alloc_table_info(size); 1382 if (!newinfo) 1383 goto out_unlock; 1384 1385 newinfo->number = number; 1386 for (i = 0; i < NF_ARP_NUMHOOKS; i++) { 1387 newinfo->hook_entry[i] = info->hook_entry[i]; 1388 newinfo->underflow[i] = info->underflow[i]; 1389 } 1390 entry1 = newinfo->entries[raw_smp_processor_id()]; 1391 pos = entry1; 1392 size = total_size; 1393 xt_entry_foreach(iter0, entry0, total_size) { 1394 ret = compat_copy_entry_from_user(iter0, &pos, &size, 1395 name, newinfo, entry1); 1396 if (ret != 0) 1397 break; 1398 } 1399 xt_compat_flush_offsets(NFPROTO_ARP); 1400 xt_compat_unlock(NFPROTO_ARP); 1401 if (ret) 1402 goto free_newinfo; 1403 1404 ret = -ELOOP; 1405 if (!mark_source_chains(newinfo, valid_hooks, entry1)) 1406 goto free_newinfo; 1407 1408 i = 0; 1409 xt_entry_foreach(iter1, entry1, newinfo->size) { 1410 ret = check_target(iter1, name); 1411 if (ret != 0) 1412 break; 1413 ++i; 1414 if (strcmp(arpt_get_target(iter1)->u.user.name, 1415 XT_ERROR_TARGET) == 0) 1416 ++newinfo->stacksize; 1417 } 1418 if (ret) { 1419 /* 1420 * The first i matches need cleanup_entry (calls ->destroy) 1421 * because they had called ->check already. The other j-i 1422 * entries need only release. 1423 */ 1424 int skip = i; 1425 j -= i; 1426 xt_entry_foreach(iter0, entry0, newinfo->size) { 1427 if (skip-- > 0) 1428 continue; 1429 if (j-- == 0) 1430 break; 1431 compat_release_entry(iter0); 1432 } 1433 xt_entry_foreach(iter1, entry1, newinfo->size) { 1434 if (i-- == 0) 1435 break; 1436 cleanup_entry(iter1); 1437 } 1438 xt_free_table_info(newinfo); 1439 return ret; 1440 } 1441 1442 /* And one copy for every other CPU */ 1443 for_each_possible_cpu(i) 1444 if (newinfo->entries[i] && newinfo->entries[i] != entry1) 1445 memcpy(newinfo->entries[i], entry1, newinfo->size); 1446 1447 *pinfo = newinfo; 1448 *pentry0 = entry1; 1449 xt_free_table_info(info); 1450 return 0; 1451 1452free_newinfo: 1453 xt_free_table_info(newinfo); 1454out: 1455 xt_entry_foreach(iter0, entry0, total_size) { 1456 if (j-- == 0) 1457 break; 1458 compat_release_entry(iter0); 1459 } 1460 return ret; 1461out_unlock: 1462 xt_compat_flush_offsets(NFPROTO_ARP); 1463 xt_compat_unlock(NFPROTO_ARP); 1464 goto out; 1465} 1466 1467struct compat_arpt_replace { 1468 char name[XT_TABLE_MAXNAMELEN]; 1469 u32 valid_hooks; 1470 u32 num_entries; 1471 u32 size; 1472 u32 hook_entry[NF_ARP_NUMHOOKS]; 1473 u32 underflow[NF_ARP_NUMHOOKS]; 1474 u32 num_counters; 1475 compat_uptr_t counters; 1476 struct compat_arpt_entry entries[0]; 1477}; 1478 1479static int compat_do_replace(struct net *net, void __user *user, 1480 unsigned int len) 1481{ 1482 int ret; 1483 struct compat_arpt_replace tmp; 1484 struct xt_table_info *newinfo; 1485 void *loc_cpu_entry; 1486 struct arpt_entry *iter; 1487 1488 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) 1489 return -EFAULT; 1490 1491 /* overflow check */ 1492 if (tmp.size >= INT_MAX / num_possible_cpus()) 1493 return -ENOMEM; 1494 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters)) 1495 return -ENOMEM; 1496 tmp.name[sizeof(tmp.name)-1] = 0; 1497 1498 newinfo = xt_alloc_table_info(tmp.size); 1499 if (!newinfo) 1500 return -ENOMEM; 1501 1502 /* choose the copy that is on our node/cpu */ 1503 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; 1504 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp), tmp.size) != 0) { 1505 ret = -EFAULT; 1506 goto free_newinfo; 1507 } 1508 1509 ret = translate_compat_table(tmp.name, tmp.valid_hooks, 1510 &newinfo, &loc_cpu_entry, tmp.size, 1511 tmp.num_entries, tmp.hook_entry, 1512 tmp.underflow); 1513 if (ret != 0) 1514 goto free_newinfo; 1515 1516 duprintf("compat_do_replace: Translated table\n"); 1517 1518 ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo, 1519 tmp.num_counters, compat_ptr(tmp.counters)); 1520 if (ret) 1521 goto free_newinfo_untrans; 1522 return 0; 1523 1524 free_newinfo_untrans: 1525 xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) 1526 cleanup_entry(iter); 1527 free_newinfo: 1528 xt_free_table_info(newinfo); 1529 return ret; 1530} 1531 1532static int compat_do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, 1533 unsigned int len) 1534{ 1535 int ret; 1536 1537 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) 1538 return -EPERM; 1539 1540 switch (cmd) { 1541 case ARPT_SO_SET_REPLACE: 1542 ret = compat_do_replace(sock_net(sk), user, len); 1543 break; 1544 1545 case ARPT_SO_SET_ADD_COUNTERS: 1546 ret = do_add_counters(sock_net(sk), user, len, 1); 1547 break; 1548 1549 default: 1550 duprintf("do_arpt_set_ctl: unknown request %i\n", cmd); 1551 ret = -EINVAL; 1552 } 1553 1554 return ret; 1555} 1556 1557static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, 1558 compat_uint_t *size, 1559 struct xt_counters *counters, 1560 unsigned int i) 1561{ 1562 struct xt_entry_target *t; 1563 struct compat_arpt_entry __user *ce; 1564 u_int16_t target_offset, next_offset; 1565 compat_uint_t origsize; 1566 int ret; 1567 1568 origsize = *size; 1569 ce = (struct compat_arpt_entry __user *)*dstptr; 1570 if (copy_to_user(ce, e, sizeof(struct arpt_entry)) != 0 || 1571 copy_to_user(&ce->counters, &counters[i], 1572 sizeof(counters[i])) != 0) 1573 return -EFAULT; 1574 1575 *dstptr += sizeof(struct compat_arpt_entry); 1576 *size -= sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry); 1577 1578 target_offset = e->target_offset - (origsize - *size); 1579 1580 t = arpt_get_target(e); 1581 ret = xt_compat_target_to_user(t, dstptr, size); 1582 if (ret) 1583 return ret; 1584 next_offset = e->next_offset - (origsize - *size); 1585 if (put_user(target_offset, &ce->target_offset) != 0 || 1586 put_user(next_offset, &ce->next_offset) != 0) 1587 return -EFAULT; 1588 return 0; 1589} 1590 1591static int compat_copy_entries_to_user(unsigned int total_size, 1592 struct xt_table *table, 1593 void __user *userptr) 1594{ 1595 struct xt_counters *counters; 1596 const struct xt_table_info *private = table->private; 1597 void __user *pos; 1598 unsigned int size; 1599 int ret = 0; 1600 void *loc_cpu_entry; 1601 unsigned int i = 0; 1602 struct arpt_entry *iter; 1603 1604 counters = alloc_counters(table); 1605 if (IS_ERR(counters)) 1606 return PTR_ERR(counters); 1607 1608 /* choose the copy on our node/cpu */ 1609 loc_cpu_entry = private->entries[raw_smp_processor_id()]; 1610 pos = userptr; 1611 size = total_size; 1612 xt_entry_foreach(iter, loc_cpu_entry, total_size) { 1613 ret = compat_copy_entry_to_user(iter, &pos, 1614 &size, counters, i++); 1615 if (ret != 0) 1616 break; 1617 } 1618 vfree(counters); 1619 return ret; 1620} 1621 1622struct compat_arpt_get_entries { 1623 char name[XT_TABLE_MAXNAMELEN]; 1624 compat_uint_t size; 1625 struct compat_arpt_entry entrytable[0]; 1626}; 1627 1628static int compat_get_entries(struct net *net, 1629 struct compat_arpt_get_entries __user *uptr, 1630 int *len) 1631{ 1632 int ret; 1633 struct compat_arpt_get_entries get; 1634 struct xt_table *t; 1635 1636 if (*len < sizeof(get)) { 1637 duprintf("compat_get_entries: %u < %zu\n", *len, sizeof(get)); 1638 return -EINVAL; 1639 } 1640 if (copy_from_user(&get, uptr, sizeof(get)) != 0) 1641 return -EFAULT; 1642 if (*len != sizeof(struct compat_arpt_get_entries) + get.size) { 1643 duprintf("compat_get_entries: %u != %zu\n", 1644 *len, sizeof(get) + get.size); 1645 return -EINVAL; 1646 } 1647 1648 xt_compat_lock(NFPROTO_ARP); 1649 t = xt_find_table_lock(net, NFPROTO_ARP, get.name); 1650 if (!IS_ERR_OR_NULL(t)) { 1651 const struct xt_table_info *private = t->private; 1652 struct xt_table_info info; 1653 1654 duprintf("t->private->number = %u\n", private->number); 1655 ret = compat_table_info(private, &info); 1656 if (!ret && get.size == info.size) { 1657 ret = compat_copy_entries_to_user(private->size, 1658 t, uptr->entrytable); 1659 } else if (!ret) { 1660 duprintf("compat_get_entries: I've got %u not %u!\n", 1661 private->size, get.size); 1662 ret = -EAGAIN; 1663 } 1664 xt_compat_flush_offsets(NFPROTO_ARP); 1665 module_put(t->me); 1666 xt_table_unlock(t); 1667 } else 1668 ret = t ? PTR_ERR(t) : -ENOENT; 1669 1670 xt_compat_unlock(NFPROTO_ARP); 1671 return ret; 1672} 1673 1674static int do_arpt_get_ctl(struct sock *, int, void __user *, int *); 1675 1676static int compat_do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, 1677 int *len) 1678{ 1679 int ret; 1680 1681 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) 1682 return -EPERM; 1683 1684 switch (cmd) { 1685 case ARPT_SO_GET_INFO: 1686 ret = get_info(sock_net(sk), user, len, 1); 1687 break; 1688 case ARPT_SO_GET_ENTRIES: 1689 ret = compat_get_entries(sock_net(sk), user, len); 1690 break; 1691 default: 1692 ret = do_arpt_get_ctl(sk, cmd, user, len); 1693 } 1694 return ret; 1695} 1696#endif 1697 1698static int do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) 1699{ 1700 int ret; 1701 1702 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) 1703 return -EPERM; 1704 1705 switch (cmd) { 1706 case ARPT_SO_SET_REPLACE: 1707 ret = do_replace(sock_net(sk), user, len); 1708 break; 1709 1710 case ARPT_SO_SET_ADD_COUNTERS: 1711 ret = do_add_counters(sock_net(sk), user, len, 0); 1712 break; 1713 1714 default: 1715 duprintf("do_arpt_set_ctl: unknown request %i\n", cmd); 1716 ret = -EINVAL; 1717 } 1718 1719 return ret; 1720} 1721 1722static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) 1723{ 1724 int ret; 1725 1726 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) 1727 return -EPERM; 1728 1729 switch (cmd) { 1730 case ARPT_SO_GET_INFO: 1731 ret = get_info(sock_net(sk), user, len, 0); 1732 break; 1733 1734 case ARPT_SO_GET_ENTRIES: 1735 ret = get_entries(sock_net(sk), user, len); 1736 break; 1737 1738 case ARPT_SO_GET_REVISION_TARGET: { 1739 struct xt_get_revision rev; 1740 1741 if (*len != sizeof(rev)) { 1742 ret = -EINVAL; 1743 break; 1744 } 1745 if (copy_from_user(&rev, user, sizeof(rev)) != 0) { 1746 ret = -EFAULT; 1747 break; 1748 } 1749 rev.name[sizeof(rev.name)-1] = 0; 1750 1751 try_then_request_module(xt_find_revision(NFPROTO_ARP, rev.name, 1752 rev.revision, 1, &ret), 1753 "arpt_%s", rev.name); 1754 break; 1755 } 1756 1757 default: 1758 duprintf("do_arpt_get_ctl: unknown request %i\n", cmd); 1759 ret = -EINVAL; 1760 } 1761 1762 return ret; 1763} 1764 1765struct xt_table *arpt_register_table(struct net *net, 1766 const struct xt_table *table, 1767 const struct arpt_replace *repl) 1768{ 1769 int ret; 1770 struct xt_table_info *newinfo; 1771 struct xt_table_info bootstrap = {0}; 1772 void *loc_cpu_entry; 1773 struct xt_table *new_table; 1774 1775 newinfo = xt_alloc_table_info(repl->size); 1776 if (!newinfo) { 1777 ret = -ENOMEM; 1778 goto out; 1779 } 1780 1781 /* choose the copy on our node/cpu */ 1782 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; 1783 memcpy(loc_cpu_entry, repl->entries, repl->size); 1784 1785 ret = translate_table(newinfo, loc_cpu_entry, repl); 1786 duprintf("arpt_register_table: translate table gives %d\n", ret); 1787 if (ret != 0) 1788 goto out_free; 1789 1790 new_table = xt_register_table(net, table, &bootstrap, newinfo); 1791 if (IS_ERR(new_table)) { 1792 ret = PTR_ERR(new_table); 1793 goto out_free; 1794 } 1795 return new_table; 1796 1797out_free: 1798 xt_free_table_info(newinfo); 1799out: 1800 return ERR_PTR(ret); 1801} 1802 1803void arpt_unregister_table(struct xt_table *table) 1804{ 1805 struct xt_table_info *private; 1806 void *loc_cpu_entry; 1807 struct module *table_owner = table->me; 1808 struct arpt_entry *iter; 1809 1810 private = xt_unregister_table(table); 1811 1812 /* Decrease module usage counts and free resources */ 1813 loc_cpu_entry = private->entries[raw_smp_processor_id()]; 1814 xt_entry_foreach(iter, loc_cpu_entry, private->size) 1815 cleanup_entry(iter); 1816 if (private->number > private->initial_entries) 1817 module_put(table_owner); 1818 xt_free_table_info(private); 1819} 1820 1821/* The built-in targets: standard (NULL) and error. */ 1822static struct xt_target arpt_builtin_tg[] __read_mostly = { 1823 { 1824 .name = XT_STANDARD_TARGET, 1825 .targetsize = sizeof(int), 1826 .family = NFPROTO_ARP, 1827#ifdef CONFIG_COMPAT 1828 .compatsize = sizeof(compat_int_t), 1829 .compat_from_user = compat_standard_from_user, 1830 .compat_to_user = compat_standard_to_user, 1831#endif 1832 }, 1833 { 1834 .name = XT_ERROR_TARGET, 1835 .target = arpt_error, 1836 .targetsize = XT_FUNCTION_MAXNAMELEN, 1837 .family = NFPROTO_ARP, 1838 }, 1839}; 1840 1841static struct nf_sockopt_ops arpt_sockopts = { 1842 .pf = PF_INET, 1843 .set_optmin = ARPT_BASE_CTL, 1844 .set_optmax = ARPT_SO_SET_MAX+1, 1845 .set = do_arpt_set_ctl, 1846#ifdef CONFIG_COMPAT 1847 .compat_set = compat_do_arpt_set_ctl, 1848#endif 1849 .get_optmin = ARPT_BASE_CTL, 1850 .get_optmax = ARPT_SO_GET_MAX+1, 1851 .get = do_arpt_get_ctl, 1852#ifdef CONFIG_COMPAT 1853 .compat_get = compat_do_arpt_get_ctl, 1854#endif 1855 .owner = THIS_MODULE, 1856}; 1857 1858static int __net_init arp_tables_net_init(struct net *net) 1859{ 1860 return xt_proto_init(net, NFPROTO_ARP); 1861} 1862 1863static void __net_exit arp_tables_net_exit(struct net *net) 1864{ 1865 xt_proto_fini(net, NFPROTO_ARP); 1866} 1867 1868static struct pernet_operations arp_tables_net_ops = { 1869 .init = arp_tables_net_init, 1870 .exit = arp_tables_net_exit, 1871}; 1872 1873static int __init arp_tables_init(void) 1874{ 1875 int ret; 1876 1877 ret = register_pernet_subsys(&arp_tables_net_ops); 1878 if (ret < 0) 1879 goto err1; 1880 1881 /* No one else will be downing sem now, so we won't sleep */ 1882 ret = xt_register_targets(arpt_builtin_tg, ARRAY_SIZE(arpt_builtin_tg)); 1883 if (ret < 0) 1884 goto err2; 1885 1886 /* Register setsockopt */ 1887 ret = nf_register_sockopt(&arpt_sockopts); 1888 if (ret < 0) 1889 goto err4; 1890 1891 printk(KERN_INFO "arp_tables: (C) 2002 David S. Miller\n"); 1892 return 0; 1893 1894err4: 1895 xt_unregister_targets(arpt_builtin_tg, ARRAY_SIZE(arpt_builtin_tg)); 1896err2: 1897 unregister_pernet_subsys(&arp_tables_net_ops); 1898err1: 1899 return ret; 1900} 1901 1902static void __exit arp_tables_fini(void) 1903{ 1904 nf_unregister_sockopt(&arpt_sockopts); 1905 xt_unregister_targets(arpt_builtin_tg, ARRAY_SIZE(arpt_builtin_tg)); 1906 unregister_pernet_subsys(&arp_tables_net_ops); 1907} 1908 1909EXPORT_SYMBOL(arpt_register_table); 1910EXPORT_SYMBOL(arpt_unregister_table); 1911EXPORT_SYMBOL(arpt_do_table); 1912 1913module_init(arp_tables_init); 1914module_exit(arp_tables_fini); 1915