usb: gadget: f_hid: fixed NULL pointer dereference
commit 2867652e4766360adf14dfda3832455e04964f2a upstream.
Disconnecting and reconnecting the USB cable can lead to crashes
and a variety of kernel log spam.
The problem was found and reproduced on the Raspberry Pi [1]
and the original fix was created in Raspberry's own fork [2].
Link: https://github.com/raspberrypi/linux/issues/3870 [1]
Link: a6e47d5f4e
[2]
Signed-off-by: Maxim Devaev <mdevaev@gmail.com>
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
Cc: stable <stable@vger.kernel.org>
Link: https://lore.kernel.org/r/20210723155928.210019-1-mdevaev@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
683702dff7
commit
825ac3f0bc
@@ -339,6 +339,11 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer,
|
|||||||
|
|
||||||
spin_lock_irqsave(&hidg->write_spinlock, flags);
|
spin_lock_irqsave(&hidg->write_spinlock, flags);
|
||||||
|
|
||||||
|
if (!hidg->req) {
|
||||||
|
spin_unlock_irqrestore(&hidg->write_spinlock, flags);
|
||||||
|
return -ESHUTDOWN;
|
||||||
|
}
|
||||||
|
|
||||||
#define WRITE_COND (!hidg->write_pending)
|
#define WRITE_COND (!hidg->write_pending)
|
||||||
try_again:
|
try_again:
|
||||||
/* write queue */
|
/* write queue */
|
||||||
@@ -359,8 +364,14 @@ try_again:
|
|||||||
count = min_t(unsigned, count, hidg->report_length);
|
count = min_t(unsigned, count, hidg->report_length);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&hidg->write_spinlock, flags);
|
spin_unlock_irqrestore(&hidg->write_spinlock, flags);
|
||||||
status = copy_from_user(req->buf, buffer, count);
|
|
||||||
|
|
||||||
|
if (!req) {
|
||||||
|
ERROR(hidg->func.config->cdev, "hidg->req is NULL\n");
|
||||||
|
status = -ESHUTDOWN;
|
||||||
|
goto release_write_pending;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = copy_from_user(req->buf, buffer, count);
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
ERROR(hidg->func.config->cdev,
|
ERROR(hidg->func.config->cdev,
|
||||||
"copy_from_user error\n");
|
"copy_from_user error\n");
|
||||||
@@ -388,15 +399,18 @@ try_again:
|
|||||||
|
|
||||||
spin_unlock_irqrestore(&hidg->write_spinlock, flags);
|
spin_unlock_irqrestore(&hidg->write_spinlock, flags);
|
||||||
|
|
||||||
status = usb_ep_queue(hidg->in_ep, req, GFP_ATOMIC);
|
if (!hidg->in_ep->enabled) {
|
||||||
if (status < 0) {
|
ERROR(hidg->func.config->cdev, "in_ep is disabled\n");
|
||||||
ERROR(hidg->func.config->cdev,
|
status = -ESHUTDOWN;
|
||||||
"usb_ep_queue error on int endpoint %zd\n", status);
|
|
||||||
goto release_write_pending;
|
goto release_write_pending;
|
||||||
} else {
|
|
||||||
status = count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status = usb_ep_queue(hidg->in_ep, req, GFP_ATOMIC);
|
||||||
|
if (status < 0)
|
||||||
|
goto release_write_pending;
|
||||||
|
else
|
||||||
|
status = count;
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
release_write_pending:
|
release_write_pending:
|
||||||
spin_lock_irqsave(&hidg->write_spinlock, flags);
|
spin_lock_irqsave(&hidg->write_spinlock, flags);
|
||||||
|
Reference in New Issue
Block a user