usbip synchronize sysfs code paths
Subsystems (3)
Shuah Khan
maintainercover usbip synchronize sysfs code paths
Fuzzing uncovered race condition between sysfs code paths in usbip drivers. Device connect/disconnect code paths initiated through sysfs interface are prone to races if disconnect happens during connect and vice versa.
This problem is common to all drivers while it can be reproduced easily in vhci_hcd. Add a sysfs_lock to usbip_device struct to protect the paths.
For a complete fix, all usbip drivers have to use sysfs_lock to protect sysfs code paths and common event handler will have to use this lock to synchonize with the sysfs paths in drivers.
This patch series adds sysfs_lock and uses it in vhci_hcd in the first patch. Subsequent patches fix usbip_host, vudc and the last patch fixes the common event handler code path.
Shuah Khan (4):
usbip: add sysfs_lock to synchronize sysfs code paths
usbip: stub-dev synchronize sysfs code paths
usbip: vudc synchronize sysfs code paths
usbip: synchronize event handler with sysfs code paths
drivers/usb/usbip/stub_dev.c | 11 +++++++++-- drivers/usb/usbip/usbip_common.h | 3 +++ drivers/usb/usbip/usbip_event.c | 2 ++ drivers/usb/usbip/vhci_hcd.c | 1 + drivers/usb/usbip/vhci_sysfs.c | 30 +++++++++++++++++++++++++----- drivers/usb/usbip/vudc_dev.c | 1 + drivers/usb/usbip/vudc_sysfs.c | 5 +++++ 7 files changed, 46 insertions(+), 7 deletions(-)
Signature · 1 line
2.27.0
Shuah Khan
maintainerPATCH 1/4 usbip: add sysfs_lock to synchronize sysfs code paths
Fuzzing uncovered race condition between sysfs code paths in usbip drivers. Device connect/disconnect code paths initiated through sysfs interface are prone to races if disconnect happens during connect and vice versa.
This problem is common to all drivers while it can be reproduced easily in vhci_hcd. Add a sysfs_lock to usbip_device struct to protect the paths.
Use this in vhci_hcd to protect sysfs paths. For a complete fix, usip_host and usip-vudc drivers and the event handler will have to use this lock to protect the paths. These changes will be done in subsequent patches.
--- drivers/usb/usbip/usbip_common.h | 3 +++ drivers/usb/usbip/vhci_hcd.c | 1 + drivers/usb/usbip/vhci_sysfs.c | 30 +++++++++++++++++++++++++----- 3 files changed, 29 insertions(+), 5 deletions(-)
drivers/usb/usbip/usbip_common.h +3 -0
@@ -263,6 +263,9 @@ struct usbip_device {/* lock for status */ spinlock_t lock; +/* mutex for synchronizing sysfs store paths */ +struct mutex sysfs_lock; +int sockfd;struct socket *tcp_socket;
drivers/usb/usbip/vhci_hcd.c +1 -0
@@ -1101,6 +1101,7 @@ static void vhci_device_init(struct vhci_device *vdev) vdev->ud.side =USBIP_VHCI ; vdev->ud.status =VDEV_ST_NULL ;spin_lock_init (&vdev->ud.lock); +mutex_init (&vdev->ud.sysfs_lock);INIT_LIST_HEAD (&vdev->priv_rx);INIT_LIST_HEAD (&vdev->priv_tx);
drivers/usb/usbip/vhci_sysfs.c +25 -5
@@ -185,6 +185,8 @@ static int vhci_port_disconnect(struct vhci_hcd *vhci_hcd, __u32 rhport)usbip_dbg_vhci_sysfs ("enter\n" ); +mutex_lock (&vdev->ud.sysfs_lock); +/* lock */ spin_lock_irqsave (&vhci->lock, flags);spin_lock (&vdev->ud.lock);
@@ -195,6 +197,7 @@ static int vhci_port_disconnect(struct vhci_hcd *vhci_hcd, __u32 rhport)/* unlock */ spin_unlock (&vdev->ud.lock);spin_unlock_irqrestore (&vhci->lock, flags); +mutex_unlock (&vdev->ud.sysfs_lock);return -EINVAL ; }
@@ -205,6 +208,8 @@ static int vhci_port_disconnect(struct vhci_hcd *vhci_hcd, __u32 rhport)usbip_event_add (&vdev->ud,VDEV_EVENT_DOWN ); +mutex_unlock (&vdev->ud.sysfs_lock); +return 0 ; }
@@ -349,30 +354,36 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr,else vdev = &vhci->vhci_hcd_hs->vdev[rhport]; +mutex_lock (&vdev->ud.sysfs_lock); +/* Extract socket from fd. */ socket =sockfd_lookup (sockfd, &err);if (!socket) {dev_err (dev,"failed to lookup sock" ); -return -EINVAL ; + err = -EINVAL ; + goto unlock_mutex; }if (socket->type !=SOCK_STREAM ) {dev_err (dev,"Expecting SOCK_STREAM - found %d" , socket->type);sockfd_put (socket); -return -EINVAL ; + err = -EINVAL ; + goto unlock_mutex; }/* create threads before locking */ tcp_rx =kthread_create (vhci_rx_loop, &vdev->ud,"vhci_rx" );if (IS_ERR (tcp_rx)) {sockfd_put (socket); -return -EINVAL ; + err = -EINVAL ; + goto unlock_mutex; } tcp_tx =kthread_create (vhci_tx_loop, &vdev->ud,"vhci_tx" );if (IS_ERR (tcp_tx)) {kthread_stop (tcp_rx);sockfd_put (socket); -return -EINVAL ; + err = -EINVAL ; + goto unlock_mutex; }/* get task structs now */
@@ -397,7 +408,8 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr,* Will be retried from userspace * if there's another free port. */ -return -EBUSY ; + err = -EBUSY ; + goto unlock_mutex; } dev_info(dev, "pdev(%u) rhport(%u) sockfd(%d)\n",
@@ -423,7 +435,15 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr,rh_port_connect (vdev, speed); +dev_info (dev,"Device attached\n" ); + +mutex_unlock (&vdev->ud.sysfs_lock); +return count; + +unlock_mutex: +mutex_unlock (&vdev->ud.sysfs_lock); +return err; }static DEVICE_ATTR_WO (attach);
Signature · 1 line
2.27.0
Shuah Khan
maintainerPATCH 2/4 usbip: stub-dev synchronize sysfs code paths
In reply to Shuah KhanFuzzing uncovered race condition between sysfs code paths in usbip drivers. Device connect/disconnect code paths initiated through sysfs interface are prone to races if disconnect happens during connect and vice versa.
Use sysfs_lock to protect sysfs paths in stub-dev.
--- drivers/usb/usbip/stub_dev.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
drivers/usb/usbip/stub_dev.c +9 -2
@@ -63,6 +63,7 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *adev_info (dev,"stub up\n" ); +mutex_lock (&sdev->ud.sysfs_lock);spin_lock_irq (&sdev->ud.lock);if (sdev->ud.status !=SDEV_ST_AVAILABLE ) {
@@ -87,13 +88,13 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a tcp_rx =kthread_create (stub_rx_loop, &sdev->ud,"stub_rx" );if (IS_ERR (tcp_rx)) {sockfd_put (socket); -return -EINVAL ; + goto unlock_mutex; } tcp_tx =kthread_create (stub_tx_loop, &sdev->ud,"stub_tx" );if (IS_ERR (tcp_tx)) {kthread_stop (tcp_rx);sockfd_put (socket); -return -EINVAL ; + goto unlock_mutex; }/* get task structs now */
@@ -112,6 +113,8 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *awake_up_process (sdev->ud.tcp_rx);wake_up_process (sdev->ud.tcp_tx); +mutex_unlock (&sdev->ud.sysfs_lock); + }else {dev_info (dev,"stub down\n" );
@@ -122,6 +125,7 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *aspin_unlock_irq (&sdev->ud.lock);usbip_event_add (&sdev->ud,SDEV_EVENT_DOWN ); +mutex_unlock (&sdev->ud.sysfs_lock); }return count;
@@ -130,6 +134,8 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *asockfd_put (socket); err:spin_unlock_irq (&sdev->ud.lock); +unlock_mutex: +mutex_unlock (&sdev->ud.sysfs_lock);return -EINVAL ; }static DEVICE_ATTR_WO (usbip_sockfd);
@@ -270,6 +276,7 @@ static struct stub_device *stub_device_alloc(struct usb_device *udev) sdev->ud.side =USBIP_STUB ; sdev->ud.status =SDEV_ST_AVAILABLE ;spin_lock_init (&sdev->ud.lock); +mutex_init (&sdev->ud.sysfs_lock); sdev->ud.tcp_socket =NULL ; sdev->ud.sockfd =-1 ;
Signature · 1 line
2.27.0
Shuah Khan
maintainerPATCH 3/4 usbip: vudc synchronize sysfs code paths
In reply to Shuah KhanFuzzing uncovered race condition between sysfs code paths in usbip drivers. Device connect/disconnect code paths initiated through sysfs interface are prone to races if disconnect happens during connect and vice versa.
Use sysfs_lock to protect sysfs paths in vudc.
--- drivers/usb/usbip/vudc_dev.c | 1 + drivers/usb/usbip/vudc_sysfs.c | 5 +++++ 2 files changed, 6 insertions(+)
drivers/usb/usbip/vudc_dev.c +1 -0
@@ -572,6 +572,7 @@ static int init_vudc_hw(struct vudc *udc)init_waitqueue_head (&udc->tx_waitq);spin_lock_init (&ud->lock); +mutex_init (&ud->sysfs_lock); ud->status =SDEV_ST_AVAILABLE ; ud->side =USBIP_VUDC ;
drivers/usb/usbip/vudc_sysfs.c +5 -0
@@ -112,6 +112,7 @@ static ssize_t usbip_sockfd_store(struct device *dev,dev_err (dev,"no device" );return -ENODEV ; } +mutex_lock (&udc->ud.sysfs_lock);spin_lock_irqsave (&udc->lock, flags);/* Don't export what we don't have */ if (!udc->driver || !udc->pullup) {
@@ -187,6 +188,8 @@ static ssize_t usbip_sockfd_store(struct device *dev,wake_up_process (udc->ud.tcp_rx);wake_up_process (udc->ud.tcp_tx); + +mutex_unlock (&udc->ud.sysfs_lock);return count; }else {
@@ -207,6 +210,7 @@ static ssize_t usbip_sockfd_store(struct device *dev, }spin_unlock_irqrestore (&udc->lock, flags); +mutex_unlock (&udc->ud.sysfs_lock);return count;
@@ -216,6 +220,7 @@ static ssize_t usbip_sockfd_store(struct device *dev,spin_unlock_irq (&udc->ud.lock); unlock:spin_unlock_irqrestore (&udc->lock, flags); +mutex_unlock (&udc->ud.sysfs_lock);return ret; }
Signature · 1 line
2.27.0
Shuah Khan
maintainerPATCH 4/4 usbip: synchronize event handler with sysfs code paths
In reply to Shuah KhanFuzzing uncovered race condition between sysfs code paths in usbip drivers. Device connect/disconnect code paths initiated through sysfs interface are prone to races if disconnect happens during connect and vice versa.
Use sysfs_lock to synchronize event handler with sysfs paths in usbip drivers.
--- drivers/usb/usbip/usbip_event.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/usb/usbip/usbip_event.c +2 -0
@@ -70,6 +70,7 @@ static void event_handler(struct work_struct *work)while ((ud =get_event ()) !=NULL ) {usbip_dbg_eh ("pending event %lx\n" , ud->event); +mutex_lock (&ud->sysfs_lock);/* * NOTE: shutdown must come first. * Shutdown the device.
@@ -90,6 +91,7 @@ static void event_handler(struct work_struct *work) ud->eh_ops.unusable (ud);unset_event (ud,USBIP_EH_UNUSABLE ); } +mutex_unlock (&ud->sysfs_lock);wake_up (&ud->eh_waitq); }
Signature · 1 line
2.27.0