| From 2f2d0088eb93db5c649d2a5e34a3800a8a935fc5 Mon Sep 17 00:00:00 2001 |
| From: Shuah Khan <shuahkh@osg.samsung.com> |
| Date: Thu, 7 Dec 2017 14:16:49 -0700 |
| Subject: usbip: prevent vhci_hcd driver from leaking a socket pointer address |
| |
| From: Shuah Khan <shuahkh@osg.samsung.com> |
| |
| commit 2f2d0088eb93db5c649d2a5e34a3800a8a935fc5 upstream. |
| |
| When a client has a USB device attached over IP, the vhci_hcd driver is |
| locally leaking a socket pointer address via the |
| |
| /sys/devices/platform/vhci_hcd/status file (world-readable) and in debug |
| output when "usbip --debug port" is run. |
| |
| Fix it to not leak. The socket pointer address is not used at the moment |
| and it was made visible as a convenient way to find IP address from socket |
| pointer address by looking up /proc/net/{tcp,tcp6}. |
| |
| As this opens a security hole, the fix replaces socket pointer address with |
| sockfd. |
| |
| Reported-by: Secunia Research <vuln@secunia.com> |
| Signed-off-by: Shuah Khan <shuahkh@osg.samsung.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/usb/usbip/usbip_common.h | 1 + |
| drivers/usb/usbip/vhci_sysfs.c | 25 ++++++++++++++++--------- |
| tools/usb/usbip/libsrc/vhci_driver.c | 8 ++++---- |
| 3 files changed, 21 insertions(+), 13 deletions(-) |
| |
| --- a/drivers/usb/usbip/usbip_common.h |
| +++ b/drivers/usb/usbip/usbip_common.h |
| @@ -270,6 +270,7 @@ struct usbip_device { |
| /* lock for status */ |
| spinlock_t lock; |
| |
| + int sockfd; |
| struct socket *tcp_socket; |
| |
| struct task_struct *tcp_rx; |
| --- a/drivers/usb/usbip/vhci_sysfs.c |
| +++ b/drivers/usb/usbip/vhci_sysfs.c |
| @@ -31,15 +31,20 @@ |
| |
| /* |
| * output example: |
| - * hub port sta spd dev socket local_busid |
| - * hs 0000 004 000 00000000 c5a7bb80 1-2.3 |
| + * hub port sta spd dev sockfd local_busid |
| + * hs 0000 004 000 00000000 3 1-2.3 |
| * ................................................ |
| - * ss 0008 004 000 00000000 d8cee980 2-3.4 |
| + * ss 0008 004 000 00000000 4 2-3.4 |
| * ................................................ |
| * |
| - * IP address can be retrieved from a socket pointer address by looking |
| - * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a |
| - * port number and its peer IP address. |
| + * Output includes socket fd instead of socket pointer address to avoid |
| + * leaking kernel memory address in: |
| + * /sys/devices/platform/vhci_hcd.0/status and in debug output. |
| + * The socket pointer address is not used at the moment and it was made |
| + * visible as a convenient way to find IP address from socket pointer |
| + * address by looking up /proc/net/{tcp,tcp6}. As this opens a security |
| + * hole, the change is made to use sockfd instead. |
| + * |
| */ |
| static void port_show_vhci(char **out, int hub, int port, struct vhci_device *vdev) |
| { |
| @@ -53,8 +58,8 @@ static void port_show_vhci(char **out, i |
| if (vdev->ud.status == VDEV_ST_USED) { |
| *out += sprintf(*out, "%03u %08x ", |
| vdev->speed, vdev->devid); |
| - *out += sprintf(*out, "%16p %s", |
| - vdev->ud.tcp_socket, |
| + *out += sprintf(*out, "%u %s", |
| + vdev->ud.sockfd, |
| dev_name(&vdev->udev->dev)); |
| |
| } else { |
| @@ -174,7 +179,8 @@ static ssize_t nports_show(struct device |
| char *s = out; |
| |
| /* |
| - * Half the ports are for SPEED_HIGH and half for SPEED_SUPER, thus the * 2. |
| + * Half the ports are for SPEED_HIGH and half for SPEED_SUPER, |
| + * thus the * 2. |
| */ |
| out += sprintf(out, "%d\n", VHCI_PORTS * vhci_num_controllers); |
| return out - s; |
| @@ -380,6 +386,7 @@ static ssize_t store_attach(struct devic |
| |
| vdev->devid = devid; |
| vdev->speed = speed; |
| + vdev->ud.sockfd = sockfd; |
| vdev->ud.tcp_socket = socket; |
| vdev->ud.status = VDEV_ST_NOTASSIGNED; |
| |
| --- a/tools/usb/usbip/libsrc/vhci_driver.c |
| +++ b/tools/usb/usbip/libsrc/vhci_driver.c |
| @@ -50,14 +50,14 @@ static int parse_status(const char *valu |
| |
| while (*c != '\0') { |
| int port, status, speed, devid; |
| - unsigned long socket; |
| + int sockfd; |
| char lbusid[SYSFS_BUS_ID_SIZE]; |
| struct usbip_imported_device *idev; |
| char hub[3]; |
| |
| - ret = sscanf(c, "%2s %d %d %d %x %lx %31s\n", |
| + ret = sscanf(c, "%2s %d %d %d %x %u %31s\n", |
| hub, &port, &status, &speed, |
| - &devid, &socket, lbusid); |
| + &devid, &sockfd, lbusid); |
| |
| if (ret < 5) { |
| dbg("sscanf failed: %d", ret); |
| @@ -66,7 +66,7 @@ static int parse_status(const char *valu |
| |
| dbg("hub %s port %d status %d speed %d devid %x", |
| hub, port, status, speed, devid); |
| - dbg("socket %lx lbusid %s", socket, lbusid); |
| + dbg("sockfd %u lbusid %s", sockfd, lbusid); |
| |
| /* if a device is connected, look at it */ |
| idev = &vhci_driver->idev[port]; |