aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2010-02-06 21:19:12 -0500
committerFlorian Westphal <fw@strlen.de>2010-02-16 11:27:19 -0500
commit90b89af7e15143c8ea22f5c8818f5a2eec9e75c1 (patch)
tree28e259c073054635c3cf5db638eb48c94274ced0 /net/bridge
parent81e675c227ec60a0bdcbb547dc530ebee23ff931 (diff)
netfilter: ebtables: try native set/getsockopt handlers, too
ebtables can be compiled to perform userspace-side padding of structures. In that case, all the structures are already in the 'native' format expected by the kernel. This tries to determine what format the userspace program is using. For most set/getsockopts, this can be done by checking the len argument for sizeof(compat_ebt_replace) and re-trying the native handler on error. In case of EBT_SO_GET_ENTRIES, the native handler is tried first, it will error out early when checking the *len argument (the compat version has to defer this check until after iterating over the kernel data set once, to adjust for all the structure size differences). As this would cause error printks, remove those as well, as recommended by Bart de Schuymer. Signed-off-by: Florian Westphal <fw@strlen.de>
Diffstat (limited to 'net/bridge')
-rw-r--r--net/bridge/netfilter/ebtables.c34
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;