diff options
author | Larry Finger <Larry.Finger@lwfinger.net> | 2009-11-05 11:37:03 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-12-11 14:55:20 -0500 |
commit | 85e034fdff2af6befc55904f3ab9cc5aa31be8fe (patch) | |
tree | 6128ed2bcfd50c1dedcf3cb61e752266708fdef5 /drivers/usb/core | |
parent | 796c8c78801ebf1bdebddda06a43276355ff91eb (diff) |
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: Larry Finger <Larry.Finger@lwfinger.net>
Cc: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/core')
-rw-r--r-- | drivers/usb/core/hcd.c | 14 |
1 files changed, 10 insertions, 4 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 34de475f016e..026ab2fe5c2d 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c | |||
@@ -1275,13 +1275,16 @@ static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, | |||
1275 | 1275 | ||
1276 | if (usb_endpoint_xfer_control(&urb->ep->desc) | 1276 | if (usb_endpoint_xfer_control(&urb->ep->desc) |
1277 | && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) { | 1277 | && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) { |
1278 | if (hcd->self.uses_dma) | 1278 | if (hcd->self.uses_dma) { |
1279 | urb->setup_dma = dma_map_single( | 1279 | urb->setup_dma = dma_map_single( |
1280 | hcd->self.controller, | 1280 | hcd->self.controller, |
1281 | urb->setup_packet, | 1281 | urb->setup_packet, |
1282 | sizeof(struct usb_ctrlrequest), | 1282 | sizeof(struct usb_ctrlrequest), |
1283 | DMA_TO_DEVICE); | 1283 | DMA_TO_DEVICE); |
1284 | else if (hcd->driver->flags & HCD_LOCAL_MEM) | 1284 | if (dma_mapping_error(hcd->self.controller, |
1285 | urb->setup_dma)) | ||
1286 | return -EAGAIN; | ||
1287 | } else if (hcd->driver->flags & HCD_LOCAL_MEM) | ||
1285 | ret = hcd_alloc_coherent( | 1288 | ret = hcd_alloc_coherent( |
1286 | urb->dev->bus, mem_flags, | 1289 | urb->dev->bus, mem_flags, |
1287 | &urb->setup_dma, | 1290 | &urb->setup_dma, |
@@ -1293,13 +1296,16 @@ static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, | |||
1293 | dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; | 1296 | dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; |
1294 | if (ret == 0 && urb->transfer_buffer_length != 0 | 1297 | if (ret == 0 && urb->transfer_buffer_length != 0 |
1295 | && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) { | 1298 | && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) { |
1296 | if (hcd->self.uses_dma) | 1299 | if (hcd->self.uses_dma) { |
1297 | urb->transfer_dma = dma_map_single ( | 1300 | urb->transfer_dma = dma_map_single ( |
1298 | hcd->self.controller, | 1301 | hcd->self.controller, |
1299 | urb->transfer_buffer, | 1302 | urb->transfer_buffer, |
1300 | urb->transfer_buffer_length, | 1303 | urb->transfer_buffer_length, |
1301 | dir); | 1304 | dir); |
1302 | else if (hcd->driver->flags & HCD_LOCAL_MEM) { | 1305 | if (dma_mapping_error(hcd->self.controller, |
1306 | urb->transfer_dma)) | ||
1307 | return -EAGAIN; | ||
1308 | } else if (hcd->driver->flags & HCD_LOCAL_MEM) { | ||
1303 | ret = hcd_alloc_coherent( | 1309 | ret = hcd_alloc_coherent( |
1304 | urb->dev->bus, mem_flags, | 1310 | urb->dev->bus, mem_flags, |
1305 | &urb->transfer_dma, | 1311 | &urb->transfer_dma, |