• Viresh Kumar's avatar
    usb: hub: Fix unbalanced reference count/memory leak/deadlocks · ab192810
    Viresh Kumar authored
    commit 6bb47e8a upstream.
    
    Memory leak and unbalanced reference count:
    
    If the hub gets disconnected while the core is still activating it, this
    can result in leaking memory of few USB structures.
    
    This will happen if we have done a kref_get() from hub_activate() and
    scheduled a delayed work item for HUB_INIT2/3. Now if hub_disconnect()
    gets called before the delayed work expires, then we will cancel the
    work from hub_quiesce(), but wouldn't do a kref_put(). And so the
    unbalance.
    
    kmemleak reports this as (with the commit e50293ef backported to
    3.10 kernel with other changes, though the same is true for mainline as
    well):
    
    unreferenced object 0xffffffc08af5b800 (size 1024):
      comm "khubd", pid 73, jiffies 4295051211 (age 6482.350s)
      hex dump (first 32 bytes):
        30 68 f3 8c c0 ff ff ff 00 a0 b2 2e c0 ff ff ff  0h..............
        01 00 00 00 00 00 00 00 00 94 7d 40 c0 ff ff ff  ..........}@....
      backtrace:
        [<ffffffc0003079ec>] create_object+0x148/0x2a0
        [<ffffffc000cc150c>] kmemleak_alloc+0x80/0xbc
        [<ffffffc000303a7c>] kmem_cache_alloc_trace+0x120/0x1ac
        [<ffffffc0006fa610>] hub_probe+0x120/0xb84
        [<ffffffc000702b20>] usb_probe_interface+0x1ec/0x298
        [<ffffffc0005d50cc>] driver_probe_device+0x160/0x374
        [<ffffffc0005d5308>] __device_attach+0x28/0x4c
        [<ffffffc0005d3164>] bus_for_each_drv+0x78/0xac
        [<ffffffc0005d4ee0>] device_attach+0x6c/0x9c
        [<ffffffc0005d42b8>] bus_probe_device+0x28/0xa0
        [<ffffffc0005d23a4>] device_add+0x324/0x604
        [<ffffffc000700fcc>] usb_set_configuration+0x660/0x6cc
        [<ffffffc00070a350>] generic_probe+0x44/0x84
        [<ffffffc000702914>] usb_probe_device+0x54/0x74
        [<ffffffc0005d50cc>] driver_probe_device+0x160/0x374
        [<ffffffc0005d5308>] __device_attach+0x28/0x4c
    
    Deadlocks:
    
    If the hub gets disconnected early enough (i.e. before INIT2/INIT3 are
    finished and the init_work is still queued), the core may call
    hub_quiesce() after acquiring interface device locks and it will wait
    for the work to be cancelled synchronously. But if the work handler is
    already running in parallel, it may try to acquire the same interface
    device lock and this may result in deadlock.
    
    Fix both the issues by removing the call to cancel_delayed_work_sync().
    
    Fixes: e50293ef ("USB: fix invalid memory access in hub_activate()")
    Reported-by: default avatarManu Gautam <mgautam@codeaurora.org>
    Signed-off-by: default avatarViresh Kumar <viresh.kumar@linaro.org>
    Acked-by: default avatarAlan Stern <stern@rowland.harvard.edu>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    ab192810
hub.c 166 KB