From eebb17ca52bc0295aebb60e97e2663493cb457e5 Mon Sep 17 00:00:00 2001 From: Andy Ross Date: Fri, 14 Jul 2017 09:33:18 -0700 Subject: [PATCH] usb_dc_dw: Correctness: use bytewise I/O in FIFO fill The Designware FIFO is filled in units of 32 bit words, but the buffer we are passed is not guaranteed to be a multiple of 4 bytes long, nor aligned on a 4-byte boundary. So in theory we are reading 0-3 bytes of unused garbage from the end of the array. That's currently benign on supported platforms with this hardware, which all support misaligned reads. But not all do. And the incoming arrival of memory protection opens the possibility that those extra bytes would cross a protection boundary and cause a crash or security bug. Do this right. (Note that this is fixed to little endian byte order. The Designware databook is frustratingly silent on the endianness it expects, but existing hardware I can see is definitely LE and I see a few spots in the Linux dwc2 driver that likewise assume LE). Signed-off-by: Andy Ross --- drivers/usb/device/usb_dc_dw.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/usb/device/usb_dc_dw.c b/drivers/usb/device/usb_dc_dw.c index a1d0af9e53b..07560e7d287 100644 --- a/drivers/usb/device/usb_dc_dw.c +++ b/drivers/usb/device/usb_dc_dw.c @@ -486,7 +486,18 @@ static int usb_dw_tx(u8_t ep, const u8_t *const data, * before accessing the register." */ for (i = 0; i < data_len; i += 4) { - USB_DW_EP_FIFO(ep_idx) = *(u32_t *)(data + i); + u32_t val = data[i]; + + if (i + 1 < data_len) { + val |= ((u32_t)data[i+1]) << 8; + } + if (i + 2 < data_len) { + val |= ((u32_t)data[i+2]) << 16; + } + if (i + 3 < data_len) { + val |= ((u32_t)data[i+3]) << 24; + } + USB_DW_EP_FIFO(ep_idx) = val; } irq_unlock(key);