From 56a7bbd7412ae8dedca14877bb7aa45199de730c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Br=C3=BCns?= Date: Sun, 17 Jan 2016 04:09:51 +0100 Subject: [PATCH] usb: dwc2: Fix out-of-bounds access, fix chunk size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix two errors in transfer len calculation, move loop invariant code out of loop. If xfer_len is equal to CONFIG_DWC2_MAX_TRANSFER_SIZE (or slightly smaller), the xfer_len will be to large, e.g.: xfer_len = MAX_TRANSFER_SIZE = 65535 max packet size = 512 => num_packets = 128 => IN xfer_len = 65536 For OUT transactions larger than (65536 - mps) bytes, the xfer_len determination is quite awkward, it is only correct due to: - max_packet_size for control/bulk/interrupt is required to be power-of-two. - (CONFIG_DWC2_MAX_TRANSFER_SIZE + 1) % max-packet-size is zero for all allowed (2^3 ... 2^9) packet sizes As the max xfer len is loop invariant, it can be moved out of the loop. Signed-off-by: Stefan BrĂ¼ns --- drivers/usb/host/dwc2.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c index 5ef6debd9a..d317104028 100644 --- a/drivers/usb/host/dwc2.c +++ b/drivers/usb/host/dwc2.c @@ -786,34 +786,34 @@ int chunk_msg(struct dwc2_priv *priv, struct usb_device *dev, uint32_t xfer_len; uint32_t num_packets; int stop_transfer = 0; + uint32_t max_xfer_len; debug("%s: msg: pipe %lx pid %d in %d len %d\n", __func__, pipe, *pid, in, len); + max_xfer_len = CONFIG_DWC2_MAX_PACKET_COUNT * max; + if (max_xfer_len > CONFIG_DWC2_MAX_TRANSFER_SIZE) + max_xfer_len = CONFIG_DWC2_MAX_TRANSFER_SIZE; + if (max_xfer_len > DWC2_DATA_BUF_SIZE) + max_xfer_len = DWC2_DATA_BUF_SIZE; + + /* Make sure that max_xfer_len is a multiple of max packet size. */ + num_packets = max_xfer_len / max; + max_xfer_len = num_packets * max; + do { /* Initialize channel */ dwc_otg_hc_init(regs, DWC2_HC_CHANNEL, dev, devnum, ep, in, eptype, max); xfer_len = len - done; - if (xfer_len > CONFIG_DWC2_MAX_TRANSFER_SIZE) - xfer_len = CONFIG_DWC2_MAX_TRANSFER_SIZE - max + 1; - if (xfer_len > DWC2_DATA_BUF_SIZE) - xfer_len = DWC2_DATA_BUF_SIZE - max + 1; - /* Make sure that xfer_len is a multiple of max packet size. */ - if (xfer_len > 0) { + if (xfer_len > max_xfer_len) + xfer_len = max_xfer_len; + else if (xfer_len > max) num_packets = (xfer_len + max - 1) / max; - if (num_packets > CONFIG_DWC2_MAX_PACKET_COUNT) { - num_packets = CONFIG_DWC2_MAX_PACKET_COUNT; - xfer_len = num_packets * max; - } - } else { + else num_packets = 1; - } - - if (in) - xfer_len = num_packets * max; debug("%s: chunk: pid %d xfer_len %u pkts %u\n", __func__, *pid, xfer_len, num_packets);