Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Aaro Koskinen and committed by
Greg Kroah-Hartman
120ee599 7923a655

+108
+108
drivers/staging/octeon-usb/octeon-hcd.c
··· 465 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 + */ 477 + struct 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 + */ 492 + static 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 + */ 523 + static 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 + */ 546 + static 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 + */ 567 + static 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 574 * Read a USB 32bit CSR. It performs the necessary address swizzle 469 575 * for 32bit CSRs and logs the value in a readable format if 470 576 * debugging is on. ··· 3707 3601 .get_frame_number = octeon_usb_get_frame_number, 3708 3602 .hub_status_data = octeon_usb_hub_status_data, 3709 3603 .hub_control = octeon_usb_hub_control, 3604 + .map_urb_for_dma = octeon_map_urb_for_dma, 3605 + .unmap_urb_for_dma = octeon_unmap_urb_for_dma, 3710 3606 }; 3711 3607 3712 3608 static int octeon_usb_probe(struct platform_device *pdev)