aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2010-02-04 12:38:53 -0500
committerFlorian Westphal <fw@strlen.de>2010-02-16 11:25:21 -0500
commite788759f44b29e5b1bc27a265dece7dcfa4234af (patch)
treebe90c201d4565e5814f19e6a4b487cfb62e44d9c /net/bridge
parent3e5e524ffb5fcf2447eb5dd9f8e54ad22dd9baa7 (diff)
netfilter: ebtables: split do_replace into two functions
once CONFIG_COMPAT support is merged this allows to call do_replace_finish() after doing the CONFIG_COMPAT conversion instead of copy & pasting this. Signed-off-by: Florian Westphal <fw@strlen.de>
Diffstat (limited to 'net/bridge')
-rw-r--r--net/bridge/netfilter/ebtables.c136
1 files changed, 71 insertions, 65 deletions
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index 4370e9680487..a707dbdc0327 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -959,91 +959,45 @@ static void get_counters(const struct ebt_counter *oldcounters,
959 } 959 }
960} 960}
961 961
962/* replace the table */ 962static int do_replace_finish(struct net *net, struct ebt_replace *repl,
963static int do_replace(struct net *net, const void __user *user, 963 struct ebt_table_info *newinfo)
964 unsigned int len)
965{ 964{
966 int ret, i, countersize; 965 int ret, i;
967 struct ebt_table_info *newinfo;
968 struct ebt_replace tmp;
969 struct ebt_table *t;
970 struct ebt_counter *counterstmp = NULL; 966 struct ebt_counter *counterstmp = NULL;
971 /* used to be able to unlock earlier */ 967 /* used to be able to unlock earlier */
972 struct ebt_table_info *table; 968 struct ebt_table_info *table;
973 969 struct ebt_table *t;
974 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
975 return -EFAULT;
976
977 if (len != sizeof(tmp) + tmp.entries_size) {
978 BUGPRINT("Wrong len argument\n");
979 return -EINVAL;
980 }
981
982 if (tmp.entries_size == 0) {
983 BUGPRINT("Entries_size never zero\n");
984 return -EINVAL;
985 }
986 /* overflow check */
987 if (tmp.nentries >= ((INT_MAX - sizeof(struct ebt_table_info)) / NR_CPUS -
988 SMP_CACHE_BYTES) / sizeof(struct ebt_counter))
989 return -ENOMEM;
990 if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter))
991 return -ENOMEM;
992
993 countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids;
994 newinfo = vmalloc(sizeof(*newinfo) + countersize);
995 if (!newinfo)
996 return -ENOMEM;
997
998 if (countersize)
999 memset(newinfo->counters, 0, countersize);
1000
1001 newinfo->entries = vmalloc(tmp.entries_size);
1002 if (!newinfo->entries) {
1003 ret = -ENOMEM;
1004 goto free_newinfo;
1005 }
1006 if (copy_from_user(
1007 newinfo->entries, tmp.entries, tmp.entries_size) != 0) {
1008 BUGPRINT("Couldn't copy entries from userspace\n");
1009 ret = -EFAULT;
1010 goto free_entries;
1011 }
1012 970
1013 /* the user wants counters back 971 /* the user wants counters back
1014 the check on the size is done later, when we have the lock */ 972 the check on the size is done later, when we have the lock */
1015 if (tmp.num_counters) { 973 if (repl->num_counters) {
1016 counterstmp = vmalloc(tmp.num_counters * sizeof(*counterstmp)); 974 unsigned long size = repl->num_counters * sizeof(*counterstmp);
1017 if (!counterstmp) { 975 counterstmp = vmalloc(size);
1018 ret = -ENOMEM; 976 if (!counterstmp)
1019 goto free_entries; 977 return -ENOMEM;
1020 }
1021 } 978 }
1022 else
1023 counterstmp = NULL;
1024 979
1025 /* this can get initialized by translate_table() */
1026 newinfo->chainstack = NULL; 980 newinfo->chainstack = NULL;
1027 ret = ebt_verify_pointers(&tmp, newinfo); 981 ret = ebt_verify_pointers(repl, newinfo);
1028 if (ret != 0) 982 if (ret != 0)
1029 goto free_counterstmp; 983 goto free_counterstmp;
1030 984
1031 ret = translate_table(net, tmp.name, newinfo); 985 ret = translate_table(net, repl->name, newinfo);
1032 986
1033 if (ret != 0) 987 if (ret != 0)
1034 goto free_counterstmp; 988 goto free_counterstmp;
1035 989
1036 t = find_table_lock(net, tmp.name, &ret, &ebt_mutex); 990 t = find_table_lock(net, repl->name, &ret, &ebt_mutex);
1037 if (!t) { 991 if (!t) {
1038 ret = -ENOENT; 992 ret = -ENOENT;
1039 goto free_iterate; 993 goto free_iterate;
1040 } 994 }
1041 995
1042 /* the table doesn't like it */ 996 /* the table doesn't like it */
1043 if (t->check && (ret = t->check(newinfo, tmp.valid_hooks))) 997 if (t->check && (ret = t->check(newinfo, repl->valid_hooks)))
1044 goto free_unlock; 998 goto free_unlock;
1045 999
1046 if (tmp.num_counters && tmp.num_counters != t->private->nentries) { 1000 if (repl->num_counters && repl->num_counters != t->private->nentries) {
1047 BUGPRINT("Wrong nr. of counters requested\n"); 1001 BUGPRINT("Wrong nr. of counters requested\n");
1048 ret = -EINVAL; 1002 ret = -EINVAL;
1049 goto free_unlock; 1003 goto free_unlock;
@@ -1059,7 +1013,7 @@ static int do_replace(struct net *net, const void __user *user,
1059 module_put(t->me); 1013 module_put(t->me);
1060 /* we need an atomic snapshot of the counters */ 1014 /* we need an atomic snapshot of the counters */
1061 write_lock_bh(&t->lock); 1015 write_lock_bh(&t->lock);
1062 if (tmp.num_counters) 1016 if (repl->num_counters)
1063 get_counters(t->private->counters, counterstmp, 1017 get_counters(t->private->counters, counterstmp,
1064 t->private->nentries); 1018 t->private->nentries);
1065 1019
@@ -1070,10 +1024,9 @@ static int do_replace(struct net *net, const void __user *user,
1070 allocation. Only reason why this is done is because this way the lock 1024 allocation. Only reason why this is done is because this way the lock
1071 is held only once, while this doesn't bring the kernel into a 1025 is held only once, while this doesn't bring the kernel into a
1072 dangerous state. */ 1026 dangerous state. */
1073 if (tmp.num_counters && 1027 if (repl->num_counters &&
1074 copy_to_user(tmp.counters, counterstmp, 1028 copy_to_user(repl->counters, counterstmp,
1075 tmp.num_counters * sizeof(struct ebt_counter))) { 1029 repl->num_counters * sizeof(struct ebt_counter))) {
1076 BUGPRINT("Couldn't copy counters to userspace\n");
1077 ret = -EFAULT; 1030 ret = -EFAULT;
1078 } 1031 }
1079 else 1032 else
@@ -1107,6 +1060,59 @@ free_counterstmp:
1107 vfree(newinfo->chainstack[i]); 1060 vfree(newinfo->chainstack[i]);
1108 vfree(newinfo->chainstack); 1061 vfree(newinfo->chainstack);
1109 } 1062 }
1063 return ret;
1064}
1065
1066/* replace the table */
1067static int do_replace(struct net *net, const void __user *user,
1068 unsigned int len)
1069{
1070 int ret, countersize;
1071 struct ebt_table_info *newinfo;
1072 struct ebt_replace tmp;
1073
1074 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1075 return -EFAULT;
1076
1077 if (len != sizeof(tmp) + tmp.entries_size) {
1078 BUGPRINT("Wrong len argument\n");
1079 return -EINVAL;
1080 }
1081
1082 if (tmp.entries_size == 0) {
1083 BUGPRINT("Entries_size never zero\n");
1084 return -EINVAL;
1085 }
1086 /* overflow check */
1087 if (tmp.nentries >= ((INT_MAX - sizeof(struct ebt_table_info)) /
1088 NR_CPUS - SMP_CACHE_BYTES) / sizeof(struct ebt_counter))
1089 return -ENOMEM;
1090 if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter))
1091 return -ENOMEM;
1092
1093 countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids;
1094 newinfo = vmalloc(sizeof(*newinfo) + countersize);
1095 if (!newinfo)
1096 return -ENOMEM;
1097
1098 if (countersize)
1099 memset(newinfo->counters, 0, countersize);
1100
1101 newinfo->entries = vmalloc(tmp.entries_size);
1102 if (!newinfo->entries) {
1103 ret = -ENOMEM;
1104 goto free_newinfo;
1105 }
1106 if (copy_from_user(
1107 newinfo->entries, tmp.entries, tmp.entries_size) != 0) {
1108 BUGPRINT("Couldn't copy entries from userspace\n");
1109 ret = -EFAULT;
1110 goto free_entries;
1111 }
1112
1113 ret = do_replace_finish(net, &tmp, newinfo);
1114 if (ret == 0)
1115 return ret;
1110free_entries: 1116free_entries:
1111 vfree(newinfo->entries); 1117 vfree(newinfo->entries);
1112free_newinfo: 1118free_newinfo: