diff options
author | Florian Westphal <fw@strlen.de> | 2010-02-04 12:38:53 -0500 |
---|---|---|
committer | Florian Westphal <fw@strlen.de> | 2010-02-16 11:25:21 -0500 |
commit | e788759f44b29e5b1bc27a265dece7dcfa4234af (patch) | |
tree | be90c201d4565e5814f19e6a4b487cfb62e44d9c /net/bridge | |
parent | 3e5e524ffb5fcf2447eb5dd9f8e54ad22dd9baa7 (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.c | 136 |
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 */ | 962 | static int do_replace_finish(struct net *net, struct ebt_replace *repl, |
963 | static 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 */ | ||
1067 | static 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; | ||
1110 | free_entries: | 1116 | free_entries: |
1111 | vfree(newinfo->entries); | 1117 | vfree(newinfo->entries); |
1112 | free_newinfo: | 1118 | free_newinfo: |