Skip to content

Commit 4e9c93a

Browse files
shuahkhgregkh
authored andcommitted
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. Cc: [email protected] Reported-and-tested-by: [email protected] Signed-off-by: Shuah Khan <[email protected]> Link: https://lore.kernel.org/r/b6568f7beae702bbc236a545d3c020106ca75eac.1616807117.git.skhan@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 3004fcb commit 4e9c93a

File tree

3 files changed

+29
-5
lines changed

3 files changed

+29
-5
lines changed

drivers/usb/usbip/usbip_common.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,9 @@ struct usbip_device {
263263
/* lock for status */
264264
spinlock_t lock;
265265

266+
/* mutex for synchronizing sysfs store paths */
267+
struct mutex sysfs_lock;
268+
266269
int sockfd;
267270
struct socket *tcp_socket;
268271

drivers/usb/usbip/vhci_hcd.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,6 +1101,7 @@ static void vhci_device_init(struct vhci_device *vdev)
11011101
vdev->ud.side = USBIP_VHCI;
11021102
vdev->ud.status = VDEV_ST_NULL;
11031103
spin_lock_init(&vdev->ud.lock);
1104+
mutex_init(&vdev->ud.sysfs_lock);
11041105

11051106
INIT_LIST_HEAD(&vdev->priv_rx);
11061107
INIT_LIST_HEAD(&vdev->priv_tx);

drivers/usb/usbip/vhci_sysfs.c

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,8 @@ static int vhci_port_disconnect(struct vhci_hcd *vhci_hcd, __u32 rhport)
185185

186186
usbip_dbg_vhci_sysfs("enter\n");
187187

188+
mutex_lock(&vdev->ud.sysfs_lock);
189+
188190
/* lock */
189191
spin_lock_irqsave(&vhci->lock, flags);
190192
spin_lock(&vdev->ud.lock);
@@ -195,6 +197,7 @@ static int vhci_port_disconnect(struct vhci_hcd *vhci_hcd, __u32 rhport)
195197
/* unlock */
196198
spin_unlock(&vdev->ud.lock);
197199
spin_unlock_irqrestore(&vhci->lock, flags);
200+
mutex_unlock(&vdev->ud.sysfs_lock);
198201

199202
return -EINVAL;
200203
}
@@ -205,6 +208,8 @@ static int vhci_port_disconnect(struct vhci_hcd *vhci_hcd, __u32 rhport)
205208

206209
usbip_event_add(&vdev->ud, VDEV_EVENT_DOWN);
207210

211+
mutex_unlock(&vdev->ud.sysfs_lock);
212+
208213
return 0;
209214
}
210215

@@ -349,30 +354,36 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr,
349354
else
350355
vdev = &vhci->vhci_hcd_hs->vdev[rhport];
351356

357+
mutex_lock(&vdev->ud.sysfs_lock);
358+
352359
/* Extract socket from fd. */
353360
socket = sockfd_lookup(sockfd, &err);
354361
if (!socket) {
355362
dev_err(dev, "failed to lookup sock");
356-
return -EINVAL;
363+
err = -EINVAL;
364+
goto unlock_mutex;
357365
}
358366
if (socket->type != SOCK_STREAM) {
359367
dev_err(dev, "Expecting SOCK_STREAM - found %d",
360368
socket->type);
361369
sockfd_put(socket);
362-
return -EINVAL;
370+
err = -EINVAL;
371+
goto unlock_mutex;
363372
}
364373

365374
/* create threads before locking */
366375
tcp_rx = kthread_create(vhci_rx_loop, &vdev->ud, "vhci_rx");
367376
if (IS_ERR(tcp_rx)) {
368377
sockfd_put(socket);
369-
return -EINVAL;
378+
err = -EINVAL;
379+
goto unlock_mutex;
370380
}
371381
tcp_tx = kthread_create(vhci_tx_loop, &vdev->ud, "vhci_tx");
372382
if (IS_ERR(tcp_tx)) {
373383
kthread_stop(tcp_rx);
374384
sockfd_put(socket);
375-
return -EINVAL;
385+
err = -EINVAL;
386+
goto unlock_mutex;
376387
}
377388

378389
/* get task structs now */
@@ -397,7 +408,8 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr,
397408
* Will be retried from userspace
398409
* if there's another free port.
399410
*/
400-
return -EBUSY;
411+
err = -EBUSY;
412+
goto unlock_mutex;
401413
}
402414

403415
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,
423435

424436
rh_port_connect(vdev, speed);
425437

438+
dev_info(dev, "Device attached\n");
439+
440+
mutex_unlock(&vdev->ud.sysfs_lock);
441+
426442
return count;
443+
444+
unlock_mutex:
445+
mutex_unlock(&vdev->ud.sysfs_lock);
446+
return err;
427447
}
428448
static DEVICE_ATTR_WO(attach);
429449

0 commit comments

Comments
 (0)