diff options
author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2010-04-07 02:30:50 -0400 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2010-04-10 10:51:13 -0400 |
commit | 9cac00b8f0079d5d3d54ec4dae453d58dec30e7c (patch) | |
tree | 902b5f22c553395e5bab8c7561b996f19584e7f6 /drivers | |
parent | 385ab5bcd4be586dffdba550b310308d89eade71 (diff) |
firewire: cdev: fix information leak
A userspace client got to see uninitialized stack-allocated memory if it
specified an _IOC_READ type of ioctl and an argument size larger than
expected by firewire-core's ioctl handlers (but not larger than the
core's union ioctl_arg).
Fix this by clearing the requested buffer size to zero, but only at _IOR
ioctls. This way, there is almost no runtime penalty to legitimate
ioctls. The only legitimate _IOR is FW_CDEV_IOC_GET_CYCLE_TIMER with 12
or 16 bytes to memset.
[Another way to fix this would be strict checking of argument size (and
possibly direction) vs. command number. However, we then need a lookup
table, and we need to allow for slight size deviations in case of 32bit
userland on 64bit kernel.]
Reported-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/firewire/core-cdev.c | 18 |
1 files changed, 9 insertions, 9 deletions
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index 5eba9e0f876c..0d3df0927efc 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c | |||
@@ -1356,24 +1356,24 @@ static int dispatch_ioctl(struct client *client, | |||
1356 | return -ENODEV; | 1356 | return -ENODEV; |
1357 | 1357 | ||
1358 | if (_IOC_TYPE(cmd) != '#' || | 1358 | if (_IOC_TYPE(cmd) != '#' || |
1359 | _IOC_NR(cmd) >= ARRAY_SIZE(ioctl_handlers)) | 1359 | _IOC_NR(cmd) >= ARRAY_SIZE(ioctl_handlers) || |
1360 | _IOC_SIZE(cmd) > sizeof(buffer)) | ||
1360 | return -EINVAL; | 1361 | return -EINVAL; |
1361 | 1362 | ||
1362 | if (_IOC_DIR(cmd) & _IOC_WRITE) { | 1363 | if (_IOC_DIR(cmd) == _IOC_READ) |
1363 | if (_IOC_SIZE(cmd) > sizeof(buffer) || | 1364 | memset(&buffer, 0, _IOC_SIZE(cmd)); |
1364 | copy_from_user(&buffer, arg, _IOC_SIZE(cmd))) | 1365 | |
1366 | if (_IOC_DIR(cmd) & _IOC_WRITE) | ||
1367 | if (copy_from_user(&buffer, arg, _IOC_SIZE(cmd))) | ||
1365 | return -EFAULT; | 1368 | return -EFAULT; |
1366 | } | ||
1367 | 1369 | ||
1368 | ret = ioctl_handlers[_IOC_NR(cmd)](client, &buffer); | 1370 | ret = ioctl_handlers[_IOC_NR(cmd)](client, &buffer); |
1369 | if (ret < 0) | 1371 | if (ret < 0) |
1370 | return ret; | 1372 | return ret; |
1371 | 1373 | ||
1372 | if (_IOC_DIR(cmd) & _IOC_READ) { | 1374 | if (_IOC_DIR(cmd) & _IOC_READ) |
1373 | if (_IOC_SIZE(cmd) > sizeof(buffer) || | 1375 | if (copy_to_user(arg, &buffer, _IOC_SIZE(cmd))) |
1374 | copy_to_user(arg, &buffer, _IOC_SIZE(cmd))) | ||
1375 | return -EFAULT; | 1376 | return -EFAULT; |
1376 | } | ||
1377 | 1377 | ||
1378 | return ret; | 1378 | return ret; |
1379 | } | 1379 | } |