usb: musb: fix crash with highmen PIO and usbmon
When handling a PIO bulk transfer with highmem buffer, a temporary
mapping is assigned to urb->transfer_buffer. After the transfer is
complete, an invalid address is left behind in this pointer. This is
not ordinarily a problem since nothing touches that buffer before the
urb is released. However, when usbmon is active, usbmon_urb_complete()
calls (indirectly) mon_bin_get_data() which does access the transfer
buffer if it is set. To prevent an invalid memory access here, reset
urb->transfer_buffer to NULL when finished (musb_host_rx()), or do not
set it at all (musb_host_tx()).
Fixes: 8e8a551654
("usb: musb: host: Handle highmem in PIO mode")
Signed-off-by: Mans Rullgard <mans@mansr.com>
Cc: stable@vger.kernel.org
Signed-off-by: Bin Liu <b-liu@ti.com>
Link: https://lore.kernel.org/r/20200316211136.2274-8-b-liu@ti.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
e72838d47d
commit
52974d94a2
|
@ -1436,10 +1436,7 @@ done:
|
||||||
* We need to map sg if the transfer_buffer is
|
* We need to map sg if the transfer_buffer is
|
||||||
* NULL.
|
* NULL.
|
||||||
*/
|
*/
|
||||||
if (!urb->transfer_buffer)
|
if (!urb->transfer_buffer) {
|
||||||
qh->use_sg = true;
|
|
||||||
|
|
||||||
if (qh->use_sg) {
|
|
||||||
/* sg_miter_start is already done in musb_ep_program */
|
/* sg_miter_start is already done in musb_ep_program */
|
||||||
if (!sg_miter_next(&qh->sg_miter)) {
|
if (!sg_miter_next(&qh->sg_miter)) {
|
||||||
dev_err(musb->controller, "error: sg list empty\n");
|
dev_err(musb->controller, "error: sg list empty\n");
|
||||||
|
@ -1447,9 +1444,8 @@ done:
|
||||||
status = -EINVAL;
|
status = -EINVAL;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
urb->transfer_buffer = qh->sg_miter.addr;
|
|
||||||
length = min_t(u32, length, qh->sg_miter.length);
|
length = min_t(u32, length, qh->sg_miter.length);
|
||||||
musb_write_fifo(hw_ep, length, urb->transfer_buffer);
|
musb_write_fifo(hw_ep, length, qh->sg_miter.addr);
|
||||||
qh->sg_miter.consumed = length;
|
qh->sg_miter.consumed = length;
|
||||||
sg_miter_stop(&qh->sg_miter);
|
sg_miter_stop(&qh->sg_miter);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1458,11 +1454,6 @@ done:
|
||||||
|
|
||||||
qh->segsize = length;
|
qh->segsize = length;
|
||||||
|
|
||||||
if (qh->use_sg) {
|
|
||||||
if (offset + length >= urb->transfer_buffer_length)
|
|
||||||
qh->use_sg = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
musb_ep_select(mbase, epnum);
|
musb_ep_select(mbase, epnum);
|
||||||
musb_writew(epio, MUSB_TXCSR,
|
musb_writew(epio, MUSB_TXCSR,
|
||||||
MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY);
|
MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY);
|
||||||
|
@ -1977,8 +1968,10 @@ finish:
|
||||||
urb->actual_length += xfer_len;
|
urb->actual_length += xfer_len;
|
||||||
qh->offset += xfer_len;
|
qh->offset += xfer_len;
|
||||||
if (done) {
|
if (done) {
|
||||||
if (qh->use_sg)
|
if (qh->use_sg) {
|
||||||
qh->use_sg = false;
|
qh->use_sg = false;
|
||||||
|
urb->transfer_buffer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (urb->status == -EINPROGRESS)
|
if (urb->status == -EINPROGRESS)
|
||||||
urb->status = status;
|
urb->status = status;
|
||||||
|
|
Loading…
Reference in New Issue