aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaro Koskinen <aaro.koskinen@iki.fi>2014-03-19 18:52:08 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-03-19 21:51:12 -0400
commit120ee599b5bf4273992ef9c6ac2a316cc3630969 (patch)
treecf7dfff66201ac9deb2d7f283e6e34a1a25416c3
parent7923a6551edebefeaf4638ecfe18b958bf33c18b (diff)
staging: octeon-usb: prevent memory corruption
octeon-hcd will crash the kernel when SLOB is used. This usually happens after the 18-byte control transfer when a device descriptor is read. The DMA engine is always transfering full 32-bit words and if the transfer is shorter, some random garbage appears after the buffer. The problem is not visible with SLUB since it rounds up the allocations to word boundary, and the extra bytes will go undetected. Fix by providing quirk functions for DMA map/unmap that allocate a bigger temporary buffer when necessary. Tested by booting EdgeRouter Lite to USB stick root file system with SLAB, SLOB and SLUB kernels. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=72121 Reported-by: Sergey Popov <pinkbyte@gentoo.org> Signed-off-by: Aaro Koskinen <aaro.koskinen@iki.fi> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/staging/octeon-usb/octeon-hcd.c108
1 files changed, 108 insertions, 0 deletions
diff --git a/drivers/staging/octeon-usb/octeon-hcd.c b/drivers/staging/octeon-usb/octeon-hcd.c
index 55380b349f95..8b8ce7293c52 100644
--- a/drivers/staging/octeon-usb/octeon-hcd.c
+++ b/drivers/staging/octeon-usb/octeon-hcd.c
@@ -465,6 +465,112 @@ struct octeon_hcd {
465#define USB_FIFO_ADDRESS(channel, usb_index) (CVMX_USBCX_GOTGCTL(usb_index) + ((channel)+1)*0x1000) 465#define USB_FIFO_ADDRESS(channel, usb_index) (CVMX_USBCX_GOTGCTL(usb_index) + ((channel)+1)*0x1000)
466 466
467/** 467/**
468 * struct octeon_temp_buffer - a bounce buffer for USB transfers
469 * @temp_buffer: the newly allocated temporary buffer (including meta-data)
470 * @orig_buffer: the original buffer passed by the USB stack
471 * @data: the newly allocated temporary buffer (excluding meta-data)
472 *
473 * Both the DMA engine and FIFO mode will always transfer full 32-bit words. If
474 * the buffer is too short, we need to allocate a temporary one, and this struct
475 * represents it.
476 */
477struct octeon_temp_buffer {
478 void *temp_buffer;
479 void *orig_buffer;
480 u8 data[0];
481};
482
483/**
484 * octeon_alloc_temp_buffer - allocate a temporary buffer for USB transfer
485 * (if needed)
486 * @urb: URB.
487 * @mem_flags: Memory allocation flags.
488 *
489 * This function allocates a temporary bounce buffer whenever it's needed
490 * due to HW limitations.
491 */
492static int octeon_alloc_temp_buffer(struct urb *urb, gfp_t mem_flags)
493{
494 struct octeon_temp_buffer *temp;
495
496 if (urb->num_sgs || urb->sg ||
497 (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) ||
498 !(urb->transfer_buffer_length % sizeof(u32)))
499 return 0;
500
501 temp = kmalloc(ALIGN(urb->transfer_buffer_length, sizeof(u32)) +
502 sizeof(*temp), mem_flags);
503 if (!temp)
504 return -ENOMEM;
505
506 temp->temp_buffer = temp;
507 temp->orig_buffer = urb->transfer_buffer;
508 if (usb_urb_dir_out(urb))
509 memcpy(temp->data, urb->transfer_buffer,
510 urb->transfer_buffer_length);
511 urb->transfer_buffer = temp->data;
512 urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER;
513
514 return 0;
515}
516
517/**
518 * octeon_free_temp_buffer - free a temporary buffer used by USB transfers.
519 * @urb: URB.
520 *
521 * Frees a buffer allocated by octeon_alloc_temp_buffer().
522 */
523static void octeon_free_temp_buffer(struct urb *urb)
524{
525 struct octeon_temp_buffer *temp;
526
527 if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER))
528 return;
529
530 temp = container_of(urb->transfer_buffer, struct octeon_temp_buffer,
531 data);
532 if (usb_urb_dir_in(urb))
533 memcpy(temp->orig_buffer, urb->transfer_buffer,
534 urb->actual_length);
535 urb->transfer_buffer = temp->orig_buffer;
536 urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER;
537 kfree(temp->temp_buffer);
538}
539
540/**
541 * octeon_map_urb_for_dma - Octeon-specific map_urb_for_dma().
542 * @hcd: USB HCD structure.
543 * @urb: URB.
544 * @mem_flags: Memory allocation flags.
545 */
546static int octeon_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
547 gfp_t mem_flags)
548{
549 int ret;
550
551 ret = octeon_alloc_temp_buffer(urb, mem_flags);
552 if (ret)
553 return ret;
554
555 ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
556 if (ret)
557 octeon_free_temp_buffer(urb);
558
559 return ret;
560}
561
562/**
563 * octeon_unmap_urb_for_dma - Octeon-specific unmap_urb_for_dma()
564 * @hcd: USB HCD structure.
565 * @urb: URB.
566 */
567static void octeon_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
568{
569 usb_hcd_unmap_urb_for_dma(hcd, urb);
570 octeon_free_temp_buffer(urb);
571}
572
573/**
468 * Read a USB 32bit CSR. It performs the necessary address swizzle 574 * Read a USB 32bit CSR. It performs the necessary address swizzle
469 * for 32bit CSRs and logs the value in a readable format if 575 * for 32bit CSRs and logs the value in a readable format if
470 * debugging is on. 576 * debugging is on.
@@ -3601,6 +3707,8 @@ static const struct hc_driver octeon_hc_driver = {
3601 .get_frame_number = octeon_usb_get_frame_number, 3707 .get_frame_number = octeon_usb_get_frame_number,
3602 .hub_status_data = octeon_usb_hub_status_data, 3708 .hub_status_data = octeon_usb_hub_status_data,
3603 .hub_control = octeon_usb_hub_control, 3709 .hub_control = octeon_usb_hub_control,
3710 .map_urb_for_dma = octeon_map_urb_for_dma,
3711 .unmap_urb_for_dma = octeon_unmap_urb_for_dma,
3604}; 3712};
3605 3713
3606static int octeon_usb_probe(struct platform_device *pdev) 3714static int octeon_usb_probe(struct platform_device *pdev)