diff options
author | David S. Miller <davem@davemloft.net> | 2010-02-24 21:23:37 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-02-24 21:23:37 -0500 |
commit | 54831a83bfe656c4c54e287c734c6b0ccaa3719b (patch) | |
tree | abd5bef16d1a6011f629a36d4e245a2ed4f3df3c /net/ipv4 | |
parent | fb977e2ca607a7e74946a1de798f474d1b80b9d6 (diff) | |
parent | 0f234214d15fa914436d304ecf5c3e43449e79f9 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/kaber/nf-next-2.6
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/netfilter/arp_tables.c | 301 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_tables.c | 436 |
2 files changed, 349 insertions, 388 deletions
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 4db5c1ece0f..57098dcda29 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c | |||
@@ -512,8 +512,7 @@ static inline int check_target(struct arpt_entry *e, const char *name) | |||
512 | } | 512 | } |
513 | 513 | ||
514 | static inline int | 514 | static inline int |
515 | find_check_entry(struct arpt_entry *e, const char *name, unsigned int size, | 515 | find_check_entry(struct arpt_entry *e, const char *name, unsigned int size) |
516 | unsigned int *i) | ||
517 | { | 516 | { |
518 | struct arpt_entry_target *t; | 517 | struct arpt_entry_target *t; |
519 | struct xt_target *target; | 518 | struct xt_target *target; |
@@ -538,8 +537,6 @@ find_check_entry(struct arpt_entry *e, const char *name, unsigned int size, | |||
538 | ret = check_target(e, name); | 537 | ret = check_target(e, name); |
539 | if (ret) | 538 | if (ret) |
540 | goto err; | 539 | goto err; |
541 | |||
542 | (*i)++; | ||
543 | return 0; | 540 | return 0; |
544 | err: | 541 | err: |
545 | module_put(t->u.kernel.target->me); | 542 | module_put(t->u.kernel.target->me); |
@@ -568,8 +565,7 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e, | |||
568 | const unsigned char *limit, | 565 | const unsigned char *limit, |
569 | const unsigned int *hook_entries, | 566 | const unsigned int *hook_entries, |
570 | const unsigned int *underflows, | 567 | const unsigned int *underflows, |
571 | unsigned int valid_hooks, | 568 | unsigned int valid_hooks) |
572 | unsigned int *i) | ||
573 | { | 569 | { |
574 | unsigned int h; | 570 | unsigned int h; |
575 | 571 | ||
@@ -606,19 +602,14 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e, | |||
606 | /* Clear counters and comefrom */ | 602 | /* Clear counters and comefrom */ |
607 | e->counters = ((struct xt_counters) { 0, 0 }); | 603 | e->counters = ((struct xt_counters) { 0, 0 }); |
608 | e->comefrom = 0; | 604 | e->comefrom = 0; |
609 | |||
610 | (*i)++; | ||
611 | return 0; | 605 | return 0; |
612 | } | 606 | } |
613 | 607 | ||
614 | static inline int cleanup_entry(struct arpt_entry *e, unsigned int *i) | 608 | static inline void cleanup_entry(struct arpt_entry *e) |
615 | { | 609 | { |
616 | struct xt_tgdtor_param par; | 610 | struct xt_tgdtor_param par; |
617 | struct arpt_entry_target *t; | 611 | struct arpt_entry_target *t; |
618 | 612 | ||
619 | if (i && (*i)-- == 0) | ||
620 | return 1; | ||
621 | |||
622 | t = arpt_get_target(e); | 613 | t = arpt_get_target(e); |
623 | par.target = t->u.kernel.target; | 614 | par.target = t->u.kernel.target; |
624 | par.targinfo = t->data; | 615 | par.targinfo = t->data; |
@@ -626,26 +617,20 @@ static inline int cleanup_entry(struct arpt_entry *e, unsigned int *i) | |||
626 | if (par.target->destroy != NULL) | 617 | if (par.target->destroy != NULL) |
627 | par.target->destroy(&par); | 618 | par.target->destroy(&par); |
628 | module_put(par.target->me); | 619 | module_put(par.target->me); |
629 | return 0; | ||
630 | } | 620 | } |
631 | 621 | ||
632 | /* Checks and translates the user-supplied table segment (held in | 622 | /* Checks and translates the user-supplied table segment (held in |
633 | * newinfo). | 623 | * newinfo). |
634 | */ | 624 | */ |
635 | static int translate_table(const char *name, | 625 | static int translate_table(struct xt_table_info *newinfo, void *entry0, |
636 | unsigned int valid_hooks, | 626 | const struct arpt_replace *repl) |
637 | struct xt_table_info *newinfo, | ||
638 | void *entry0, | ||
639 | unsigned int size, | ||
640 | unsigned int number, | ||
641 | const unsigned int *hook_entries, | ||
642 | const unsigned int *underflows) | ||
643 | { | 627 | { |
628 | struct arpt_entry *iter; | ||
644 | unsigned int i; | 629 | unsigned int i; |
645 | int ret; | 630 | int ret = 0; |
646 | 631 | ||
647 | newinfo->size = size; | 632 | newinfo->size = repl->size; |
648 | newinfo->number = number; | 633 | newinfo->number = repl->num_entries; |
649 | 634 | ||
650 | /* Init all hooks to impossible value. */ | 635 | /* Init all hooks to impossible value. */ |
651 | for (i = 0; i < NF_ARP_NUMHOOKS; i++) { | 636 | for (i = 0; i < NF_ARP_NUMHOOKS; i++) { |
@@ -657,52 +642,61 @@ static int translate_table(const char *name, | |||
657 | i = 0; | 642 | i = 0; |
658 | 643 | ||
659 | /* Walk through entries, checking offsets. */ | 644 | /* Walk through entries, checking offsets. */ |
660 | ret = ARPT_ENTRY_ITERATE(entry0, newinfo->size, | 645 | xt_entry_foreach(iter, entry0, newinfo->size) { |
661 | check_entry_size_and_hooks, | 646 | ret = check_entry_size_and_hooks(iter, newinfo, entry0, |
662 | newinfo, | 647 | entry0 + repl->size, repl->hook_entry, repl->underflow, |
663 | entry0, | 648 | repl->valid_hooks); |
664 | entry0 + size, | 649 | if (ret != 0) |
665 | hook_entries, underflows, valid_hooks, &i); | 650 | break; |
651 | ++i; | ||
652 | } | ||
666 | duprintf("translate_table: ARPT_ENTRY_ITERATE gives %d\n", ret); | 653 | duprintf("translate_table: ARPT_ENTRY_ITERATE gives %d\n", ret); |
667 | if (ret != 0) | 654 | if (ret != 0) |
668 | return ret; | 655 | return ret; |
669 | 656 | ||
670 | if (i != number) { | 657 | if (i != repl->num_entries) { |
671 | duprintf("translate_table: %u not %u entries\n", | 658 | duprintf("translate_table: %u not %u entries\n", |
672 | i, number); | 659 | i, repl->num_entries); |
673 | return -EINVAL; | 660 | return -EINVAL; |
674 | } | 661 | } |
675 | 662 | ||
676 | /* Check hooks all assigned */ | 663 | /* Check hooks all assigned */ |
677 | for (i = 0; i < NF_ARP_NUMHOOKS; i++) { | 664 | for (i = 0; i < NF_ARP_NUMHOOKS; i++) { |
678 | /* Only hooks which are valid */ | 665 | /* Only hooks which are valid */ |
679 | if (!(valid_hooks & (1 << i))) | 666 | if (!(repl->valid_hooks & (1 << i))) |
680 | continue; | 667 | continue; |
681 | if (newinfo->hook_entry[i] == 0xFFFFFFFF) { | 668 | if (newinfo->hook_entry[i] == 0xFFFFFFFF) { |
682 | duprintf("Invalid hook entry %u %u\n", | 669 | duprintf("Invalid hook entry %u %u\n", |
683 | i, hook_entries[i]); | 670 | i, repl->hook_entry[i]); |
684 | return -EINVAL; | 671 | return -EINVAL; |
685 | } | 672 | } |
686 | if (newinfo->underflow[i] == 0xFFFFFFFF) { | 673 | if (newinfo->underflow[i] == 0xFFFFFFFF) { |
687 | duprintf("Invalid underflow %u %u\n", | 674 | duprintf("Invalid underflow %u %u\n", |
688 | i, underflows[i]); | 675 | i, repl->underflow[i]); |
689 | return -EINVAL; | 676 | return -EINVAL; |
690 | } | 677 | } |
691 | } | 678 | } |
692 | 679 | ||
693 | if (!mark_source_chains(newinfo, valid_hooks, entry0)) { | 680 | if (!mark_source_chains(newinfo, repl->valid_hooks, entry0)) { |
694 | duprintf("Looping hook\n"); | 681 | duprintf("Looping hook\n"); |
695 | return -ELOOP; | 682 | return -ELOOP; |
696 | } | 683 | } |
697 | 684 | ||
698 | /* Finally, each sanity check must pass */ | 685 | /* Finally, each sanity check must pass */ |
699 | i = 0; | 686 | i = 0; |
700 | ret = ARPT_ENTRY_ITERATE(entry0, newinfo->size, | 687 | xt_entry_foreach(iter, entry0, newinfo->size) { |
701 | find_check_entry, name, size, &i); | 688 | ret = find_check_entry(iter, repl->name, repl->size); |
689 | if (ret != 0) | ||
690 | break; | ||
691 | ++i; | ||
692 | } | ||
702 | 693 | ||
703 | if (ret != 0) { | 694 | if (ret != 0) { |
704 | ARPT_ENTRY_ITERATE(entry0, newinfo->size, | 695 | xt_entry_foreach(iter, entry0, newinfo->size) { |
705 | cleanup_entry, &i); | 696 | if (i-- == 0) |
697 | break; | ||
698 | cleanup_entry(iter); | ||
699 | } | ||
706 | return ret; | 700 | return ret; |
707 | } | 701 | } |
708 | 702 | ||
@@ -715,30 +709,10 @@ static int translate_table(const char *name, | |||
715 | return ret; | 709 | return ret; |
716 | } | 710 | } |
717 | 711 | ||
718 | /* Gets counters. */ | ||
719 | static inline int add_entry_to_counter(const struct arpt_entry *e, | ||
720 | struct xt_counters total[], | ||
721 | unsigned int *i) | ||
722 | { | ||
723 | ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); | ||
724 | |||
725 | (*i)++; | ||
726 | return 0; | ||
727 | } | ||
728 | |||
729 | static inline int set_entry_to_counter(const struct arpt_entry *e, | ||
730 | struct xt_counters total[], | ||
731 | unsigned int *i) | ||
732 | { | ||
733 | SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); | ||
734 | |||
735 | (*i)++; | ||
736 | return 0; | ||
737 | } | ||
738 | |||
739 | static void get_counters(const struct xt_table_info *t, | 712 | static void get_counters(const struct xt_table_info *t, |
740 | struct xt_counters counters[]) | 713 | struct xt_counters counters[]) |
741 | { | 714 | { |
715 | struct arpt_entry *iter; | ||
742 | unsigned int cpu; | 716 | unsigned int cpu; |
743 | unsigned int i; | 717 | unsigned int i; |
744 | unsigned int curcpu; | 718 | unsigned int curcpu; |
@@ -754,22 +728,22 @@ static void get_counters(const struct xt_table_info *t, | |||
754 | curcpu = smp_processor_id(); | 728 | curcpu = smp_processor_id(); |
755 | 729 | ||
756 | i = 0; | 730 | i = 0; |
757 | ARPT_ENTRY_ITERATE(t->entries[curcpu], | 731 | xt_entry_foreach(iter, t->entries[curcpu], t->size) { |
758 | t->size, | 732 | SET_COUNTER(counters[i], iter->counters.bcnt, |
759 | set_entry_to_counter, | 733 | iter->counters.pcnt); |
760 | counters, | 734 | ++i; |
761 | &i); | 735 | } |
762 | 736 | ||
763 | for_each_possible_cpu(cpu) { | 737 | for_each_possible_cpu(cpu) { |
764 | if (cpu == curcpu) | 738 | if (cpu == curcpu) |
765 | continue; | 739 | continue; |
766 | i = 0; | 740 | i = 0; |
767 | xt_info_wrlock(cpu); | 741 | xt_info_wrlock(cpu); |
768 | ARPT_ENTRY_ITERATE(t->entries[cpu], | 742 | xt_entry_foreach(iter, t->entries[cpu], t->size) { |
769 | t->size, | 743 | ADD_COUNTER(counters[i], iter->counters.bcnt, |
770 | add_entry_to_counter, | 744 | iter->counters.pcnt); |
771 | counters, | 745 | ++i; |
772 | &i); | 746 | } |
773 | xt_info_wrunlock(cpu); | 747 | xt_info_wrunlock(cpu); |
774 | } | 748 | } |
775 | local_bh_enable(); | 749 | local_bh_enable(); |
@@ -899,7 +873,9 @@ static int compat_calc_entry(const struct arpt_entry *e, | |||
899 | static int compat_table_info(const struct xt_table_info *info, | 873 | static int compat_table_info(const struct xt_table_info *info, |
900 | struct xt_table_info *newinfo) | 874 | struct xt_table_info *newinfo) |
901 | { | 875 | { |
876 | struct arpt_entry *iter; | ||
902 | void *loc_cpu_entry; | 877 | void *loc_cpu_entry; |
878 | int ret; | ||
903 | 879 | ||
904 | if (!newinfo || !info) | 880 | if (!newinfo || !info) |
905 | return -EINVAL; | 881 | return -EINVAL; |
@@ -908,9 +884,12 @@ static int compat_table_info(const struct xt_table_info *info, | |||
908 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); | 884 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); |
909 | newinfo->initial_entries = 0; | 885 | newinfo->initial_entries = 0; |
910 | loc_cpu_entry = info->entries[raw_smp_processor_id()]; | 886 | loc_cpu_entry = info->entries[raw_smp_processor_id()]; |
911 | return ARPT_ENTRY_ITERATE(loc_cpu_entry, info->size, | 887 | xt_entry_foreach(iter, loc_cpu_entry, info->size) { |
912 | compat_calc_entry, info, loc_cpu_entry, | 888 | ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo); |
913 | newinfo); | 889 | if (ret != 0) |
890 | return ret; | ||
891 | } | ||
892 | return 0; | ||
914 | } | 893 | } |
915 | #endif | 894 | #endif |
916 | 895 | ||
@@ -1025,6 +1004,7 @@ static int __do_replace(struct net *net, const char *name, | |||
1025 | struct xt_table_info *oldinfo; | 1004 | struct xt_table_info *oldinfo; |
1026 | struct xt_counters *counters; | 1005 | struct xt_counters *counters; |
1027 | void *loc_cpu_old_entry; | 1006 | void *loc_cpu_old_entry; |
1007 | struct arpt_entry *iter; | ||
1028 | 1008 | ||
1029 | ret = 0; | 1009 | ret = 0; |
1030 | counters = vmalloc_node(num_counters * sizeof(struct xt_counters), | 1010 | counters = vmalloc_node(num_counters * sizeof(struct xt_counters), |
@@ -1068,8 +1048,8 @@ static int __do_replace(struct net *net, const char *name, | |||
1068 | 1048 | ||
1069 | /* Decrease module usage counts and free resource */ | 1049 | /* Decrease module usage counts and free resource */ |
1070 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; | 1050 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; |
1071 | ARPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry, | 1051 | xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size) |
1072 | NULL); | 1052 | cleanup_entry(iter); |
1073 | 1053 | ||
1074 | xt_free_table_info(oldinfo); | 1054 | xt_free_table_info(oldinfo); |
1075 | if (copy_to_user(counters_ptr, counters, | 1055 | if (copy_to_user(counters_ptr, counters, |
@@ -1095,6 +1075,7 @@ static int do_replace(struct net *net, const void __user *user, | |||
1095 | struct arpt_replace tmp; | 1075 | struct arpt_replace tmp; |
1096 | struct xt_table_info *newinfo; | 1076 | struct xt_table_info *newinfo; |
1097 | void *loc_cpu_entry; | 1077 | void *loc_cpu_entry; |
1078 | struct arpt_entry *iter; | ||
1098 | 1079 | ||
1099 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) | 1080 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) |
1100 | return -EFAULT; | 1081 | return -EFAULT; |
@@ -1115,9 +1096,7 @@ static int do_replace(struct net *net, const void __user *user, | |||
1115 | goto free_newinfo; | 1096 | goto free_newinfo; |
1116 | } | 1097 | } |
1117 | 1098 | ||
1118 | ret = translate_table(tmp.name, tmp.valid_hooks, | 1099 | ret = translate_table(newinfo, loc_cpu_entry, &tmp); |
1119 | newinfo, loc_cpu_entry, tmp.size, tmp.num_entries, | ||
1120 | tmp.hook_entry, tmp.underflow); | ||
1121 | if (ret != 0) | 1100 | if (ret != 0) |
1122 | goto free_newinfo; | 1101 | goto free_newinfo; |
1123 | 1102 | ||
@@ -1130,25 +1109,13 @@ static int do_replace(struct net *net, const void __user *user, | |||
1130 | return 0; | 1109 | return 0; |
1131 | 1110 | ||
1132 | free_newinfo_untrans: | 1111 | free_newinfo_untrans: |
1133 | ARPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL); | 1112 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) |
1113 | cleanup_entry(iter); | ||
1134 | free_newinfo: | 1114 | free_newinfo: |
1135 | xt_free_table_info(newinfo); | 1115 | xt_free_table_info(newinfo); |
1136 | return ret; | 1116 | return ret; |
1137 | } | 1117 | } |
1138 | 1118 | ||
1139 | /* We're lazy, and add to the first CPU; overflow works its fey magic | ||
1140 | * and everything is OK. */ | ||
1141 | static int | ||
1142 | add_counter_to_entry(struct arpt_entry *e, | ||
1143 | const struct xt_counters addme[], | ||
1144 | unsigned int *i) | ||
1145 | { | ||
1146 | ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | ||
1147 | |||
1148 | (*i)++; | ||
1149 | return 0; | ||
1150 | } | ||
1151 | |||
1152 | static int do_add_counters(struct net *net, const void __user *user, | 1119 | static int do_add_counters(struct net *net, const void __user *user, |
1153 | unsigned int len, int compat) | 1120 | unsigned int len, int compat) |
1154 | { | 1121 | { |
@@ -1163,6 +1130,7 @@ static int do_add_counters(struct net *net, const void __user *user, | |||
1163 | const struct xt_table_info *private; | 1130 | const struct xt_table_info *private; |
1164 | int ret = 0; | 1131 | int ret = 0; |
1165 | void *loc_cpu_entry; | 1132 | void *loc_cpu_entry; |
1133 | struct arpt_entry *iter; | ||
1166 | #ifdef CONFIG_COMPAT | 1134 | #ifdef CONFIG_COMPAT |
1167 | struct compat_xt_counters_info compat_tmp; | 1135 | struct compat_xt_counters_info compat_tmp; |
1168 | 1136 | ||
@@ -1220,11 +1188,10 @@ static int do_add_counters(struct net *net, const void __user *user, | |||
1220 | curcpu = smp_processor_id(); | 1188 | curcpu = smp_processor_id(); |
1221 | loc_cpu_entry = private->entries[curcpu]; | 1189 | loc_cpu_entry = private->entries[curcpu]; |
1222 | xt_info_wrlock(curcpu); | 1190 | xt_info_wrlock(curcpu); |
1223 | ARPT_ENTRY_ITERATE(loc_cpu_entry, | 1191 | xt_entry_foreach(iter, loc_cpu_entry, private->size) { |
1224 | private->size, | 1192 | ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt); |
1225 | add_counter_to_entry, | 1193 | ++i; |
1226 | paddc, | 1194 | } |
1227 | &i); | ||
1228 | xt_info_wrunlock(curcpu); | 1195 | xt_info_wrunlock(curcpu); |
1229 | unlock_up_free: | 1196 | unlock_up_free: |
1230 | local_bh_enable(); | 1197 | local_bh_enable(); |
@@ -1237,17 +1204,12 @@ static int do_add_counters(struct net *net, const void __user *user, | |||
1237 | } | 1204 | } |
1238 | 1205 | ||
1239 | #ifdef CONFIG_COMPAT | 1206 | #ifdef CONFIG_COMPAT |
1240 | static inline int | 1207 | static inline void compat_release_entry(struct compat_arpt_entry *e) |
1241 | compat_release_entry(struct compat_arpt_entry *e, unsigned int *i) | ||
1242 | { | 1208 | { |
1243 | struct arpt_entry_target *t; | 1209 | struct arpt_entry_target *t; |
1244 | 1210 | ||
1245 | if (i && (*i)-- == 0) | ||
1246 | return 1; | ||
1247 | |||
1248 | t = compat_arpt_get_target(e); | 1211 | t = compat_arpt_get_target(e); |
1249 | module_put(t->u.kernel.target->me); | 1212 | module_put(t->u.kernel.target->me); |
1250 | return 0; | ||
1251 | } | 1213 | } |
1252 | 1214 | ||
1253 | static inline int | 1215 | static inline int |
@@ -1258,7 +1220,6 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e, | |||
1258 | const unsigned char *limit, | 1220 | const unsigned char *limit, |
1259 | const unsigned int *hook_entries, | 1221 | const unsigned int *hook_entries, |
1260 | const unsigned int *underflows, | 1222 | const unsigned int *underflows, |
1261 | unsigned int *i, | ||
1262 | const char *name) | 1223 | const char *name) |
1263 | { | 1224 | { |
1264 | struct arpt_entry_target *t; | 1225 | struct arpt_entry_target *t; |
@@ -1318,8 +1279,6 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e, | |||
1318 | /* Clear counters and comefrom */ | 1279 | /* Clear counters and comefrom */ |
1319 | memset(&e->counters, 0, sizeof(e->counters)); | 1280 | memset(&e->counters, 0, sizeof(e->counters)); |
1320 | e->comefrom = 0; | 1281 | e->comefrom = 0; |
1321 | |||
1322 | (*i)++; | ||
1323 | return 0; | 1282 | return 0; |
1324 | 1283 | ||
1325 | release_target: | 1284 | release_target: |
@@ -1363,19 +1322,6 @@ compat_copy_entry_from_user(struct compat_arpt_entry *e, void **dstptr, | |||
1363 | return ret; | 1322 | return ret; |
1364 | } | 1323 | } |
1365 | 1324 | ||
1366 | static inline int compat_check_entry(struct arpt_entry *e, const char *name, | ||
1367 | unsigned int *i) | ||
1368 | { | ||
1369 | int ret; | ||
1370 | |||
1371 | ret = check_target(e, name); | ||
1372 | if (ret) | ||
1373 | return ret; | ||
1374 | |||
1375 | (*i)++; | ||
1376 | return 0; | ||
1377 | } | ||
1378 | |||
1379 | static int translate_compat_table(const char *name, | 1325 | static int translate_compat_table(const char *name, |
1380 | unsigned int valid_hooks, | 1326 | unsigned int valid_hooks, |
1381 | struct xt_table_info **pinfo, | 1327 | struct xt_table_info **pinfo, |
@@ -1388,8 +1334,10 @@ static int translate_compat_table(const char *name, | |||
1388 | unsigned int i, j; | 1334 | unsigned int i, j; |
1389 | struct xt_table_info *newinfo, *info; | 1335 | struct xt_table_info *newinfo, *info; |
1390 | void *pos, *entry0, *entry1; | 1336 | void *pos, *entry0, *entry1; |
1337 | struct compat_arpt_entry *iter0; | ||
1338 | struct arpt_entry *iter1; | ||
1391 | unsigned int size; | 1339 | unsigned int size; |
1392 | int ret; | 1340 | int ret = 0; |
1393 | 1341 | ||
1394 | info = *pinfo; | 1342 | info = *pinfo; |
1395 | entry0 = *pentry0; | 1343 | entry0 = *pentry0; |
@@ -1406,13 +1354,14 @@ static int translate_compat_table(const char *name, | |||
1406 | j = 0; | 1354 | j = 0; |
1407 | xt_compat_lock(NFPROTO_ARP); | 1355 | xt_compat_lock(NFPROTO_ARP); |
1408 | /* Walk through entries, checking offsets. */ | 1356 | /* Walk through entries, checking offsets. */ |
1409 | ret = COMPAT_ARPT_ENTRY_ITERATE(entry0, total_size, | 1357 | xt_entry_foreach(iter0, entry0, total_size) { |
1410 | check_compat_entry_size_and_hooks, | 1358 | ret = check_compat_entry_size_and_hooks(iter0, info, &size, |
1411 | info, &size, entry0, | 1359 | entry0, entry0 + total_size, hook_entries, underflows, |
1412 | entry0 + total_size, | 1360 | name); |
1413 | hook_entries, underflows, &j, name); | 1361 | if (ret != 0) |
1414 | if (ret != 0) | 1362 | goto out_unlock; |
1415 | goto out_unlock; | 1363 | ++j; |
1364 | } | ||
1416 | 1365 | ||
1417 | ret = -EINVAL; | 1366 | ret = -EINVAL; |
1418 | if (j != number) { | 1367 | if (j != number) { |
@@ -1451,9 +1400,12 @@ static int translate_compat_table(const char *name, | |||
1451 | entry1 = newinfo->entries[raw_smp_processor_id()]; | 1400 | entry1 = newinfo->entries[raw_smp_processor_id()]; |
1452 | pos = entry1; | 1401 | pos = entry1; |
1453 | size = total_size; | 1402 | size = total_size; |
1454 | ret = COMPAT_ARPT_ENTRY_ITERATE(entry0, total_size, | 1403 | xt_entry_foreach(iter0, entry0, total_size) { |
1455 | compat_copy_entry_from_user, | 1404 | ret = compat_copy_entry_from_user(iter0, &pos, |
1456 | &pos, &size, name, newinfo, entry1); | 1405 | &size, name, newinfo, entry1); |
1406 | if (ret != 0) | ||
1407 | break; | ||
1408 | } | ||
1457 | xt_compat_flush_offsets(NFPROTO_ARP); | 1409 | xt_compat_flush_offsets(NFPROTO_ARP); |
1458 | xt_compat_unlock(NFPROTO_ARP); | 1410 | xt_compat_unlock(NFPROTO_ARP); |
1459 | if (ret) | 1411 | if (ret) |
@@ -1464,13 +1416,32 @@ static int translate_compat_table(const char *name, | |||
1464 | goto free_newinfo; | 1416 | goto free_newinfo; |
1465 | 1417 | ||
1466 | i = 0; | 1418 | i = 0; |
1467 | ret = ARPT_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry, | 1419 | xt_entry_foreach(iter1, entry1, newinfo->size) { |
1468 | name, &i); | 1420 | ret = check_target(iter1, name); |
1421 | if (ret != 0) | ||
1422 | break; | ||
1423 | ++i; | ||
1424 | } | ||
1469 | if (ret) { | 1425 | if (ret) { |
1426 | /* | ||
1427 | * The first i matches need cleanup_entry (calls ->destroy) | ||
1428 | * because they had called ->check already. The other j-i | ||
1429 | * entries need only release. | ||
1430 | */ | ||
1431 | int skip = i; | ||
1470 | j -= i; | 1432 | j -= i; |
1471 | COMPAT_ARPT_ENTRY_ITERATE_CONTINUE(entry0, newinfo->size, i, | 1433 | xt_entry_foreach(iter0, entry0, newinfo->size) { |
1472 | compat_release_entry, &j); | 1434 | if (skip-- > 0) |
1473 | ARPT_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, &i); | 1435 | continue; |
1436 | if (j-- == 0) | ||
1437 | break; | ||
1438 | compat_release_entry(iter0); | ||
1439 | } | ||
1440 | xt_entry_foreach(iter1, entry1, newinfo->size) { | ||
1441 | if (i-- == 0) | ||
1442 | break; | ||
1443 | cleanup_entry(iter1); | ||
1444 | } | ||
1474 | xt_free_table_info(newinfo); | 1445 | xt_free_table_info(newinfo); |
1475 | return ret; | 1446 | return ret; |
1476 | } | 1447 | } |
@@ -1488,7 +1459,11 @@ static int translate_compat_table(const char *name, | |||
1488 | free_newinfo: | 1459 | free_newinfo: |
1489 | xt_free_table_info(newinfo); | 1460 | xt_free_table_info(newinfo); |
1490 | out: | 1461 | out: |
1491 | COMPAT_ARPT_ENTRY_ITERATE(entry0, total_size, compat_release_entry, &j); | 1462 | xt_entry_foreach(iter0, entry0, total_size) { |
1463 | if (j-- == 0) | ||
1464 | break; | ||
1465 | compat_release_entry(iter0); | ||
1466 | } | ||
1492 | return ret; | 1467 | return ret; |
1493 | out_unlock: | 1468 | out_unlock: |
1494 | xt_compat_flush_offsets(NFPROTO_ARP); | 1469 | xt_compat_flush_offsets(NFPROTO_ARP); |
@@ -1515,6 +1490,7 @@ static int compat_do_replace(struct net *net, void __user *user, | |||
1515 | struct compat_arpt_replace tmp; | 1490 | struct compat_arpt_replace tmp; |
1516 | struct xt_table_info *newinfo; | 1491 | struct xt_table_info *newinfo; |
1517 | void *loc_cpu_entry; | 1492 | void *loc_cpu_entry; |
1493 | struct arpt_entry *iter; | ||
1518 | 1494 | ||
1519 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) | 1495 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) |
1520 | return -EFAULT; | 1496 | return -EFAULT; |
@@ -1552,7 +1528,8 @@ static int compat_do_replace(struct net *net, void __user *user, | |||
1552 | return 0; | 1528 | return 0; |
1553 | 1529 | ||
1554 | free_newinfo_untrans: | 1530 | free_newinfo_untrans: |
1555 | ARPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL); | 1531 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) |
1532 | cleanup_entry(iter); | ||
1556 | free_newinfo: | 1533 | free_newinfo: |
1557 | xt_free_table_info(newinfo); | 1534 | xt_free_table_info(newinfo); |
1558 | return ret; | 1535 | return ret; |
@@ -1586,7 +1563,7 @@ static int compat_do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, | |||
1586 | static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, | 1563 | static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, |
1587 | compat_uint_t *size, | 1564 | compat_uint_t *size, |
1588 | struct xt_counters *counters, | 1565 | struct xt_counters *counters, |
1589 | unsigned int *i) | 1566 | unsigned int i) |
1590 | { | 1567 | { |
1591 | struct arpt_entry_target *t; | 1568 | struct arpt_entry_target *t; |
1592 | struct compat_arpt_entry __user *ce; | 1569 | struct compat_arpt_entry __user *ce; |
@@ -1594,14 +1571,12 @@ static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, | |||
1594 | compat_uint_t origsize; | 1571 | compat_uint_t origsize; |
1595 | int ret; | 1572 | int ret; |
1596 | 1573 | ||
1597 | ret = -EFAULT; | ||
1598 | origsize = *size; | 1574 | origsize = *size; |
1599 | ce = (struct compat_arpt_entry __user *)*dstptr; | 1575 | ce = (struct compat_arpt_entry __user *)*dstptr; |
1600 | if (copy_to_user(ce, e, sizeof(struct arpt_entry))) | 1576 | if (copy_to_user(ce, e, sizeof(struct arpt_entry)) != 0 || |
1601 | goto out; | 1577 | copy_to_user(&ce->counters, &counters[i], |
1602 | 1578 | sizeof(counters[i])) != 0) | |
1603 | if (copy_to_user(&ce->counters, &counters[*i], sizeof(counters[*i]))) | 1579 | return -EFAULT; |
1604 | goto out; | ||
1605 | 1580 | ||
1606 | *dstptr += sizeof(struct compat_arpt_entry); | 1581 | *dstptr += sizeof(struct compat_arpt_entry); |
1607 | *size -= sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry); | 1582 | *size -= sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry); |
@@ -1611,18 +1586,12 @@ static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, | |||
1611 | t = arpt_get_target(e); | 1586 | t = arpt_get_target(e); |
1612 | ret = xt_compat_target_to_user(t, dstptr, size); | 1587 | ret = xt_compat_target_to_user(t, dstptr, size); |
1613 | if (ret) | 1588 | if (ret) |
1614 | goto out; | 1589 | return ret; |
1615 | ret = -EFAULT; | ||
1616 | next_offset = e->next_offset - (origsize - *size); | 1590 | next_offset = e->next_offset - (origsize - *size); |
1617 | if (put_user(target_offset, &ce->target_offset)) | 1591 | if (put_user(target_offset, &ce->target_offset) != 0 || |
1618 | goto out; | 1592 | put_user(next_offset, &ce->next_offset) != 0) |
1619 | if (put_user(next_offset, &ce->next_offset)) | 1593 | return -EFAULT; |
1620 | goto out; | ||
1621 | |||
1622 | (*i)++; | ||
1623 | return 0; | 1594 | return 0; |
1624 | out: | ||
1625 | return ret; | ||
1626 | } | 1595 | } |
1627 | 1596 | ||
1628 | static int compat_copy_entries_to_user(unsigned int total_size, | 1597 | static int compat_copy_entries_to_user(unsigned int total_size, |
@@ -1636,6 +1605,7 @@ static int compat_copy_entries_to_user(unsigned int total_size, | |||
1636 | int ret = 0; | 1605 | int ret = 0; |
1637 | void *loc_cpu_entry; | 1606 | void *loc_cpu_entry; |
1638 | unsigned int i = 0; | 1607 | unsigned int i = 0; |
1608 | struct arpt_entry *iter; | ||
1639 | 1609 | ||
1640 | counters = alloc_counters(table); | 1610 | counters = alloc_counters(table); |
1641 | if (IS_ERR(counters)) | 1611 | if (IS_ERR(counters)) |
@@ -1645,9 +1615,12 @@ static int compat_copy_entries_to_user(unsigned int total_size, | |||
1645 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; | 1615 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; |
1646 | pos = userptr; | 1616 | pos = userptr; |
1647 | size = total_size; | 1617 | size = total_size; |
1648 | ret = ARPT_ENTRY_ITERATE(loc_cpu_entry, total_size, | 1618 | xt_entry_foreach(iter, loc_cpu_entry, total_size) { |
1649 | compat_copy_entry_to_user, | 1619 | ret = compat_copy_entry_to_user(iter, &pos, |
1650 | &pos, &size, counters, &i); | 1620 | &size, counters, i++); |
1621 | if (ret != 0) | ||
1622 | break; | ||
1623 | } | ||
1651 | vfree(counters); | 1624 | vfree(counters); |
1652 | return ret; | 1625 | return ret; |
1653 | } | 1626 | } |
@@ -1815,12 +1788,7 @@ struct xt_table *arpt_register_table(struct net *net, | |||
1815 | loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; | 1788 | loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; |
1816 | memcpy(loc_cpu_entry, repl->entries, repl->size); | 1789 | memcpy(loc_cpu_entry, repl->entries, repl->size); |
1817 | 1790 | ||
1818 | ret = translate_table(table->name, table->valid_hooks, | 1791 | ret = translate_table(newinfo, loc_cpu_entry, repl); |
1819 | newinfo, loc_cpu_entry, repl->size, | ||
1820 | repl->num_entries, | ||
1821 | repl->hook_entry, | ||
1822 | repl->underflow); | ||
1823 | |||
1824 | duprintf("arpt_register_table: translate table gives %d\n", ret); | 1792 | duprintf("arpt_register_table: translate table gives %d\n", ret); |
1825 | if (ret != 0) | 1793 | if (ret != 0) |
1826 | goto out_free; | 1794 | goto out_free; |
@@ -1843,13 +1811,14 @@ void arpt_unregister_table(struct xt_table *table) | |||
1843 | struct xt_table_info *private; | 1811 | struct xt_table_info *private; |
1844 | void *loc_cpu_entry; | 1812 | void *loc_cpu_entry; |
1845 | struct module *table_owner = table->me; | 1813 | struct module *table_owner = table->me; |
1814 | struct arpt_entry *iter; | ||
1846 | 1815 | ||
1847 | private = xt_unregister_table(table); | 1816 | private = xt_unregister_table(table); |
1848 | 1817 | ||
1849 | /* Decrease module usage counts and free resources */ | 1818 | /* Decrease module usage counts and free resources */ |
1850 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; | 1819 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; |
1851 | ARPT_ENTRY_ITERATE(loc_cpu_entry, private->size, | 1820 | xt_entry_foreach(iter, loc_cpu_entry, private->size) |
1852 | cleanup_entry, NULL); | 1821 | cleanup_entry(iter); |
1853 | if (private->number > private->initial_entries) | 1822 | if (private->number > private->initial_entries) |
1854 | module_put(table_owner); | 1823 | module_put(table_owner); |
1855 | xt_free_table_info(private); | 1824 | xt_free_table_info(private); |
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index e94c18bdfc6..c92f4e541cf 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c | |||
@@ -288,6 +288,7 @@ static void trace_packet(const struct sk_buff *skb, | |||
288 | const void *table_base; | 288 | const void *table_base; |
289 | const struct ipt_entry *root; | 289 | const struct ipt_entry *root; |
290 | const char *hookname, *chainname, *comment; | 290 | const char *hookname, *chainname, *comment; |
291 | const struct ipt_entry *iter; | ||
291 | unsigned int rulenum = 0; | 292 | unsigned int rulenum = 0; |
292 | 293 | ||
293 | table_base = private->entries[smp_processor_id()]; | 294 | table_base = private->entries[smp_processor_id()]; |
@@ -296,10 +297,10 @@ static void trace_packet(const struct sk_buff *skb, | |||
296 | hookname = chainname = hooknames[hook]; | 297 | hookname = chainname = hooknames[hook]; |
297 | comment = comments[NF_IP_TRACE_COMMENT_RULE]; | 298 | comment = comments[NF_IP_TRACE_COMMENT_RULE]; |
298 | 299 | ||
299 | IPT_ENTRY_ITERATE(root, | 300 | xt_entry_foreach(iter, root, private->size - private->hook_entry[hook]) |
300 | private->size - private->hook_entry[hook], | 301 | if (get_chainname_rulenum(iter, e, hookname, |
301 | get_chainname_rulenum, | 302 | &chainname, &comment, &rulenum) != 0) |
302 | e, hookname, &chainname, &comment, &rulenum); | 303 | break; |
303 | 304 | ||
304 | nf_log_packet(AF_INET, hook, skb, in, out, &trace_loginfo, | 305 | nf_log_packet(AF_INET, hook, skb, in, out, &trace_loginfo, |
305 | "TRACE: %s:%s:%s:%u ", | 306 | "TRACE: %s:%s:%s:%u ", |
@@ -365,16 +366,21 @@ ipt_do_table(struct sk_buff *skb, | |||
365 | 366 | ||
366 | do { | 367 | do { |
367 | const struct ipt_entry_target *t; | 368 | const struct ipt_entry_target *t; |
369 | const struct xt_entry_match *ematch; | ||
368 | 370 | ||
369 | IP_NF_ASSERT(e); | 371 | IP_NF_ASSERT(e); |
370 | IP_NF_ASSERT(back); | 372 | IP_NF_ASSERT(back); |
371 | if (!ip_packet_match(ip, indev, outdev, | 373 | if (!ip_packet_match(ip, indev, outdev, |
372 | &e->ip, mtpar.fragoff) || | 374 | &e->ip, mtpar.fragoff)) { |
373 | IPT_MATCH_ITERATE(e, do_match, skb, &mtpar) != 0) { | 375 | no_match: |
374 | e = ipt_next_entry(e); | 376 | e = ipt_next_entry(e); |
375 | continue; | 377 | continue; |
376 | } | 378 | } |
377 | 379 | ||
380 | xt_ematch_foreach(ematch, e) | ||
381 | if (do_match(ematch, skb, &mtpar) != 0) | ||
382 | goto no_match; | ||
383 | |||
378 | ADD_COUNTER(e->counters, ntohs(ip->tot_len), 1); | 384 | ADD_COUNTER(e->counters, ntohs(ip->tot_len), 1); |
379 | 385 | ||
380 | t = ipt_get_target(e); | 386 | t = ipt_get_target(e); |
@@ -566,14 +572,10 @@ mark_source_chains(const struct xt_table_info *newinfo, | |||
566 | return 1; | 572 | return 1; |
567 | } | 573 | } |
568 | 574 | ||
569 | static int | 575 | static void cleanup_match(struct ipt_entry_match *m, struct net *net) |
570 | cleanup_match(struct ipt_entry_match *m, struct net *net, unsigned int *i) | ||
571 | { | 576 | { |
572 | struct xt_mtdtor_param par; | 577 | struct xt_mtdtor_param par; |
573 | 578 | ||
574 | if (i && (*i)-- == 0) | ||
575 | return 1; | ||
576 | |||
577 | par.net = net; | 579 | par.net = net; |
578 | par.match = m->u.kernel.match; | 580 | par.match = m->u.kernel.match; |
579 | par.matchinfo = m->data; | 581 | par.matchinfo = m->data; |
@@ -581,7 +583,6 @@ cleanup_match(struct ipt_entry_match *m, struct net *net, unsigned int *i) | |||
581 | if (par.match->destroy != NULL) | 583 | if (par.match->destroy != NULL) |
582 | par.match->destroy(&par); | 584 | par.match->destroy(&par); |
583 | module_put(par.match->me); | 585 | module_put(par.match->me); |
584 | return 0; | ||
585 | } | 586 | } |
586 | 587 | ||
587 | static int | 588 | static int |
@@ -606,8 +607,7 @@ check_entry(const struct ipt_entry *e, const char *name) | |||
606 | } | 607 | } |
607 | 608 | ||
608 | static int | 609 | static int |
609 | check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par, | 610 | check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par) |
610 | unsigned int *i) | ||
611 | { | 611 | { |
612 | const struct ipt_ip *ip = par->entryinfo; | 612 | const struct ipt_ip *ip = par->entryinfo; |
613 | int ret; | 613 | int ret; |
@@ -622,13 +622,11 @@ check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par, | |||
622 | par.match->name); | 622 | par.match->name); |
623 | return ret; | 623 | return ret; |
624 | } | 624 | } |
625 | ++*i; | ||
626 | return 0; | 625 | return 0; |
627 | } | 626 | } |
628 | 627 | ||
629 | static int | 628 | static int |
630 | find_check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par, | 629 | find_check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par) |
631 | unsigned int *i) | ||
632 | { | 630 | { |
633 | struct xt_match *match; | 631 | struct xt_match *match; |
634 | int ret; | 632 | int ret; |
@@ -642,7 +640,7 @@ find_check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par, | |||
642 | } | 640 | } |
643 | m->u.kernel.match = match; | 641 | m->u.kernel.match = match; |
644 | 642 | ||
645 | ret = check_match(m, par, i); | 643 | ret = check_match(m, par); |
646 | if (ret) | 644 | if (ret) |
647 | goto err; | 645 | goto err; |
648 | 646 | ||
@@ -678,13 +676,14 @@ static int check_target(struct ipt_entry *e, struct net *net, const char *name) | |||
678 | 676 | ||
679 | static int | 677 | static int |
680 | find_check_entry(struct ipt_entry *e, struct net *net, const char *name, | 678 | find_check_entry(struct ipt_entry *e, struct net *net, const char *name, |
681 | unsigned int size, unsigned int *i) | 679 | unsigned int size) |
682 | { | 680 | { |
683 | struct ipt_entry_target *t; | 681 | struct ipt_entry_target *t; |
684 | struct xt_target *target; | 682 | struct xt_target *target; |
685 | int ret; | 683 | int ret; |
686 | unsigned int j; | 684 | unsigned int j; |
687 | struct xt_mtchk_param mtpar; | 685 | struct xt_mtchk_param mtpar; |
686 | struct xt_entry_match *ematch; | ||
688 | 687 | ||
689 | ret = check_entry(e, name); | 688 | ret = check_entry(e, name); |
690 | if (ret) | 689 | if (ret) |
@@ -696,9 +695,12 @@ find_check_entry(struct ipt_entry *e, struct net *net, const char *name, | |||
696 | mtpar.entryinfo = &e->ip; | 695 | mtpar.entryinfo = &e->ip; |
697 | mtpar.hook_mask = e->comefrom; | 696 | mtpar.hook_mask = e->comefrom; |
698 | mtpar.family = NFPROTO_IPV4; | 697 | mtpar.family = NFPROTO_IPV4; |
699 | ret = IPT_MATCH_ITERATE(e, find_check_match, &mtpar, &j); | 698 | xt_ematch_foreach(ematch, e) { |
700 | if (ret != 0) | 699 | ret = find_check_match(ematch, &mtpar); |
701 | goto cleanup_matches; | 700 | if (ret != 0) |
701 | goto cleanup_matches; | ||
702 | ++j; | ||
703 | } | ||
702 | 704 | ||
703 | t = ipt_get_target(e); | 705 | t = ipt_get_target(e); |
704 | target = try_then_request_module(xt_find_target(AF_INET, | 706 | target = try_then_request_module(xt_find_target(AF_INET, |
@@ -715,13 +717,15 @@ find_check_entry(struct ipt_entry *e, struct net *net, const char *name, | |||
715 | ret = check_target(e, net, name); | 717 | ret = check_target(e, net, name); |
716 | if (ret) | 718 | if (ret) |
717 | goto err; | 719 | goto err; |
718 | |||
719 | (*i)++; | ||
720 | return 0; | 720 | return 0; |
721 | err: | 721 | err: |
722 | module_put(t->u.kernel.target->me); | 722 | module_put(t->u.kernel.target->me); |
723 | cleanup_matches: | 723 | cleanup_matches: |
724 | IPT_MATCH_ITERATE(e, cleanup_match, net, &j); | 724 | xt_ematch_foreach(ematch, e) { |
725 | if (j-- == 0) | ||
726 | break; | ||
727 | cleanup_match(ematch, net); | ||
728 | } | ||
725 | return ret; | 729 | return ret; |
726 | } | 730 | } |
727 | 731 | ||
@@ -747,8 +751,7 @@ check_entry_size_and_hooks(struct ipt_entry *e, | |||
747 | const unsigned char *limit, | 751 | const unsigned char *limit, |
748 | const unsigned int *hook_entries, | 752 | const unsigned int *hook_entries, |
749 | const unsigned int *underflows, | 753 | const unsigned int *underflows, |
750 | unsigned int valid_hooks, | 754 | unsigned int valid_hooks) |
751 | unsigned int *i) | ||
752 | { | 755 | { |
753 | unsigned int h; | 756 | unsigned int h; |
754 | 757 | ||
@@ -785,22 +788,19 @@ check_entry_size_and_hooks(struct ipt_entry *e, | |||
785 | /* Clear counters and comefrom */ | 788 | /* Clear counters and comefrom */ |
786 | e->counters = ((struct xt_counters) { 0, 0 }); | 789 | e->counters = ((struct xt_counters) { 0, 0 }); |
787 | e->comefrom = 0; | 790 | e->comefrom = 0; |
788 | |||
789 | (*i)++; | ||
790 | return 0; | 791 | return 0; |
791 | } | 792 | } |
792 | 793 | ||
793 | static int | 794 | static void |
794 | cleanup_entry(struct ipt_entry *e, struct net *net, unsigned int *i) | 795 | cleanup_entry(struct ipt_entry *e, struct net *net) |
795 | { | 796 | { |
796 | struct xt_tgdtor_param par; | 797 | struct xt_tgdtor_param par; |
797 | struct ipt_entry_target *t; | 798 | struct ipt_entry_target *t; |
798 | 799 | struct xt_entry_match *ematch; | |
799 | if (i && (*i)-- == 0) | ||
800 | return 1; | ||
801 | 800 | ||
802 | /* Cleanup all matches */ | 801 | /* Cleanup all matches */ |
803 | IPT_MATCH_ITERATE(e, cleanup_match, net, NULL); | 802 | xt_ematch_foreach(ematch, e) |
803 | cleanup_match(ematch, net); | ||
804 | t = ipt_get_target(e); | 804 | t = ipt_get_target(e); |
805 | 805 | ||
806 | par.net = net; | 806 | par.net = net; |
@@ -810,27 +810,20 @@ cleanup_entry(struct ipt_entry *e, struct net *net, unsigned int *i) | |||
810 | if (par.target->destroy != NULL) | 810 | if (par.target->destroy != NULL) |
811 | par.target->destroy(&par); | 811 | par.target->destroy(&par); |
812 | module_put(par.target->me); | 812 | module_put(par.target->me); |
813 | return 0; | ||
814 | } | 813 | } |
815 | 814 | ||
816 | /* Checks and translates the user-supplied table segment (held in | 815 | /* Checks and translates the user-supplied table segment (held in |
817 | newinfo) */ | 816 | newinfo) */ |
818 | static int | 817 | static int |
819 | translate_table(struct net *net, | 818 | translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0, |
820 | const char *name, | 819 | const struct ipt_replace *repl) |
821 | unsigned int valid_hooks, | ||
822 | struct xt_table_info *newinfo, | ||
823 | void *entry0, | ||
824 | unsigned int size, | ||
825 | unsigned int number, | ||
826 | const unsigned int *hook_entries, | ||
827 | const unsigned int *underflows) | ||
828 | { | 820 | { |
821 | struct ipt_entry *iter; | ||
829 | unsigned int i; | 822 | unsigned int i; |
830 | int ret; | 823 | int ret = 0; |
831 | 824 | ||
832 | newinfo->size = size; | 825 | newinfo->size = repl->size; |
833 | newinfo->number = number; | 826 | newinfo->number = repl->num_entries; |
834 | 827 | ||
835 | /* Init all hooks to impossible value. */ | 828 | /* Init all hooks to impossible value. */ |
836 | for (i = 0; i < NF_INET_NUMHOOKS; i++) { | 829 | for (i = 0; i < NF_INET_NUMHOOKS; i++) { |
@@ -841,49 +834,56 @@ translate_table(struct net *net, | |||
841 | duprintf("translate_table: size %u\n", newinfo->size); | 834 | duprintf("translate_table: size %u\n", newinfo->size); |
842 | i = 0; | 835 | i = 0; |
843 | /* Walk through entries, checking offsets. */ | 836 | /* Walk through entries, checking offsets. */ |
844 | ret = IPT_ENTRY_ITERATE(entry0, newinfo->size, | 837 | xt_entry_foreach(iter, entry0, newinfo->size) { |
845 | check_entry_size_and_hooks, | 838 | ret = check_entry_size_and_hooks(iter, newinfo, entry0, |
846 | newinfo, | 839 | entry0 + repl->size, repl->hook_entry, repl->underflow, |
847 | entry0, | 840 | repl->valid_hooks); |
848 | entry0 + size, | 841 | if (ret != 0) |
849 | hook_entries, underflows, valid_hooks, &i); | 842 | return ret; |
850 | if (ret != 0) | 843 | ++i; |
851 | return ret; | 844 | } |
852 | 845 | ||
853 | if (i != number) { | 846 | if (i != repl->num_entries) { |
854 | duprintf("translate_table: %u not %u entries\n", | 847 | duprintf("translate_table: %u not %u entries\n", |
855 | i, number); | 848 | i, repl->num_entries); |
856 | return -EINVAL; | 849 | return -EINVAL; |
857 | } | 850 | } |
858 | 851 | ||
859 | /* Check hooks all assigned */ | 852 | /* Check hooks all assigned */ |
860 | for (i = 0; i < NF_INET_NUMHOOKS; i++) { | 853 | for (i = 0; i < NF_INET_NUMHOOKS; i++) { |
861 | /* Only hooks which are valid */ | 854 | /* Only hooks which are valid */ |
862 | if (!(valid_hooks & (1 << i))) | 855 | if (!(repl->valid_hooks & (1 << i))) |
863 | continue; | 856 | continue; |
864 | if (newinfo->hook_entry[i] == 0xFFFFFFFF) { | 857 | if (newinfo->hook_entry[i] == 0xFFFFFFFF) { |
865 | duprintf("Invalid hook entry %u %u\n", | 858 | duprintf("Invalid hook entry %u %u\n", |
866 | i, hook_entries[i]); | 859 | i, repl->hook_entry[i]); |
867 | return -EINVAL; | 860 | return -EINVAL; |
868 | } | 861 | } |
869 | if (newinfo->underflow[i] == 0xFFFFFFFF) { | 862 | if (newinfo->underflow[i] == 0xFFFFFFFF) { |
870 | duprintf("Invalid underflow %u %u\n", | 863 | duprintf("Invalid underflow %u %u\n", |
871 | i, underflows[i]); | 864 | i, repl->underflow[i]); |
872 | return -EINVAL; | 865 | return -EINVAL; |
873 | } | 866 | } |
874 | } | 867 | } |
875 | 868 | ||
876 | if (!mark_source_chains(newinfo, valid_hooks, entry0)) | 869 | if (!mark_source_chains(newinfo, repl->valid_hooks, entry0)) |
877 | return -ELOOP; | 870 | return -ELOOP; |
878 | 871 | ||
879 | /* Finally, each sanity check must pass */ | 872 | /* Finally, each sanity check must pass */ |
880 | i = 0; | 873 | i = 0; |
881 | ret = IPT_ENTRY_ITERATE(entry0, newinfo->size, | 874 | xt_entry_foreach(iter, entry0, newinfo->size) { |
882 | find_check_entry, net, name, size, &i); | 875 | ret = find_check_entry(iter, net, repl->name, repl->size); |
876 | if (ret != 0) | ||
877 | break; | ||
878 | ++i; | ||
879 | } | ||
883 | 880 | ||
884 | if (ret != 0) { | 881 | if (ret != 0) { |
885 | IPT_ENTRY_ITERATE(entry0, newinfo->size, | 882 | xt_entry_foreach(iter, entry0, newinfo->size) { |
886 | cleanup_entry, net, &i); | 883 | if (i-- == 0) |
884 | break; | ||
885 | cleanup_entry(iter, net); | ||
886 | } | ||
887 | return ret; | 887 | return ret; |
888 | } | 888 | } |
889 | 889 | ||
@@ -896,33 +896,11 @@ translate_table(struct net *net, | |||
896 | return ret; | 896 | return ret; |
897 | } | 897 | } |
898 | 898 | ||
899 | /* Gets counters. */ | ||
900 | static inline int | ||
901 | add_entry_to_counter(const struct ipt_entry *e, | ||
902 | struct xt_counters total[], | ||
903 | unsigned int *i) | ||
904 | { | ||
905 | ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); | ||
906 | |||
907 | (*i)++; | ||
908 | return 0; | ||
909 | } | ||
910 | |||
911 | static inline int | ||
912 | set_entry_to_counter(const struct ipt_entry *e, | ||
913 | struct ipt_counters total[], | ||
914 | unsigned int *i) | ||
915 | { | ||
916 | SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); | ||
917 | |||
918 | (*i)++; | ||
919 | return 0; | ||
920 | } | ||
921 | |||
922 | static void | 899 | static void |
923 | get_counters(const struct xt_table_info *t, | 900 | get_counters(const struct xt_table_info *t, |
924 | struct xt_counters counters[]) | 901 | struct xt_counters counters[]) |
925 | { | 902 | { |
903 | struct ipt_entry *iter; | ||
926 | unsigned int cpu; | 904 | unsigned int cpu; |
927 | unsigned int i; | 905 | unsigned int i; |
928 | unsigned int curcpu; | 906 | unsigned int curcpu; |
@@ -938,22 +916,22 @@ get_counters(const struct xt_table_info *t, | |||
938 | curcpu = smp_processor_id(); | 916 | curcpu = smp_processor_id(); |
939 | 917 | ||
940 | i = 0; | 918 | i = 0; |
941 | IPT_ENTRY_ITERATE(t->entries[curcpu], | 919 | xt_entry_foreach(iter, t->entries[curcpu], t->size) { |
942 | t->size, | 920 | SET_COUNTER(counters[i], iter->counters.bcnt, |
943 | set_entry_to_counter, | 921 | iter->counters.pcnt); |
944 | counters, | 922 | ++i; |
945 | &i); | 923 | } |
946 | 924 | ||
947 | for_each_possible_cpu(cpu) { | 925 | for_each_possible_cpu(cpu) { |
948 | if (cpu == curcpu) | 926 | if (cpu == curcpu) |
949 | continue; | 927 | continue; |
950 | i = 0; | 928 | i = 0; |
951 | xt_info_wrlock(cpu); | 929 | xt_info_wrlock(cpu); |
952 | IPT_ENTRY_ITERATE(t->entries[cpu], | 930 | xt_entry_foreach(iter, t->entries[cpu], t->size) { |
953 | t->size, | 931 | ADD_COUNTER(counters[i], iter->counters.bcnt, |
954 | add_entry_to_counter, | 932 | iter->counters.pcnt); |
955 | counters, | 933 | ++i; /* macro does multi eval of i */ |
956 | &i); | 934 | } |
957 | xt_info_wrunlock(cpu); | 935 | xt_info_wrunlock(cpu); |
958 | } | 936 | } |
959 | local_bh_enable(); | 937 | local_bh_enable(); |
@@ -1072,24 +1050,19 @@ static int compat_standard_to_user(void __user *dst, const void *src) | |||
1072 | return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0; | 1050 | return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0; |
1073 | } | 1051 | } |
1074 | 1052 | ||
1075 | static inline int | ||
1076 | compat_calc_match(const struct ipt_entry_match *m, int *size) | ||
1077 | { | ||
1078 | *size += xt_compat_match_offset(m->u.kernel.match); | ||
1079 | return 0; | ||
1080 | } | ||
1081 | |||
1082 | static int compat_calc_entry(const struct ipt_entry *e, | 1053 | static int compat_calc_entry(const struct ipt_entry *e, |
1083 | const struct xt_table_info *info, | 1054 | const struct xt_table_info *info, |
1084 | const void *base, struct xt_table_info *newinfo) | 1055 | const void *base, struct xt_table_info *newinfo) |
1085 | { | 1056 | { |
1057 | const struct xt_entry_match *ematch; | ||
1086 | const struct ipt_entry_target *t; | 1058 | const struct ipt_entry_target *t; |
1087 | unsigned int entry_offset; | 1059 | unsigned int entry_offset; |
1088 | int off, i, ret; | 1060 | int off, i, ret; |
1089 | 1061 | ||
1090 | off = sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry); | 1062 | off = sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry); |
1091 | entry_offset = (void *)e - base; | 1063 | entry_offset = (void *)e - base; |
1092 | IPT_MATCH_ITERATE(e, compat_calc_match, &off); | 1064 | xt_ematch_foreach(ematch, e) |
1065 | off += xt_compat_match_offset(ematch->u.kernel.match); | ||
1093 | t = ipt_get_target_c(e); | 1066 | t = ipt_get_target_c(e); |
1094 | off += xt_compat_target_offset(t->u.kernel.target); | 1067 | off += xt_compat_target_offset(t->u.kernel.target); |
1095 | newinfo->size -= off; | 1068 | newinfo->size -= off; |
@@ -1111,7 +1084,9 @@ static int compat_calc_entry(const struct ipt_entry *e, | |||
1111 | static int compat_table_info(const struct xt_table_info *info, | 1084 | static int compat_table_info(const struct xt_table_info *info, |
1112 | struct xt_table_info *newinfo) | 1085 | struct xt_table_info *newinfo) |
1113 | { | 1086 | { |
1087 | struct ipt_entry *iter; | ||
1114 | void *loc_cpu_entry; | 1088 | void *loc_cpu_entry; |
1089 | int ret; | ||
1115 | 1090 | ||
1116 | if (!newinfo || !info) | 1091 | if (!newinfo || !info) |
1117 | return -EINVAL; | 1092 | return -EINVAL; |
@@ -1120,9 +1095,12 @@ static int compat_table_info(const struct xt_table_info *info, | |||
1120 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); | 1095 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); |
1121 | newinfo->initial_entries = 0; | 1096 | newinfo->initial_entries = 0; |
1122 | loc_cpu_entry = info->entries[raw_smp_processor_id()]; | 1097 | loc_cpu_entry = info->entries[raw_smp_processor_id()]; |
1123 | return IPT_ENTRY_ITERATE(loc_cpu_entry, info->size, | 1098 | xt_entry_foreach(iter, loc_cpu_entry, info->size) { |
1124 | compat_calc_entry, info, loc_cpu_entry, | 1099 | ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo); |
1125 | newinfo); | 1100 | if (ret != 0) |
1101 | return ret; | ||
1102 | } | ||
1103 | return 0; | ||
1126 | } | 1104 | } |
1127 | #endif | 1105 | #endif |
1128 | 1106 | ||
@@ -1236,6 +1214,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, | |||
1236 | struct xt_table_info *oldinfo; | 1214 | struct xt_table_info *oldinfo; |
1237 | struct xt_counters *counters; | 1215 | struct xt_counters *counters; |
1238 | void *loc_cpu_old_entry; | 1216 | void *loc_cpu_old_entry; |
1217 | struct ipt_entry *iter; | ||
1239 | 1218 | ||
1240 | ret = 0; | 1219 | ret = 0; |
1241 | counters = vmalloc(num_counters * sizeof(struct xt_counters)); | 1220 | counters = vmalloc(num_counters * sizeof(struct xt_counters)); |
@@ -1278,8 +1257,9 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, | |||
1278 | 1257 | ||
1279 | /* Decrease module usage counts and free resource */ | 1258 | /* Decrease module usage counts and free resource */ |
1280 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; | 1259 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; |
1281 | IPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry, | 1260 | xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size) |
1282 | net, NULL); | 1261 | cleanup_entry(iter, net); |
1262 | |||
1283 | xt_free_table_info(oldinfo); | 1263 | xt_free_table_info(oldinfo); |
1284 | if (copy_to_user(counters_ptr, counters, | 1264 | if (copy_to_user(counters_ptr, counters, |
1285 | sizeof(struct xt_counters) * num_counters) != 0) | 1265 | sizeof(struct xt_counters) * num_counters) != 0) |
@@ -1304,6 +1284,7 @@ do_replace(struct net *net, const void __user *user, unsigned int len) | |||
1304 | struct ipt_replace tmp; | 1284 | struct ipt_replace tmp; |
1305 | struct xt_table_info *newinfo; | 1285 | struct xt_table_info *newinfo; |
1306 | void *loc_cpu_entry; | 1286 | void *loc_cpu_entry; |
1287 | struct ipt_entry *iter; | ||
1307 | 1288 | ||
1308 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) | 1289 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) |
1309 | return -EFAULT; | 1290 | return -EFAULT; |
@@ -1324,9 +1305,7 @@ do_replace(struct net *net, const void __user *user, unsigned int len) | |||
1324 | goto free_newinfo; | 1305 | goto free_newinfo; |
1325 | } | 1306 | } |
1326 | 1307 | ||
1327 | ret = translate_table(net, tmp.name, tmp.valid_hooks, | 1308 | ret = translate_table(net, newinfo, loc_cpu_entry, &tmp); |
1328 | newinfo, loc_cpu_entry, tmp.size, tmp.num_entries, | ||
1329 | tmp.hook_entry, tmp.underflow); | ||
1330 | if (ret != 0) | 1309 | if (ret != 0) |
1331 | goto free_newinfo; | 1310 | goto free_newinfo; |
1332 | 1311 | ||
@@ -1339,25 +1318,13 @@ do_replace(struct net *net, const void __user *user, unsigned int len) | |||
1339 | return 0; | 1318 | return 0; |
1340 | 1319 | ||
1341 | free_newinfo_untrans: | 1320 | free_newinfo_untrans: |
1342 | IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, net, NULL); | 1321 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) |
1322 | cleanup_entry(iter, net); | ||
1343 | free_newinfo: | 1323 | free_newinfo: |
1344 | xt_free_table_info(newinfo); | 1324 | xt_free_table_info(newinfo); |
1345 | return ret; | 1325 | return ret; |
1346 | } | 1326 | } |
1347 | 1327 | ||
1348 | /* We're lazy, and add to the first CPU; overflow works its fey magic | ||
1349 | * and everything is OK. */ | ||
1350 | static int | ||
1351 | add_counter_to_entry(struct ipt_entry *e, | ||
1352 | const struct xt_counters addme[], | ||
1353 | unsigned int *i) | ||
1354 | { | ||
1355 | ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | ||
1356 | |||
1357 | (*i)++; | ||
1358 | return 0; | ||
1359 | } | ||
1360 | |||
1361 | static int | 1328 | static int |
1362 | do_add_counters(struct net *net, const void __user *user, | 1329 | do_add_counters(struct net *net, const void __user *user, |
1363 | unsigned int len, int compat) | 1330 | unsigned int len, int compat) |
@@ -1373,6 +1340,7 @@ do_add_counters(struct net *net, const void __user *user, | |||
1373 | const struct xt_table_info *private; | 1340 | const struct xt_table_info *private; |
1374 | int ret = 0; | 1341 | int ret = 0; |
1375 | void *loc_cpu_entry; | 1342 | void *loc_cpu_entry; |
1343 | struct ipt_entry *iter; | ||
1376 | #ifdef CONFIG_COMPAT | 1344 | #ifdef CONFIG_COMPAT |
1377 | struct compat_xt_counters_info compat_tmp; | 1345 | struct compat_xt_counters_info compat_tmp; |
1378 | 1346 | ||
@@ -1430,11 +1398,10 @@ do_add_counters(struct net *net, const void __user *user, | |||
1430 | curcpu = smp_processor_id(); | 1398 | curcpu = smp_processor_id(); |
1431 | loc_cpu_entry = private->entries[curcpu]; | 1399 | loc_cpu_entry = private->entries[curcpu]; |
1432 | xt_info_wrlock(curcpu); | 1400 | xt_info_wrlock(curcpu); |
1433 | IPT_ENTRY_ITERATE(loc_cpu_entry, | 1401 | xt_entry_foreach(iter, loc_cpu_entry, private->size) { |
1434 | private->size, | 1402 | ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt); |
1435 | add_counter_to_entry, | 1403 | ++i; |
1436 | paddc, | 1404 | } |
1437 | &i); | ||
1438 | xt_info_wrunlock(curcpu); | 1405 | xt_info_wrunlock(curcpu); |
1439 | unlock_up_free: | 1406 | unlock_up_free: |
1440 | local_bh_enable(); | 1407 | local_bh_enable(); |
@@ -1462,45 +1429,40 @@ struct compat_ipt_replace { | |||
1462 | static int | 1429 | static int |
1463 | compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr, | 1430 | compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr, |
1464 | unsigned int *size, struct xt_counters *counters, | 1431 | unsigned int *size, struct xt_counters *counters, |
1465 | unsigned int *i) | 1432 | unsigned int i) |
1466 | { | 1433 | { |
1467 | struct ipt_entry_target *t; | 1434 | struct ipt_entry_target *t; |
1468 | struct compat_ipt_entry __user *ce; | 1435 | struct compat_ipt_entry __user *ce; |
1469 | u_int16_t target_offset, next_offset; | 1436 | u_int16_t target_offset, next_offset; |
1470 | compat_uint_t origsize; | 1437 | compat_uint_t origsize; |
1471 | int ret; | 1438 | const struct xt_entry_match *ematch; |
1439 | int ret = 0; | ||
1472 | 1440 | ||
1473 | ret = -EFAULT; | ||
1474 | origsize = *size; | 1441 | origsize = *size; |
1475 | ce = (struct compat_ipt_entry __user *)*dstptr; | 1442 | ce = (struct compat_ipt_entry __user *)*dstptr; |
1476 | if (copy_to_user(ce, e, sizeof(struct ipt_entry))) | 1443 | if (copy_to_user(ce, e, sizeof(struct ipt_entry)) != 0 || |
1477 | goto out; | 1444 | copy_to_user(&ce->counters, &counters[i], |
1478 | 1445 | sizeof(counters[i])) != 0) | |
1479 | if (copy_to_user(&ce->counters, &counters[*i], sizeof(counters[*i]))) | 1446 | return -EFAULT; |
1480 | goto out; | ||
1481 | 1447 | ||
1482 | *dstptr += sizeof(struct compat_ipt_entry); | 1448 | *dstptr += sizeof(struct compat_ipt_entry); |
1483 | *size -= sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry); | 1449 | *size -= sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry); |
1484 | 1450 | ||
1485 | ret = IPT_MATCH_ITERATE(e, xt_compat_match_to_user, dstptr, size); | 1451 | xt_ematch_foreach(ematch, e) { |
1452 | ret = xt_compat_match_to_user(ematch, dstptr, size); | ||
1453 | if (ret != 0) | ||
1454 | return ret; | ||
1455 | } | ||
1486 | target_offset = e->target_offset - (origsize - *size); | 1456 | target_offset = e->target_offset - (origsize - *size); |
1487 | if (ret) | ||
1488 | goto out; | ||
1489 | t = ipt_get_target(e); | 1457 | t = ipt_get_target(e); |
1490 | ret = xt_compat_target_to_user(t, dstptr, size); | 1458 | ret = xt_compat_target_to_user(t, dstptr, size); |
1491 | if (ret) | 1459 | if (ret) |
1492 | goto out; | 1460 | return ret; |
1493 | ret = -EFAULT; | ||
1494 | next_offset = e->next_offset - (origsize - *size); | 1461 | next_offset = e->next_offset - (origsize - *size); |
1495 | if (put_user(target_offset, &ce->target_offset)) | 1462 | if (put_user(target_offset, &ce->target_offset) != 0 || |
1496 | goto out; | 1463 | put_user(next_offset, &ce->next_offset) != 0) |
1497 | if (put_user(next_offset, &ce->next_offset)) | 1464 | return -EFAULT; |
1498 | goto out; | ||
1499 | |||
1500 | (*i)++; | ||
1501 | return 0; | 1465 | return 0; |
1502 | out: | ||
1503 | return ret; | ||
1504 | } | 1466 | } |
1505 | 1467 | ||
1506 | static int | 1468 | static int |
@@ -1508,7 +1470,7 @@ compat_find_calc_match(struct ipt_entry_match *m, | |||
1508 | const char *name, | 1470 | const char *name, |
1509 | const struct ipt_ip *ip, | 1471 | const struct ipt_ip *ip, |
1510 | unsigned int hookmask, | 1472 | unsigned int hookmask, |
1511 | int *size, unsigned int *i) | 1473 | int *size) |
1512 | { | 1474 | { |
1513 | struct xt_match *match; | 1475 | struct xt_match *match; |
1514 | 1476 | ||
@@ -1522,34 +1484,19 @@ compat_find_calc_match(struct ipt_entry_match *m, | |||
1522 | } | 1484 | } |
1523 | m->u.kernel.match = match; | 1485 | m->u.kernel.match = match; |
1524 | *size += xt_compat_match_offset(match); | 1486 | *size += xt_compat_match_offset(match); |
1525 | |||
1526 | (*i)++; | ||
1527 | return 0; | 1487 | return 0; |
1528 | } | 1488 | } |
1529 | 1489 | ||
1530 | static int | 1490 | static void compat_release_entry(struct compat_ipt_entry *e) |
1531 | compat_release_match(struct ipt_entry_match *m, unsigned int *i) | ||
1532 | { | ||
1533 | if (i && (*i)-- == 0) | ||
1534 | return 1; | ||
1535 | |||
1536 | module_put(m->u.kernel.match->me); | ||
1537 | return 0; | ||
1538 | } | ||
1539 | |||
1540 | static int | ||
1541 | compat_release_entry(struct compat_ipt_entry *e, unsigned int *i) | ||
1542 | { | 1491 | { |
1543 | struct ipt_entry_target *t; | 1492 | struct ipt_entry_target *t; |
1544 | 1493 | struct xt_entry_match *ematch; | |
1545 | if (i && (*i)-- == 0) | ||
1546 | return 1; | ||
1547 | 1494 | ||
1548 | /* Cleanup all matches */ | 1495 | /* Cleanup all matches */ |
1549 | COMPAT_IPT_MATCH_ITERATE(e, compat_release_match, NULL); | 1496 | xt_ematch_foreach(ematch, e) |
1497 | module_put(ematch->u.kernel.match->me); | ||
1550 | t = compat_ipt_get_target(e); | 1498 | t = compat_ipt_get_target(e); |
1551 | module_put(t->u.kernel.target->me); | 1499 | module_put(t->u.kernel.target->me); |
1552 | return 0; | ||
1553 | } | 1500 | } |
1554 | 1501 | ||
1555 | static int | 1502 | static int |
@@ -1560,9 +1507,9 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e, | |||
1560 | const unsigned char *limit, | 1507 | const unsigned char *limit, |
1561 | const unsigned int *hook_entries, | 1508 | const unsigned int *hook_entries, |
1562 | const unsigned int *underflows, | 1509 | const unsigned int *underflows, |
1563 | unsigned int *i, | ||
1564 | const char *name) | 1510 | const char *name) |
1565 | { | 1511 | { |
1512 | struct xt_entry_match *ematch; | ||
1566 | struct ipt_entry_target *t; | 1513 | struct ipt_entry_target *t; |
1567 | struct xt_target *target; | 1514 | struct xt_target *target; |
1568 | unsigned int entry_offset; | 1515 | unsigned int entry_offset; |
@@ -1591,10 +1538,13 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e, | |||
1591 | off = sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry); | 1538 | off = sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry); |
1592 | entry_offset = (void *)e - (void *)base; | 1539 | entry_offset = (void *)e - (void *)base; |
1593 | j = 0; | 1540 | j = 0; |
1594 | ret = COMPAT_IPT_MATCH_ITERATE(e, compat_find_calc_match, name, | 1541 | xt_ematch_foreach(ematch, e) { |
1595 | &e->ip, e->comefrom, &off, &j); | 1542 | ret = compat_find_calc_match(ematch, name, |
1596 | if (ret != 0) | 1543 | &e->ip, e->comefrom, &off); |
1597 | goto release_matches; | 1544 | if (ret != 0) |
1545 | goto release_matches; | ||
1546 | ++j; | ||
1547 | } | ||
1598 | 1548 | ||
1599 | t = compat_ipt_get_target(e); | 1549 | t = compat_ipt_get_target(e); |
1600 | target = try_then_request_module(xt_find_target(AF_INET, | 1550 | target = try_then_request_module(xt_find_target(AF_INET, |
@@ -1626,14 +1576,16 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e, | |||
1626 | /* Clear counters and comefrom */ | 1576 | /* Clear counters and comefrom */ |
1627 | memset(&e->counters, 0, sizeof(e->counters)); | 1577 | memset(&e->counters, 0, sizeof(e->counters)); |
1628 | e->comefrom = 0; | 1578 | e->comefrom = 0; |
1629 | |||
1630 | (*i)++; | ||
1631 | return 0; | 1579 | return 0; |
1632 | 1580 | ||
1633 | out: | 1581 | out: |
1634 | module_put(t->u.kernel.target->me); | 1582 | module_put(t->u.kernel.target->me); |
1635 | release_matches: | 1583 | release_matches: |
1636 | IPT_MATCH_ITERATE(e, compat_release_match, &j); | 1584 | xt_ematch_foreach(ematch, e) { |
1585 | if (j-- == 0) | ||
1586 | break; | ||
1587 | module_put(ematch->u.kernel.match->me); | ||
1588 | } | ||
1637 | return ret; | 1589 | return ret; |
1638 | } | 1590 | } |
1639 | 1591 | ||
@@ -1647,6 +1599,7 @@ compat_copy_entry_from_user(struct compat_ipt_entry *e, void **dstptr, | |||
1647 | struct ipt_entry *de; | 1599 | struct ipt_entry *de; |
1648 | unsigned int origsize; | 1600 | unsigned int origsize; |
1649 | int ret, h; | 1601 | int ret, h; |
1602 | struct xt_entry_match *ematch; | ||
1650 | 1603 | ||
1651 | ret = 0; | 1604 | ret = 0; |
1652 | origsize = *size; | 1605 | origsize = *size; |
@@ -1657,10 +1610,11 @@ compat_copy_entry_from_user(struct compat_ipt_entry *e, void **dstptr, | |||
1657 | *dstptr += sizeof(struct ipt_entry); | 1610 | *dstptr += sizeof(struct ipt_entry); |
1658 | *size += sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry); | 1611 | *size += sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry); |
1659 | 1612 | ||
1660 | ret = COMPAT_IPT_MATCH_ITERATE(e, xt_compat_match_from_user, | 1613 | xt_ematch_foreach(ematch, e) { |
1661 | dstptr, size); | 1614 | ret = xt_compat_match_from_user(ematch, dstptr, size); |
1662 | if (ret) | 1615 | if (ret != 0) |
1663 | return ret; | 1616 | return ret; |
1617 | } | ||
1664 | de->target_offset = e->target_offset - (origsize - *size); | 1618 | de->target_offset = e->target_offset - (origsize - *size); |
1665 | t = compat_ipt_get_target(e); | 1619 | t = compat_ipt_get_target(e); |
1666 | target = t->u.kernel.target; | 1620 | target = t->u.kernel.target; |
@@ -1677,12 +1631,12 @@ compat_copy_entry_from_user(struct compat_ipt_entry *e, void **dstptr, | |||
1677 | } | 1631 | } |
1678 | 1632 | ||
1679 | static int | 1633 | static int |
1680 | compat_check_entry(struct ipt_entry *e, struct net *net, const char *name, | 1634 | compat_check_entry(struct ipt_entry *e, struct net *net, const char *name) |
1681 | unsigned int *i) | ||
1682 | { | 1635 | { |
1636 | struct xt_entry_match *ematch; | ||
1683 | struct xt_mtchk_param mtpar; | 1637 | struct xt_mtchk_param mtpar; |
1684 | unsigned int j; | 1638 | unsigned int j; |
1685 | int ret; | 1639 | int ret = 0; |
1686 | 1640 | ||
1687 | j = 0; | 1641 | j = 0; |
1688 | mtpar.net = net; | 1642 | mtpar.net = net; |
@@ -1690,19 +1644,24 @@ compat_check_entry(struct ipt_entry *e, struct net *net, const char *name, | |||
1690 | mtpar.entryinfo = &e->ip; | 1644 | mtpar.entryinfo = &e->ip; |
1691 | mtpar.hook_mask = e->comefrom; | 1645 | mtpar.hook_mask = e->comefrom; |
1692 | mtpar.family = NFPROTO_IPV4; | 1646 | mtpar.family = NFPROTO_IPV4; |
1693 | ret = IPT_MATCH_ITERATE(e, check_match, &mtpar, &j); | 1647 | xt_ematch_foreach(ematch, e) { |
1694 | if (ret) | 1648 | ret = check_match(ematch, &mtpar); |
1695 | goto cleanup_matches; | 1649 | if (ret != 0) |
1650 | goto cleanup_matches; | ||
1651 | ++j; | ||
1652 | } | ||
1696 | 1653 | ||
1697 | ret = check_target(e, net, name); | 1654 | ret = check_target(e, net, name); |
1698 | if (ret) | 1655 | if (ret) |
1699 | goto cleanup_matches; | 1656 | goto cleanup_matches; |
1700 | |||
1701 | (*i)++; | ||
1702 | return 0; | 1657 | return 0; |
1703 | 1658 | ||
1704 | cleanup_matches: | 1659 | cleanup_matches: |
1705 | IPT_MATCH_ITERATE(e, cleanup_match, net, &j); | 1660 | xt_ematch_foreach(ematch, e) { |
1661 | if (j-- == 0) | ||
1662 | break; | ||
1663 | cleanup_match(ematch, net); | ||
1664 | } | ||
1706 | return ret; | 1665 | return ret; |
1707 | } | 1666 | } |
1708 | 1667 | ||
@@ -1720,6 +1679,8 @@ translate_compat_table(struct net *net, | |||
1720 | unsigned int i, j; | 1679 | unsigned int i, j; |
1721 | struct xt_table_info *newinfo, *info; | 1680 | struct xt_table_info *newinfo, *info; |
1722 | void *pos, *entry0, *entry1; | 1681 | void *pos, *entry0, *entry1; |
1682 | struct compat_ipt_entry *iter0; | ||
1683 | struct ipt_entry *iter1; | ||
1723 | unsigned int size; | 1684 | unsigned int size; |
1724 | int ret; | 1685 | int ret; |
1725 | 1686 | ||
@@ -1738,13 +1699,14 @@ translate_compat_table(struct net *net, | |||
1738 | j = 0; | 1699 | j = 0; |
1739 | xt_compat_lock(AF_INET); | 1700 | xt_compat_lock(AF_INET); |
1740 | /* Walk through entries, checking offsets. */ | 1701 | /* Walk through entries, checking offsets. */ |
1741 | ret = COMPAT_IPT_ENTRY_ITERATE(entry0, total_size, | 1702 | xt_entry_foreach(iter0, entry0, total_size) { |
1742 | check_compat_entry_size_and_hooks, | 1703 | ret = check_compat_entry_size_and_hooks(iter0, info, &size, |
1743 | info, &size, entry0, | 1704 | entry0, entry0 + total_size, hook_entries, underflows, |
1744 | entry0 + total_size, | 1705 | name); |
1745 | hook_entries, underflows, &j, name); | 1706 | if (ret != 0) |
1746 | if (ret != 0) | 1707 | goto out_unlock; |
1747 | goto out_unlock; | 1708 | ++j; |
1709 | } | ||
1748 | 1710 | ||
1749 | ret = -EINVAL; | 1711 | ret = -EINVAL; |
1750 | if (j != number) { | 1712 | if (j != number) { |
@@ -1783,9 +1745,12 @@ translate_compat_table(struct net *net, | |||
1783 | entry1 = newinfo->entries[raw_smp_processor_id()]; | 1745 | entry1 = newinfo->entries[raw_smp_processor_id()]; |
1784 | pos = entry1; | 1746 | pos = entry1; |
1785 | size = total_size; | 1747 | size = total_size; |
1786 | ret = COMPAT_IPT_ENTRY_ITERATE(entry0, total_size, | 1748 | xt_entry_foreach(iter0, entry0, total_size) { |
1787 | compat_copy_entry_from_user, | 1749 | ret = compat_copy_entry_from_user(iter0, &pos, |
1788 | &pos, &size, name, newinfo, entry1); | 1750 | &size, name, newinfo, entry1); |
1751 | if (ret != 0) | ||
1752 | break; | ||
1753 | } | ||
1789 | xt_compat_flush_offsets(AF_INET); | 1754 | xt_compat_flush_offsets(AF_INET); |
1790 | xt_compat_unlock(AF_INET); | 1755 | xt_compat_unlock(AF_INET); |
1791 | if (ret) | 1756 | if (ret) |
@@ -1796,13 +1761,32 @@ translate_compat_table(struct net *net, | |||
1796 | goto free_newinfo; | 1761 | goto free_newinfo; |
1797 | 1762 | ||
1798 | i = 0; | 1763 | i = 0; |
1799 | ret = IPT_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry, | 1764 | xt_entry_foreach(iter1, entry1, newinfo->size) { |
1800 | net, name, &i); | 1765 | ret = compat_check_entry(iter1, net, name); |
1766 | if (ret != 0) | ||
1767 | break; | ||
1768 | ++i; | ||
1769 | } | ||
1801 | if (ret) { | 1770 | if (ret) { |
1771 | /* | ||
1772 | * The first i matches need cleanup_entry (calls ->destroy) | ||
1773 | * because they had called ->check already. The other j-i | ||
1774 | * entries need only release. | ||
1775 | */ | ||
1776 | int skip = i; | ||
1802 | j -= i; | 1777 | j -= i; |
1803 | COMPAT_IPT_ENTRY_ITERATE_CONTINUE(entry0, newinfo->size, i, | 1778 | xt_entry_foreach(iter0, entry0, newinfo->size) { |
1804 | compat_release_entry, &j); | 1779 | if (skip-- > 0) |
1805 | IPT_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, net, &i); | 1780 | continue; |
1781 | if (j-- == 0) | ||
1782 | break; | ||
1783 | compat_release_entry(iter0); | ||
1784 | } | ||
1785 | xt_entry_foreach(iter1, entry1, newinfo->size) { | ||
1786 | if (i-- == 0) | ||
1787 | break; | ||
1788 | cleanup_entry(iter1, net); | ||
1789 | } | ||
1806 | xt_free_table_info(newinfo); | 1790 | xt_free_table_info(newinfo); |
1807 | return ret; | 1791 | return ret; |
1808 | } | 1792 | } |
@@ -1820,7 +1804,11 @@ translate_compat_table(struct net *net, | |||
1820 | free_newinfo: | 1804 | free_newinfo: |
1821 | xt_free_table_info(newinfo); | 1805 | xt_free_table_info(newinfo); |
1822 | out: | 1806 | out: |
1823 | COMPAT_IPT_ENTRY_ITERATE(entry0, total_size, compat_release_entry, &j); | 1807 | xt_entry_foreach(iter0, entry0, total_size) { |
1808 | if (j-- == 0) | ||
1809 | break; | ||
1810 | compat_release_entry(iter0); | ||
1811 | } | ||
1824 | return ret; | 1812 | return ret; |
1825 | out_unlock: | 1813 | out_unlock: |
1826 | xt_compat_flush_offsets(AF_INET); | 1814 | xt_compat_flush_offsets(AF_INET); |
@@ -1835,6 +1823,7 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len) | |||
1835 | struct compat_ipt_replace tmp; | 1823 | struct compat_ipt_replace tmp; |
1836 | struct xt_table_info *newinfo; | 1824 | struct xt_table_info *newinfo; |
1837 | void *loc_cpu_entry; | 1825 | void *loc_cpu_entry; |
1826 | struct ipt_entry *iter; | ||
1838 | 1827 | ||
1839 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) | 1828 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) |
1840 | return -EFAULT; | 1829 | return -EFAULT; |
@@ -1873,7 +1862,8 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len) | |||
1873 | return 0; | 1862 | return 0; |
1874 | 1863 | ||
1875 | free_newinfo_untrans: | 1864 | free_newinfo_untrans: |
1876 | IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, net, NULL); | 1865 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) |
1866 | cleanup_entry(iter, net); | ||
1877 | free_newinfo: | 1867 | free_newinfo: |
1878 | xt_free_table_info(newinfo); | 1868 | xt_free_table_info(newinfo); |
1879 | return ret; | 1869 | return ret; |
@@ -1922,6 +1912,7 @@ compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table, | |||
1922 | int ret = 0; | 1912 | int ret = 0; |
1923 | const void *loc_cpu_entry; | 1913 | const void *loc_cpu_entry; |
1924 | unsigned int i = 0; | 1914 | unsigned int i = 0; |
1915 | struct ipt_entry *iter; | ||
1925 | 1916 | ||
1926 | counters = alloc_counters(table); | 1917 | counters = alloc_counters(table); |
1927 | if (IS_ERR(counters)) | 1918 | if (IS_ERR(counters)) |
@@ -1934,9 +1925,12 @@ compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table, | |||
1934 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; | 1925 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; |
1935 | pos = userptr; | 1926 | pos = userptr; |
1936 | size = total_size; | 1927 | size = total_size; |
1937 | ret = IPT_ENTRY_ITERATE(loc_cpu_entry, total_size, | 1928 | xt_entry_foreach(iter, loc_cpu_entry, total_size) { |
1938 | compat_copy_entry_to_user, | 1929 | ret = compat_copy_entry_to_user(iter, &pos, |
1939 | &pos, &size, counters, &i); | 1930 | &size, counters, i++); |
1931 | if (ret != 0) | ||
1932 | break; | ||
1933 | } | ||
1940 | 1934 | ||
1941 | vfree(counters); | 1935 | vfree(counters); |
1942 | return ret; | 1936 | return ret; |
@@ -2110,11 +2104,7 @@ struct xt_table *ipt_register_table(struct net *net, | |||
2110 | loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; | 2104 | loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; |
2111 | memcpy(loc_cpu_entry, repl->entries, repl->size); | 2105 | memcpy(loc_cpu_entry, repl->entries, repl->size); |
2112 | 2106 | ||
2113 | ret = translate_table(net, table->name, table->valid_hooks, | 2107 | ret = translate_table(net, newinfo, loc_cpu_entry, repl); |
2114 | newinfo, loc_cpu_entry, repl->size, | ||
2115 | repl->num_entries, | ||
2116 | repl->hook_entry, | ||
2117 | repl->underflow); | ||
2118 | if (ret != 0) | 2108 | if (ret != 0) |
2119 | goto out_free; | 2109 | goto out_free; |
2120 | 2110 | ||
@@ -2137,12 +2127,14 @@ void ipt_unregister_table(struct net *net, struct xt_table *table) | |||
2137 | struct xt_table_info *private; | 2127 | struct xt_table_info *private; |
2138 | void *loc_cpu_entry; | 2128 | void *loc_cpu_entry; |
2139 | struct module *table_owner = table->me; | 2129 | struct module *table_owner = table->me; |
2130 | struct ipt_entry *iter; | ||
2140 | 2131 | ||
2141 | private = xt_unregister_table(table); | 2132 | private = xt_unregister_table(table); |
2142 | 2133 | ||
2143 | /* Decrease module usage counts and free resources */ | 2134 | /* Decrease module usage counts and free resources */ |
2144 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; | 2135 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; |
2145 | IPT_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, net, NULL); | 2136 | xt_entry_foreach(iter, loc_cpu_entry, private->size) |
2137 | cleanup_entry(iter, net); | ||
2146 | if (private->number > private->initial_entries) | 2138 | if (private->number > private->initial_entries) |
2147 | module_put(table_owner); | 2139 | module_put(table_owner); |
2148 | xt_free_table_info(private); | 2140 | xt_free_table_info(private); |