diff options
-rw-r--r-- | net/bridge/netfilter/ebtables.c | 34 |
1 files changed, 24 insertions, 10 deletions
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index fcaefdd6200b..dfb58056a89a 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c | |||
@@ -1428,16 +1428,12 @@ static int copy_everything_to_user(struct ebt_table *t, void __user *user, | |||
1428 | oldcounters = t->table->counters; | 1428 | oldcounters = t->table->counters; |
1429 | } | 1429 | } |
1430 | 1430 | ||
1431 | if (copy_from_user(&tmp, user, sizeof(tmp))) { | 1431 | if (copy_from_user(&tmp, user, sizeof(tmp))) |
1432 | BUGPRINT("Cfu didn't work\n"); | ||
1433 | return -EFAULT; | 1432 | return -EFAULT; |
1434 | } | ||
1435 | 1433 | ||
1436 | if (*len != sizeof(struct ebt_replace) + entries_size + | 1434 | if (*len != sizeof(struct ebt_replace) + entries_size + |
1437 | (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) { | 1435 | (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) |
1438 | BUGPRINT("Wrong size\n"); | ||
1439 | return -EINVAL; | 1436 | return -EINVAL; |
1440 | } | ||
1441 | 1437 | ||
1442 | if (tmp.nentries != nentries) { | 1438 | if (tmp.nentries != nentries) { |
1443 | BUGPRINT("Nentries wrong\n"); | 1439 | BUGPRINT("Nentries wrong\n"); |
@@ -2213,8 +2209,12 @@ static int compat_do_replace(struct net *net, void __user *user, | |||
2213 | void *entries_tmp; | 2209 | void *entries_tmp; |
2214 | 2210 | ||
2215 | ret = compat_copy_ebt_replace_from_user(&tmp, user, len); | 2211 | ret = compat_copy_ebt_replace_from_user(&tmp, user, len); |
2216 | if (ret) | 2212 | if (ret) { |
2213 | /* try real handler in case userland supplied needed padding */ | ||
2214 | if (ret == -EINVAL && do_replace(net, user, len) == 0) | ||
2215 | ret = 0; | ||
2217 | return ret; | 2216 | return ret; |
2217 | } | ||
2218 | 2218 | ||
2219 | countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids; | 2219 | countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids; |
2220 | newinfo = vmalloc(sizeof(*newinfo) + countersize); | 2220 | newinfo = vmalloc(sizeof(*newinfo) + countersize); |
@@ -2303,8 +2303,9 @@ static int compat_update_counters(struct net *net, void __user *user, | |||
2303 | if (copy_from_user(&hlp, user, sizeof(hlp))) | 2303 | if (copy_from_user(&hlp, user, sizeof(hlp))) |
2304 | return -EFAULT; | 2304 | return -EFAULT; |
2305 | 2305 | ||
2306 | /* try real handler in case userland supplied needed padding */ | ||
2306 | if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter)) | 2307 | if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter)) |
2307 | return -EINVAL; | 2308 | return update_counters(net, user, len); |
2308 | 2309 | ||
2309 | return do_update_counters(net, hlp.name, compat_ptr(hlp.counters), | 2310 | return do_update_counters(net, hlp.name, compat_ptr(hlp.counters), |
2310 | hlp.num_counters, user, len); | 2311 | hlp.num_counters, user, len); |
@@ -2341,9 +2342,10 @@ static int compat_do_ebt_get_ctl(struct sock *sk, int cmd, | |||
2341 | if (!capable(CAP_NET_ADMIN)) | 2342 | if (!capable(CAP_NET_ADMIN)) |
2342 | return -EPERM; | 2343 | return -EPERM; |
2343 | 2344 | ||
2345 | /* try real handler in case userland supplied needed padding */ | ||
2344 | if ((cmd == EBT_SO_GET_INFO || | 2346 | if ((cmd == EBT_SO_GET_INFO || |
2345 | cmd == EBT_SO_GET_INIT_INFO) && *len != sizeof(tmp)) | 2347 | cmd == EBT_SO_GET_INIT_INFO) && *len != sizeof(tmp)) |
2346 | return -EINVAL; | 2348 | return do_ebt_get_ctl(sk, cmd, user, len); |
2347 | 2349 | ||
2348 | if (copy_from_user(&tmp, user, sizeof(tmp))) | 2350 | if (copy_from_user(&tmp, user, sizeof(tmp))) |
2349 | return -EFAULT; | 2351 | return -EFAULT; |
@@ -2380,7 +2382,19 @@ static int compat_do_ebt_get_ctl(struct sock *sk, int cmd, | |||
2380 | break; | 2382 | break; |
2381 | case EBT_SO_GET_ENTRIES: | 2383 | case EBT_SO_GET_ENTRIES: |
2382 | case EBT_SO_GET_INIT_ENTRIES: | 2384 | case EBT_SO_GET_INIT_ENTRIES: |
2383 | ret = compat_copy_everything_to_user(t, user, len, cmd); | 2385 | /* |
2386 | * try real handler first in case of userland-side padding. | ||
2387 | * in case we are dealing with an 'ordinary' 32 bit binary | ||
2388 | * without 64bit compatibility padding, this will fail right | ||
2389 | * after copy_from_user when the *len argument is validated. | ||
2390 | * | ||
2391 | * the compat_ variant needs to do one pass over the kernel | ||
2392 | * data set to adjust for size differences before it the check. | ||
2393 | */ | ||
2394 | if (copy_everything_to_user(t, user, len, cmd) == 0) | ||
2395 | ret = 0; | ||
2396 | else | ||
2397 | ret = compat_copy_everything_to_user(t, user, len, cmd); | ||
2384 | break; | 2398 | break; |
2385 | default: | 2399 | default: |
2386 | ret = -EINVAL; | 2400 | ret = -EINVAL; |