From d6bd89c758d0f19120b58b82d6f8c6090c0a3c53 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 24 Jan 2018 10:12:45 +0100 Subject: [PATCH] 4.9-stable patches added patches: orangefs-initialize-op-on-loop-restart-in-orangefs_devreq_read.patch orangefs-use-list_for_each_entry_safe-in-purge_waiting_ops.patch usbip-fix-implicit-fallthrough-warning.patch usbip-fix-potential-format-overflow-in-userspace-tools.patch usbip-prevent-vhci_hcd-driver-from-leaking-a-socket-pointer-address.patch --- ...loop-restart-in-orangefs_devreq_read.patch | 46 +++++++ ...each_entry_safe-in-purge_waiting_ops.patch | 34 +++++ queue-4.9/series | 5 + ...bip-fix-implicit-fallthrough-warning.patch | 35 +++++ ...l-format-overflow-in-userspace-tools.patch | 108 +++++++++++++++ ...rom-leaking-a-socket-pointer-address.patch | 128 ++++++++++++++++++ 6 files changed, 356 insertions(+) create mode 100644 queue-4.9/orangefs-initialize-op-on-loop-restart-in-orangefs_devreq_read.patch create mode 100644 queue-4.9/orangefs-use-list_for_each_entry_safe-in-purge_waiting_ops.patch create mode 100644 queue-4.9/usbip-fix-implicit-fallthrough-warning.patch create mode 100644 queue-4.9/usbip-fix-potential-format-overflow-in-userspace-tools.patch create mode 100644 queue-4.9/usbip-prevent-vhci_hcd-driver-from-leaking-a-socket-pointer-address.patch diff --git a/queue-4.9/orangefs-initialize-op-on-loop-restart-in-orangefs_devreq_read.patch b/queue-4.9/orangefs-initialize-op-on-loop-restart-in-orangefs_devreq_read.patch new file mode 100644 index 00000000000..e2a2e55d6d3 --- /dev/null +++ b/queue-4.9/orangefs-initialize-op-on-loop-restart-in-orangefs_devreq_read.patch @@ -0,0 +1,46 @@ +From a0ec1ded22e6a6bc41981fae22406835b006a66e Mon Sep 17 00:00:00 2001 +From: Martin Brandenburg +Date: Mon, 22 Jan 2018 15:44:52 -0500 +Subject: orangefs: initialize op on loop restart in orangefs_devreq_read + +From: Martin Brandenburg + +commit a0ec1ded22e6a6bc41981fae22406835b006a66e upstream. + +In orangefs_devreq_read, there is a loop which picks an op off the list +of pending ops. If the loop fails to find an op, there is nothing to +read, and it returns EAGAIN. If the op has been given up on, the loop +is restarted via a goto. The bug is that the variable which the found +op is written to is not reinitialized, so if there are no more eligible +ops on the list, the code runs again on the already handled op. + +This is triggered by interrupting a process while the op is being copied +to the client-core. It's a fairly small window, but it's there. + +Signed-off-by: Martin Brandenburg +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + fs/orangefs/devorangefs-req.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/fs/orangefs/devorangefs-req.c ++++ b/fs/orangefs/devorangefs-req.c +@@ -161,7 +161,7 @@ static ssize_t orangefs_devreq_read(stru + struct orangefs_kernel_op_s *op, *temp; + __s32 proto_ver = ORANGEFS_KERNEL_PROTO_VERSION; + static __s32 magic = ORANGEFS_DEVREQ_MAGIC; +- struct orangefs_kernel_op_s *cur_op = NULL; ++ struct orangefs_kernel_op_s *cur_op; + unsigned long ret; + + /* We do not support blocking IO. */ +@@ -181,6 +181,7 @@ static ssize_t orangefs_devreq_read(stru + } + + restart: ++ cur_op = NULL; + /* Get next op (if any) from top of list. */ + spin_lock(&orangefs_request_list_lock); + list_for_each_entry_safe(op, temp, &orangefs_request_list, list) { diff --git a/queue-4.9/orangefs-use-list_for_each_entry_safe-in-purge_waiting_ops.patch b/queue-4.9/orangefs-use-list_for_each_entry_safe-in-purge_waiting_ops.patch new file mode 100644 index 00000000000..709ef609917 --- /dev/null +++ b/queue-4.9/orangefs-use-list_for_each_entry_safe-in-purge_waiting_ops.patch @@ -0,0 +1,34 @@ +From 0afc0decf247f65b7aba666a76a0a68adf4bc435 Mon Sep 17 00:00:00 2001 +From: Martin Brandenburg +Date: Mon, 22 Jan 2018 15:44:51 -0500 +Subject: orangefs: use list_for_each_entry_safe in purge_waiting_ops + +From: Martin Brandenburg + +commit 0afc0decf247f65b7aba666a76a0a68adf4bc435 upstream. + +set_op_state_purged can delete the op. + +Signed-off-by: Martin Brandenburg +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + fs/orangefs/waitqueue.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/fs/orangefs/waitqueue.c ++++ b/fs/orangefs/waitqueue.c +@@ -28,10 +28,10 @@ static void orangefs_clean_up_interrupte + */ + void purge_waiting_ops(void) + { +- struct orangefs_kernel_op_s *op; ++ struct orangefs_kernel_op_s *op, *tmp; + + spin_lock(&orangefs_request_list_lock); +- list_for_each_entry(op, &orangefs_request_list, list) { ++ list_for_each_entry_safe(op, tmp, &orangefs_request_list, list) { + gossip_debug(GOSSIP_WAIT_DEBUG, + "pvfs2-client-core: purging op tag %llu %s\n", + llu(op->tag), diff --git a/queue-4.9/series b/queue-4.9/series index e2d6ad978ed..3c3e7c19515 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -1 +1,6 @@ x86-asm-32-make-sync_core-handle-missing-cpuid-on-all-32-bit-kernels.patch +orangefs-use-list_for_each_entry_safe-in-purge_waiting_ops.patch +orangefs-initialize-op-on-loop-restart-in-orangefs_devreq_read.patch +usbip-prevent-vhci_hcd-driver-from-leaking-a-socket-pointer-address.patch +usbip-fix-implicit-fallthrough-warning.patch +usbip-fix-potential-format-overflow-in-userspace-tools.patch diff --git a/queue-4.9/usbip-fix-implicit-fallthrough-warning.patch b/queue-4.9/usbip-fix-implicit-fallthrough-warning.patch new file mode 100644 index 00000000000..da83c9c39ce --- /dev/null +++ b/queue-4.9/usbip-fix-implicit-fallthrough-warning.patch @@ -0,0 +1,35 @@ +From cfd6ed4537a9e938fa76facecd4b9cd65b6d1563 Mon Sep 17 00:00:00 2001 +From: Jonathan Dieter +Date: Mon, 27 Feb 2017 10:31:04 +0200 +Subject: usbip: Fix implicit fallthrough warning + +From: Jonathan Dieter + +commit cfd6ed4537a9e938fa76facecd4b9cd65b6d1563 upstream. + +GCC 7 now warns when switch statements fall through implicitly, and with +-Werror enabled in configure.ac, that makes these tools unbuildable. + +We fix this by notifying the compiler that this particular case statement +is meant to fall through. + +Reviewed-by: Peter Senna Tschudin +Signed-off-by: Jonathan Dieter +Signed-off-by: Shuah Khan +Signed-off-by: Greg Kroah-Hartman + +--- + tools/usb/usbip/src/usbip.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/tools/usb/usbip/src/usbip.c ++++ b/tools/usb/usbip/src/usbip.c +@@ -176,6 +176,8 @@ int main(int argc, char *argv[]) + break; + case '?': + printf("usbip: invalid option\n"); ++ /* Terminate after printing error */ ++ /* FALLTHRU */ + default: + usbip_usage(); + goto out; diff --git a/queue-4.9/usbip-fix-potential-format-overflow-in-userspace-tools.patch b/queue-4.9/usbip-fix-potential-format-overflow-in-userspace-tools.patch new file mode 100644 index 00000000000..0602642abae --- /dev/null +++ b/queue-4.9/usbip-fix-potential-format-overflow-in-userspace-tools.patch @@ -0,0 +1,108 @@ +From e5dfa3f902b9a642ae8c6997d57d7c41e384a90b Mon Sep 17 00:00:00 2001 +From: Jonathan Dieter +Date: Mon, 27 Feb 2017 10:31:03 +0200 +Subject: usbip: Fix potential format overflow in userspace tools + +From: Jonathan Dieter + +commit e5dfa3f902b9a642ae8c6997d57d7c41e384a90b upstream. + +The usbip userspace tools call sprintf()/snprintf() and don't check for +the return value which can lead the paths to overflow, truncating the +final file in the path. + +More urgently, GCC 7 now warns that these aren't checked with +-Wformat-overflow, and with -Werror enabled in configure.ac, that makes +these tools unbuildable. + +This patch fixes these problems by replacing sprintf() with snprintf() in +one place and adding checks for the return value of snprintf(). + +Reviewed-by: Peter Senna Tschudin +Signed-off-by: Jonathan Dieter +Acked-by: Shuah Khan +Signed-off-by: Shuah Khan +Signed-off-by: Greg Kroah-Hartman + +--- + tools/usb/usbip/libsrc/usbip_common.c | 9 ++++++++- + tools/usb/usbip/libsrc/usbip_host_common.c | 28 +++++++++++++++++++++++----- + 2 files changed, 31 insertions(+), 6 deletions(-) + +--- a/tools/usb/usbip/libsrc/usbip_common.c ++++ b/tools/usb/usbip/libsrc/usbip_common.c +@@ -215,9 +215,16 @@ int read_usb_interface(struct usbip_usb_ + struct usbip_usb_interface *uinf) + { + char busid[SYSFS_BUS_ID_SIZE]; ++ int size; + struct udev_device *sif; + +- sprintf(busid, "%s:%d.%d", udev->busid, udev->bConfigurationValue, i); ++ size = snprintf(busid, sizeof(busid), "%s:%d.%d", ++ udev->busid, udev->bConfigurationValue, i); ++ if (size < 0 || (unsigned int)size >= sizeof(busid)) { ++ err("busid length %i >= %lu or < 0", size, ++ (long unsigned)sizeof(busid)); ++ return -1; ++ } + + sif = udev_device_new_from_subsystem_sysname(udev_context, "usb", busid); + if (!sif) { +--- a/tools/usb/usbip/libsrc/usbip_host_common.c ++++ b/tools/usb/usbip/libsrc/usbip_host_common.c +@@ -40,13 +40,20 @@ struct udev *udev_context; + static int32_t read_attr_usbip_status(struct usbip_usb_device *udev) + { + char status_attr_path[SYSFS_PATH_MAX]; ++ int size; + int fd; + int length; + char status; + int value = 0; + +- snprintf(status_attr_path, SYSFS_PATH_MAX, "%s/usbip_status", +- udev->path); ++ size = snprintf(status_attr_path, sizeof(status_attr_path), ++ "%s/usbip_status", udev->path); ++ if (size < 0 || (unsigned int)size >= sizeof(status_attr_path)) { ++ err("usbip_status path length %i >= %lu or < 0", size, ++ (long unsigned)sizeof(status_attr_path)); ++ return -1; ++ } ++ + + fd = open(status_attr_path, O_RDONLY); + if (fd < 0) { +@@ -218,6 +225,7 @@ int usbip_export_device(struct usbip_exp + { + char attr_name[] = "usbip_sockfd"; + char sockfd_attr_path[SYSFS_PATH_MAX]; ++ int size; + char sockfd_buff[30]; + int ret; + +@@ -237,10 +245,20 @@ int usbip_export_device(struct usbip_exp + } + + /* only the first interface is true */ +- snprintf(sockfd_attr_path, sizeof(sockfd_attr_path), "%s/%s", +- edev->udev.path, attr_name); ++ size = snprintf(sockfd_attr_path, sizeof(sockfd_attr_path), "%s/%s", ++ edev->udev.path, attr_name); ++ if (size < 0 || (unsigned int)size >= sizeof(sockfd_attr_path)) { ++ err("exported device path length %i >= %lu or < 0", size, ++ (long unsigned)sizeof(sockfd_attr_path)); ++ return -1; ++ } + +- snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", sockfd); ++ size = snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", sockfd); ++ if (size < 0 || (unsigned int)size >= sizeof(sockfd_buff)) { ++ err("socket length %i >= %lu or < 0", size, ++ (long unsigned)sizeof(sockfd_buff)); ++ return -1; ++ } + + ret = write_sysfs_attribute(sockfd_attr_path, sockfd_buff, + strlen(sockfd_buff)); diff --git a/queue-4.9/usbip-prevent-vhci_hcd-driver-from-leaking-a-socket-pointer-address.patch b/queue-4.9/usbip-prevent-vhci_hcd-driver-from-leaking-a-socket-pointer-address.patch new file mode 100644 index 00000000000..24be68f625c --- /dev/null +++ b/queue-4.9/usbip-prevent-vhci_hcd-driver-from-leaking-a-socket-pointer-address.patch @@ -0,0 +1,128 @@ +From 2f2d0088eb93db5c649d2a5e34a3800a8a935fc5 Mon Sep 17 00:00:00 2001 +From: Shuah Khan +Date: Thu, 7 Dec 2017 14:16:49 -0700 +Subject: usbip: prevent vhci_hcd driver from leaking a socket pointer address + +From: Shuah Khan + +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 +Signed-off-by: Shuah Khan +Signed-off-by: Greg Kroah-Hartman +--- + 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, 20 insertions(+), 14 deletions(-) + +--- a/drivers/usb/usbip/usbip_common.h ++++ b/drivers/usb/usbip/usbip_common.h +@@ -271,6 +271,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 +@@ -49,13 +49,17 @@ static ssize_t status_show_vhci(int pdev + + /* + * output example: +- * port sta spd dev socket local_busid +- * 0000 004 000 00000000 c5a7bb80 1-2.3 +- * 0001 004 000 00000000 d8cee980 2-3.4 ++ * port sta spd dev sockfd local_busid ++ * 0000 004 000 00000000 000003 1-2.3 ++ * 0001 004 000 00000000 000004 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. + */ + for (i = 0; i < VHCI_HC_PORTS; i++) { + struct vhci_device *vdev = &vhci->vdev[i]; +@@ -68,13 +72,13 @@ static ssize_t status_show_vhci(int pdev + 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, "%06u %s", ++ vdev->ud.sockfd, + dev_name(&vdev->udev->dev)); + + } else { + out += sprintf(out, "000 00000000 "); +- out += sprintf(out, "0000000000000000 0-0"); ++ out += sprintf(out, "000000 0-0"); + } + + out += sprintf(out, "\n"); +@@ -125,7 +129,7 @@ static ssize_t status_show(struct device + int pdev_nr; + + out += sprintf(out, +- "port sta spd dev socket local_busid\n"); ++ "port sta spd dev sockfd local_busid\n"); + + pdev_nr = status_name_to_id(attr->attr.name); + if (pdev_nr < 0) +@@ -324,6 +328,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 +@@ -55,12 +55,12 @@ 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]; + +- ret = sscanf(c, "%d %d %d %x %lx %31s\n", ++ ret = sscanf(c, "%d %d %d %x %u %31s\n", + &port, &status, &speed, +- &devid, &socket, lbusid); ++ &devid, &sockfd, lbusid); + + if (ret < 5) { + dbg("sscanf failed: %d", ret); +@@ -69,7 +69,7 @@ static int parse_status(const char *valu + + dbg("port %d status %d speed %d devid %x", + 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 */ -- 2.47.3