From bd299e3b421a3389cb4ec8e82b79ad3408dd3631 Mon Sep 17 00:00:00 2001 From: Sonny Rao Date: Wed, 20 Feb 2013 17:45:06 -0800 Subject: [PATCH] CHROMIUM: bluetooth/usb: hack to cover up dma after free corruption This is a horrible, gross hack to cover up the fact that we sometimes get an apparent DMA from the interrupt endpoint on the bluetooth module after shutting it down. This ends up manifesting as random kernel crashes, often from other users of kmalloc-16. Since we don't have root cause (yet?) and can't do much about it, put in this band-aid which will leak around 64 bytes of memory every time we suspend/resume a usb bluetooth device. We make no attempt to free this memory because we don't know when the DMA could come in and it's a relatively small amount so probably not worth trying to free it later. Another issue is that SLUB will mix together objects from different slabs if they are all the same size. So, in order to get a separate slab in /proc/slabinfo, we turn on some of the slab debugging options. The main reason for doing this is to let us track how much memory got leaked through slabinfo. This will trigger a BUG_ON() in kmem_cache_create() if the kernel is compiled with CONFIG_SLAB && !CONFIG_DEBUG_SLAB. One day, when we have a real fix, we should remove this abomination. Signed-off-by: Sonny Rao BUG=chrome-os-partner:12507 BUG=chrome-os-partner:17614 TEST=repeated suspend resume, should not see a kernel crash Change-Id: Iebdfe033d178c664a91fce1164b255aa1c322ad0 Reviewed-on: https://gerrit.chromium.org/gerrit/43682 Commit-Queue: Sonny Rao Reviewed-by: Sonny Rao Tested-by: Sonny Rao Reviewed-by: Vincent Palatin Reviewed-on: https://gerrit.chromium.org/gerrit/43918 --- drivers/bluetooth/btusb.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index b5cbe27c6e230..3df1d5c624e07 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -56,6 +56,13 @@ static struct usb_driver btusb_driver; #define BTUSB_WRONG_SCO_MTU 0x40 #define BTUSB_ATH3012 0x80 +/* Hack to deal with USB controllers/devices which */ +/* DMA after we shut the device down and kill the URB */ +static struct kmem_cache *btusb_intr_buf_cache; + +/* Max interrupt packet size for a full-speed device is 64 bytes */ +#define BTUSB_INTR_BUF_SIZE (64) + static struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ { USB_DEVICE_INFO(0xe0, 0x01, 0x01) }, @@ -316,7 +323,8 @@ static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags) size = le16_to_cpu(data->intr_ep->wMaxPacketSize); - buf = kmalloc(size, mem_flags); + BUG_ON(size > BTUSB_INTR_BUF_SIZE); + buf = kmem_cache_alloc(btusb_intr_buf_cache, mem_flags); if (!buf) { usb_free_urb(urb); return -ENOMEM; @@ -328,7 +336,8 @@ static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags) btusb_intr_complete, hdev, data->intr_ep->bInterval); - urb->transfer_flags |= URB_FREE_BUFFER; + /* HACK: intentionally leak this buffer due to DMA after free */ + /* urb->transfer_flags |= URB_FREE_BUFFER; */ usb_anchor_urb(urb, &data->intr_anchor); @@ -919,6 +928,16 @@ static int btusb_probe(struct usb_interface *intf, BT_DBG("intf %p id %p", intf, id); + if (!btusb_intr_buf_cache) { + btusb_intr_buf_cache = kmem_cache_create("btusb_intr_buf", + BTUSB_INTR_BUF_SIZE, + BTUSB_INTR_BUF_SIZE, + SLAB_RED_ZONE | + SLAB_POISON, + NULL); + BUG_ON(!btusb_intr_buf_cache); + } + /* interface numbers are hardcoded in the spec */ if (intf->cur_altsetting->desc.bInterfaceNumber != 0) return -ENODEV; -- 2.39.5