Skip to content

Commit 45285db

Browse files
xairygregkh
authored andcommitted
usb: raw-gadget: properly handle interrupted requests
commit e8033bd upstream. 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 b37a168 commit 45285db

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
@@ -663,12 +663,12 @@ static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
663663
if (WARN_ON(in && dev->ep0_out_pending)) {
664664
ret = -ENODEV;
665665
dev->state = STATE_DEV_FAILED;
666-
goto out_done;
666+
goto out_unlock;
667667
}
668668
if (WARN_ON(!in && dev->ep0_in_pending)) {
669669
ret = -ENODEV;
670670
dev->state = STATE_DEV_FAILED;
671-
goto out_done;
671+
goto out_unlock;
672672
}
673673

674674
dev->req->buf = data;
@@ -683,7 +683,7 @@ static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
683683
"fail, usb_ep_queue returned %d\n", ret);
684684
spin_lock_irqsave(&dev->lock, flags);
685685
dev->state = STATE_DEV_FAILED;
686-
goto out_done;
686+
goto out_queue_failed;
687687
}
688688

689689
ret = wait_for_completion_interruptible(&dev->ep0_done);
@@ -692,13 +692,16 @@ static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
692692
usb_ep_dequeue(dev->gadget->ep0, dev->req);
693693
wait_for_completion(&dev->ep0_done);
694694
spin_lock_irqsave(&dev->lock, flags);
695-
goto out_done;
695+
if (dev->ep0_status == -ECONNRESET)
696+
dev->ep0_status = -EINTR;
697+
goto out_interrupted;
696698
}
697699

698700
spin_lock_irqsave(&dev->lock, flags);
699-
ret = dev->ep0_status;
700701

701-
out_done:
702+
out_interrupted:
703+
ret = dev->ep0_status;
704+
out_queue_failed:
702705
dev->ep0_urb_queued = false;
703706
out_unlock:
704707
spin_unlock_irqrestore(&dev->lock, flags);
@@ -1067,7 +1070,7 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
10671070
"fail, usb_ep_queue returned %d\n", ret);
10681071
spin_lock_irqsave(&dev->lock, flags);
10691072
dev->state = STATE_DEV_FAILED;
1070-
goto out_done;
1073+
goto out_queue_failed;
10711074
}
10721075

10731076
ret = wait_for_completion_interruptible(&done);
@@ -1076,13 +1079,16 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
10761079
usb_ep_dequeue(ep->ep, ep->req);
10771080
wait_for_completion(&done);
10781081
spin_lock_irqsave(&dev->lock, flags);
1079-
goto out_done;
1082+
if (ep->status == -ECONNRESET)
1083+
ep->status = -EINTR;
1084+
goto out_interrupted;
10801085
}
10811086

10821087
spin_lock_irqsave(&dev->lock, flags);
1083-
ret = ep->status;
10841088

1085-
out_done:
1089+
out_interrupted:
1090+
ret = ep->status;
1091+
out_queue_failed:
10861092
ep->urb_queued = false;
10871093
out_unlock:
10881094
spin_unlock_irqrestore(&dev->lock, flags);

0 commit comments

Comments
 (0)