summaryrefslogtreecommitdiff
path: root/drivers/firewire
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2012-10-06 16:12:56 +0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-10-21 20:27:58 +0400
commit0bd1ed9ead1a2b7fc1534bff04729c3712a6fb25 (patch)
tree97f7e4b5b5c8359aa21c53900ae11046c97d7d77 /drivers/firewire
parent90e4ed1b7de612e4ed18029e61134ab2fea6233e (diff)
downloadlinux-0bd1ed9ead1a2b7fc1534bff04729c3712a6fb25.tar.xz
firewire: cdev: fix user memory corruption (i386 userland on amd64 kernel)
commit 790198f74c9d1b46b6a89504361b1a844670d050 upstream. Fix two bugs of the /dev/fw* character device concerning the FW_CDEV_IOC_GET_INFO ioctl with nonzero fw_cdev_get_info.bus_reset. (Practically all /dev/fw* clients issue this ioctl right after opening the device.) Both bugs are caused by sizeof(struct fw_cdev_event_bus_reset) being 36 without natural alignment and 40 with natural alignment. 1) Memory corruption, affecting i386 userland on amd64 kernel: Userland reserves a 36 bytes large buffer, kernel writes 40 bytes. This has been first found and reported against libraw1394 if compiled with gcc 4.7 which happens to order libraw1394's stack such that the bug became visible as data corruption. 2) Information leak, affecting all kernel architectures except i386: 4 bytes of random kernel stack data were leaked to userspace. Hence limit the respective copy_to_user() to the 32-bit aligned size of struct fw_cdev_event_bus_reset. Reported-by: Simon Kirby <sim@hostway.ca> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/firewire')
-rw-r--r--drivers/firewire/core-cdev.c4
1 files changed, 2 insertions, 2 deletions
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index 2e6b24547e2a..b8e4809cae0e 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -471,8 +471,8 @@ static int ioctl_get_info(struct client *client, union ioctl_arg *arg)
client->bus_reset_closure = a->bus_reset_closure;
if (a->bus_reset != 0) {
fill_bus_reset_event(&bus_reset, client);
- ret = copy_to_user(u64_to_uptr(a->bus_reset),
- &bus_reset, sizeof(bus_reset));
+ /* unaligned size of bus_reset is 36 bytes */
+ ret = copy_to_user(u64_to_uptr(a->bus_reset), &bus_reset, 36);
}
if (ret == 0 && list_empty(&client->link))
list_add_tail(&client->link, &client->device->client_list);