Skip to content

Commit e8033bd

Browse files
xairygregkh
authored andcommitted
usb: raw-gadget: properly handle interrupted requests
Currently, if a USB request that was queued by Raw Gadget is interrupted (via a signal), wait_for_completion_interruptible returns -ERESTARTSYS. Raw Gadget then attempts to propagate this value to userspace as a return value from its ioctls. However, when -ERESTARTSYS is returned by a syscall handler, the kernel internally restarts the syscall. This doesn't allow userspace applications to interrupt requests queued by Raw Gadget (which is required when the emulated device is asked to switch altsettings). It also violates the implied interface of Raw Gadget that a single ioctl must only queue a single USB request. Instead, make Raw Gadget do what GadgetFS does: check whether the request was interrupted (dequeued with status == -ECONNRESET) and report -EINTR to userspace. Fixes: f2c2e71 ("usb: gadget: add raw-gadget interface") Cc: stable <stable@kernel.org> Signed-off-by: Andrey Konovalov <andreyknvl@gmail.com> Link: https://lore.kernel.org/r/0db45b1d7cc466e3d4d1ab353f61d63c977fbbc5.1698350424.git.andreyknvl@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 2998874 commit e8033bd

1 file changed

Lines changed: 16 additions & 10 deletions

File tree

drivers/usb/gadget/legacy/raw_gadget.c

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -674,12 +674,12 @@ static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
674674
if (WARN_ON(in && dev->ep0_out_pending)) {
675675
ret = -ENODEV;
676676
dev->state = STATE_DEV_FAILED;
677-
goto out_done;
677+
goto out_unlock;
678678
}
679679
if (WARN_ON(!in && dev->ep0_in_pending)) {
680680
ret = -ENODEV;
681681
dev->state = STATE_DEV_FAILED;
682-
goto out_done;
682+
goto out_unlock;
683683
}
684684

685685
dev->req->buf = data;
@@ -694,7 +694,7 @@ static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
694694
"fail, usb_ep_queue returned %d\n", ret);
695695
spin_lock_irqsave(&dev->lock, flags);
696696
dev->state = STATE_DEV_FAILED;
697-
goto out_done;
697+
goto out_queue_failed;
698698
}
699699

700700
ret = wait_for_completion_interruptible(&dev->ep0_done);
@@ -703,13 +703,16 @@ static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
703703
usb_ep_dequeue(dev->gadget->ep0, dev->req);
704704
wait_for_completion(&dev->ep0_done);
705705
spin_lock_irqsave(&dev->lock, flags);
706-
goto out_done;
706+
if (dev->ep0_status == -ECONNRESET)
707+
dev->ep0_status = -EINTR;
708+
goto out_interrupted;
707709
}
708710

709711
spin_lock_irqsave(&dev->lock, flags);
710-
ret = dev->ep0_status;
711712

712-
out_done:
713+
out_interrupted:
714+
ret = dev->ep0_status;
715+
out_queue_failed:
713716
dev->ep0_urb_queued = false;
714717
out_unlock:
715718
spin_unlock_irqrestore(&dev->lock, flags);
@@ -1078,7 +1081,7 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
10781081
"fail, usb_ep_queue returned %d\n", ret);
10791082
spin_lock_irqsave(&dev->lock, flags);
10801083
dev->state = STATE_DEV_FAILED;
1081-
goto out_done;
1084+
goto out_queue_failed;
10821085
}
10831086

10841087
ret = wait_for_completion_interruptible(&done);
@@ -1087,13 +1090,16 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
10871090
usb_ep_dequeue(ep->ep, ep->req);
10881091
wait_for_completion(&done);
10891092
spin_lock_irqsave(&dev->lock, flags);
1090-
goto out_done;
1093+
if (ep->status == -ECONNRESET)
1094+
ep->status = -EINTR;
1095+
goto out_interrupted;
10911096
}
10921097

10931098
spin_lock_irqsave(&dev->lock, flags);
1094-
ret = ep->status;
10951099

1096-
out_done:
1100+
out_interrupted:
1101+
ret = ep->status;
1102+
out_queue_failed:
10971103
ep->urb_queued = false;
10981104
out_unlock:
10991105
spin_unlock_irqrestore(&dev->lock, flags);

0 commit comments

Comments
 (0)