Commit 85e034fd authored by Larry Finger's avatar Larry Finger Committed by Greg Kroah-Hartman

USB: Check results of dma_map_single

In map_urb_for_dma(), the DMA address returned by dma_map_single()
is not checked to determine if it is legal. This lack of checking
contributed to a problem with the libertas wireless driver
(http://marc.info/?l=linux-wireless&m=125695331205062&w=2). The
difficulty was not detected until the buffer was unmapped. By this time
memory corruption had occurred.

The situation is fixed by testing the returned DMA address, and
returning -EAGAIN if the address is invalid.
Signed-off-by: default avatarLarry Finger <Larry.Finger@lwfinger.net>
Cc: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 796c8c78
...@@ -1275,13 +1275,16 @@ static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, ...@@ -1275,13 +1275,16 @@ static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
if (usb_endpoint_xfer_control(&urb->ep->desc) if (usb_endpoint_xfer_control(&urb->ep->desc)
&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) { && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
if (hcd->self.uses_dma) if (hcd->self.uses_dma) {
urb->setup_dma = dma_map_single( urb->setup_dma = dma_map_single(
hcd->self.controller, hcd->self.controller,
urb->setup_packet, urb->setup_packet,
sizeof(struct usb_ctrlrequest), sizeof(struct usb_ctrlrequest),
DMA_TO_DEVICE); DMA_TO_DEVICE);
else if (hcd->driver->flags & HCD_LOCAL_MEM) if (dma_mapping_error(hcd->self.controller,
urb->setup_dma))
return -EAGAIN;
} else if (hcd->driver->flags & HCD_LOCAL_MEM)
ret = hcd_alloc_coherent( ret = hcd_alloc_coherent(
urb->dev->bus, mem_flags, urb->dev->bus, mem_flags,
&urb->setup_dma, &urb->setup_dma,
...@@ -1293,13 +1296,16 @@ static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, ...@@ -1293,13 +1296,16 @@ static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
if (ret == 0 && urb->transfer_buffer_length != 0 if (ret == 0 && urb->transfer_buffer_length != 0
&& !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) { && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
if (hcd->self.uses_dma) if (hcd->self.uses_dma) {
urb->transfer_dma = dma_map_single ( urb->transfer_dma = dma_map_single (
hcd->self.controller, hcd->self.controller,
urb->transfer_buffer, urb->transfer_buffer,
urb->transfer_buffer_length, urb->transfer_buffer_length,
dir); dir);
else if (hcd->driver->flags & HCD_LOCAL_MEM) { if (dma_mapping_error(hcd->self.controller,
urb->transfer_dma))
return -EAGAIN;
} else if (hcd->driver->flags & HCD_LOCAL_MEM) {
ret = hcd_alloc_coherent( ret = hcd_alloc_coherent(
urb->dev->bus, mem_flags, urb->dev->bus, mem_flags,
&urb->transfer_dma, &urb->transfer_dma,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment