diff options
Diffstat (limited to 'net/ipv4/netfilter/arp_tables.c')
-rw-r--r-- | net/ipv4/netfilter/arp_tables.c | 57 |
1 files changed, 31 insertions, 26 deletions
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 6e3e0e8b1ce3..4cfcc22f7430 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c | |||
@@ -367,23 +367,12 @@ static inline bool unconditional(const struct arpt_entry *e) | |||
367 | memcmp(&e->arp, &uncond, sizeof(uncond)) == 0; | 367 | memcmp(&e->arp, &uncond, sizeof(uncond)) == 0; |
368 | } | 368 | } |
369 | 369 | ||
370 | static bool find_jump_target(const struct xt_table_info *t, | ||
371 | const struct arpt_entry *target) | ||
372 | { | ||
373 | struct arpt_entry *iter; | ||
374 | |||
375 | xt_entry_foreach(iter, t->entries, t->size) { | ||
376 | if (iter == target) | ||
377 | return true; | ||
378 | } | ||
379 | return false; | ||
380 | } | ||
381 | |||
382 | /* Figures out from what hook each rule can be called: returns 0 if | 370 | /* Figures out from what hook each rule can be called: returns 0 if |
383 | * there are loops. Puts hook bitmask in comefrom. | 371 | * there are loops. Puts hook bitmask in comefrom. |
384 | */ | 372 | */ |
385 | static int mark_source_chains(const struct xt_table_info *newinfo, | 373 | static int mark_source_chains(const struct xt_table_info *newinfo, |
386 | unsigned int valid_hooks, void *entry0) | 374 | unsigned int valid_hooks, void *entry0, |
375 | unsigned int *offsets) | ||
387 | { | 376 | { |
388 | unsigned int hook; | 377 | unsigned int hook; |
389 | 378 | ||
@@ -472,10 +461,11 @@ static int mark_source_chains(const struct xt_table_info *newinfo, | |||
472 | /* This a jump; chase it. */ | 461 | /* This a jump; chase it. */ |
473 | duprintf("Jump rule %u -> %u\n", | 462 | duprintf("Jump rule %u -> %u\n", |
474 | pos, newpos); | 463 | pos, newpos); |
464 | if (!xt_find_jump_offset(offsets, newpos, | ||
465 | newinfo->number)) | ||
466 | return 0; | ||
475 | e = (struct arpt_entry *) | 467 | e = (struct arpt_entry *) |
476 | (entry0 + newpos); | 468 | (entry0 + newpos); |
477 | if (!find_jump_target(newinfo, e)) | ||
478 | return 0; | ||
479 | } else { | 469 | } else { |
480 | /* ... this is a fallthru */ | 470 | /* ... this is a fallthru */ |
481 | newpos = pos + e->next_offset; | 471 | newpos = pos + e->next_offset; |
@@ -521,11 +511,13 @@ find_check_entry(struct arpt_entry *e, const char *name, unsigned int size) | |||
521 | { | 511 | { |
522 | struct xt_entry_target *t; | 512 | struct xt_entry_target *t; |
523 | struct xt_target *target; | 513 | struct xt_target *target; |
514 | unsigned long pcnt; | ||
524 | int ret; | 515 | int ret; |
525 | 516 | ||
526 | e->counters.pcnt = xt_percpu_counter_alloc(); | 517 | pcnt = xt_percpu_counter_alloc(); |
527 | if (IS_ERR_VALUE(e->counters.pcnt)) | 518 | if (IS_ERR_VALUE(pcnt)) |
528 | return -ENOMEM; | 519 | return -ENOMEM; |
520 | e->counters.pcnt = pcnt; | ||
529 | 521 | ||
530 | t = arpt_get_target(e); | 522 | t = arpt_get_target(e); |
531 | target = xt_request_find_target(NFPROTO_ARP, t->u.user.name, | 523 | target = xt_request_find_target(NFPROTO_ARP, t->u.user.name, |
@@ -642,6 +634,7 @@ static int translate_table(struct xt_table_info *newinfo, void *entry0, | |||
642 | const struct arpt_replace *repl) | 634 | const struct arpt_replace *repl) |
643 | { | 635 | { |
644 | struct arpt_entry *iter; | 636 | struct arpt_entry *iter; |
637 | unsigned int *offsets; | ||
645 | unsigned int i; | 638 | unsigned int i; |
646 | int ret = 0; | 639 | int ret = 0; |
647 | 640 | ||
@@ -655,6 +648,9 @@ static int translate_table(struct xt_table_info *newinfo, void *entry0, | |||
655 | } | 648 | } |
656 | 649 | ||
657 | duprintf("translate_table: size %u\n", newinfo->size); | 650 | duprintf("translate_table: size %u\n", newinfo->size); |
651 | offsets = xt_alloc_entry_offsets(newinfo->number); | ||
652 | if (!offsets) | ||
653 | return -ENOMEM; | ||
658 | i = 0; | 654 | i = 0; |
659 | 655 | ||
660 | /* Walk through entries, checking offsets. */ | 656 | /* Walk through entries, checking offsets. */ |
@@ -665,7 +661,9 @@ static int translate_table(struct xt_table_info *newinfo, void *entry0, | |||
665 | repl->underflow, | 661 | repl->underflow, |
666 | repl->valid_hooks); | 662 | repl->valid_hooks); |
667 | if (ret != 0) | 663 | if (ret != 0) |
668 | break; | 664 | goto out_free; |
665 | if (i < repl->num_entries) | ||
666 | offsets[i] = (void *)iter - entry0; | ||
669 | ++i; | 667 | ++i; |
670 | if (strcmp(arpt_get_target(iter)->u.user.name, | 668 | if (strcmp(arpt_get_target(iter)->u.user.name, |
671 | XT_ERROR_TARGET) == 0) | 669 | XT_ERROR_TARGET) == 0) |
@@ -673,12 +671,13 @@ static int translate_table(struct xt_table_info *newinfo, void *entry0, | |||
673 | } | 671 | } |
674 | duprintf("translate_table: ARPT_ENTRY_ITERATE gives %d\n", ret); | 672 | duprintf("translate_table: ARPT_ENTRY_ITERATE gives %d\n", ret); |
675 | if (ret != 0) | 673 | if (ret != 0) |
676 | return ret; | 674 | goto out_free; |
677 | 675 | ||
676 | ret = -EINVAL; | ||
678 | if (i != repl->num_entries) { | 677 | if (i != repl->num_entries) { |
679 | duprintf("translate_table: %u not %u entries\n", | 678 | duprintf("translate_table: %u not %u entries\n", |
680 | i, repl->num_entries); | 679 | i, repl->num_entries); |
681 | return -EINVAL; | 680 | goto out_free; |
682 | } | 681 | } |
683 | 682 | ||
684 | /* Check hooks all assigned */ | 683 | /* Check hooks all assigned */ |
@@ -689,17 +688,20 @@ static int translate_table(struct xt_table_info *newinfo, void *entry0, | |||
689 | if (newinfo->hook_entry[i] == 0xFFFFFFFF) { | 688 | if (newinfo->hook_entry[i] == 0xFFFFFFFF) { |
690 | duprintf("Invalid hook entry %u %u\n", | 689 | duprintf("Invalid hook entry %u %u\n", |
691 | i, repl->hook_entry[i]); | 690 | i, repl->hook_entry[i]); |
692 | return -EINVAL; | 691 | goto out_free; |
693 | } | 692 | } |
694 | if (newinfo->underflow[i] == 0xFFFFFFFF) { | 693 | if (newinfo->underflow[i] == 0xFFFFFFFF) { |
695 | duprintf("Invalid underflow %u %u\n", | 694 | duprintf("Invalid underflow %u %u\n", |
696 | i, repl->underflow[i]); | 695 | i, repl->underflow[i]); |
697 | return -EINVAL; | 696 | goto out_free; |
698 | } | 697 | } |
699 | } | 698 | } |
700 | 699 | ||
701 | if (!mark_source_chains(newinfo, repl->valid_hooks, entry0)) | 700 | if (!mark_source_chains(newinfo, repl->valid_hooks, entry0, offsets)) { |
702 | return -ELOOP; | 701 | ret = -ELOOP; |
702 | goto out_free; | ||
703 | } | ||
704 | kvfree(offsets); | ||
703 | 705 | ||
704 | /* Finally, each sanity check must pass */ | 706 | /* Finally, each sanity check must pass */ |
705 | i = 0; | 707 | i = 0; |
@@ -720,6 +722,9 @@ static int translate_table(struct xt_table_info *newinfo, void *entry0, | |||
720 | } | 722 | } |
721 | 723 | ||
722 | return ret; | 724 | return ret; |
725 | out_free: | ||
726 | kvfree(offsets); | ||
727 | return ret; | ||
723 | } | 728 | } |
724 | 729 | ||
725 | static void get_counters(const struct xt_table_info *t, | 730 | static void get_counters(const struct xt_table_info *t, |
@@ -1336,8 +1341,8 @@ static int translate_compat_table(struct xt_table_info **pinfo, | |||
1336 | 1341 | ||
1337 | newinfo->number = compatr->num_entries; | 1342 | newinfo->number = compatr->num_entries; |
1338 | for (i = 0; i < NF_ARP_NUMHOOKS; i++) { | 1343 | for (i = 0; i < NF_ARP_NUMHOOKS; i++) { |
1339 | newinfo->hook_entry[i] = info->hook_entry[i]; | 1344 | newinfo->hook_entry[i] = compatr->hook_entry[i]; |
1340 | newinfo->underflow[i] = info->underflow[i]; | 1345 | newinfo->underflow[i] = compatr->underflow[i]; |
1341 | } | 1346 | } |
1342 | entry1 = newinfo->entries; | 1347 | entry1 = newinfo->entries; |
1343 | pos = entry1; | 1348 | pos = entry1; |