2020-03-09 15:28:12

by Måns Rullgård

[permalink] [raw]
Subject: [PATCH v2] 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->tranfer_buffer to NULL when finished (musb_host_rx()), or do not
set it at all (musb_host_tx()).

Fixes: 8e8a55165469 ("usb: musb: host: Handle highmem in PIO mode")
Signed-off-by: Mans Rullgard <[email protected]>
---
Changed in v2:
- Do not set urb->transfer_buffer in musb_host_tx()
---
drivers/usb/musb/musb_host.c | 17 +++++------------
1 file changed, 5 insertions(+), 12 deletions(-)

diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 1c813c37462a..8736f4251a22 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -1436,10 +1436,7 @@ void musb_host_tx(struct musb *musb, u8 epnum)
* We need to map sg if the transfer_buffer is
* NULL.
*/
- if (!urb->transfer_buffer)
- qh->use_sg = true;
-
- if (qh->use_sg) {
+ if (!urb->transfer_buffer) {
/* sg_miter_start is already done in musb_ep_program */
if (!sg_miter_next(&qh->sg_miter)) {
dev_err(musb->controller, "error: sg list empty\n");
@@ -1447,9 +1444,8 @@ void musb_host_tx(struct musb *musb, u8 epnum)
status = -EINVAL;
goto done;
}
- urb->transfer_buffer = qh->sg_miter.addr;
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;
sg_miter_stop(&qh->sg_miter);
} else {
@@ -1458,11 +1454,6 @@ void musb_host_tx(struct musb *musb, u8 epnum)

qh->segsize = length;

- if (qh->use_sg) {
- if (offset + length >= urb->transfer_buffer_length)
- qh->use_sg = false;
- }
-
musb_ep_select(mbase, epnum);
musb_writew(epio, MUSB_TXCSR,
MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY);
@@ -1977,8 +1968,10 @@ void musb_host_rx(struct musb *musb, u8 epnum)
urb->actual_length += xfer_len;
qh->offset += xfer_len;
if (done) {
- if (qh->use_sg)
+ if (qh->use_sg) {
qh->use_sg = false;
+ urb->transfer_buffer = NULL;
+ }

if (urb->status == -EINPROGRESS)
urb->status = status;
--
2.25.1


2020-03-09 16:11:59

by Bin Liu

[permalink] [raw]
Subject: Re: [PATCH v2] usb: musb: fix crash with highmen PIO and usbmon

On Mon, Mar 09, 2020 at 03:26:53PM +0000, Mans Rullgard wrote:
> 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->tranfer_buffer to NULL when finished (musb_host_rx()), or do not

WARNING: 'tranfer' may be misspelled

I have fixed it locally.

> set it at all (musb_host_tx()).
>
> Fixes: 8e8a55165469 ("usb: musb: host: Handle highmem in PIO mode")
> Signed-off-by: Mans Rullgard <[email protected]>

Applied. Thanks.
-Bin.