• Isaac Manjarres's avatar
    ARM: 9229/1: amba: Fix use-after-free in amba_read_periphid() · 25af7406
    Isaac Manjarres authored
    After commit f2d3b9a4 ("ARM: 9220/1: amba: Remove deferred device
    addition"), it became possible for amba_read_periphid() to be invoked
    concurrently from two threads for a particular AMBA device.
    
    Consider the case where a thread (T0) is registering an AMBA driver, and
    searching for all of the devices it can match with on the AMBA bus.
    Suppose that another thread (T1) is executing the deferred probe work,
    and is searching through all of the AMBA drivers on the bus for a driver
    that matches a particular AMBA device. Assume that both threads begin
    operating on the same AMBA device and the device's peripheral ID is
    still unknown.
    
    In this scenario, the amba_match() function will be invoked for the
    same AMBA device by both threads, which means amba_read_periphid()
    can also be invoked by both threads, and both threads will be able
    to manipulate the AMBA device's pclk pointer without any synchronization.
    It's possible that one thread will initialize the pclk pointer, then the
    other thread will re-initialize it, overwriting the previous value, and
    both will race to free the same pclk, resulting in a use-after-free for
    whichever thread frees the pclk last.
    
    Add a lock per AMBA device to synchronize the handling with detecting the
    peripheral ID to avoid the use-after-free scenario.
    
    The following KFENCE bug report helped detect this problem:
    ==================================================================
    BUG: KFENCE: use-after-free read in clk_disable+0x14/0x34
    
    Use-after-free read at 0x(ptrval) (in kfence-#19):
     clk_disable+0x14/0x34
     amba_read_periphid+0xdc/0x134
     amba_match+0x3c/0x84
     __driver_attach+0x20/0x158
     bus_for_each_dev+0x74/0xc0
     bus_add_driver+0x154/0x1e8
     driver_register+0x88/0x11c
     do_one_initcall+0x8c/0x2fc
     kernel_init_freeable+0x190/0x220
     kernel_init+0x10/0x108
     ret_from_fork+0x14/0x3c
     0x0
    
    kfence-#19: 0x(ptrval)-0x(ptrval), size=36, cache=kmalloc-64
    
    allocated by task 8 on cpu 0 at 11.629931s:
     clk_hw_create_clk+0x38/0x134
     amba_get_enable_pclk+0x10/0x68
     amba_read_periphid+0x28/0x134
     amba_match+0x3c/0x84
     __device_attach_driver+0x2c/0xc4
     bus_for_each_drv+0x80/0xd0
     __device_attach+0xb0/0x1f0
     bus_probe_device+0x88/0x90
     deferred_probe_work_func+0x8c/0xc0
     process_one_work+0x23c/0x690
     worker_thread+0x34/0x488
     kthread+0xd4/0xfc
     ret_from_fork+0x14/0x3c
     0x0
    
    freed by task 8 on cpu 0 at 11.630095s:
     amba_read_periphid+0xec/0x134
     amba_match+0x3c/0x84
     __device_attach_driver+0x2c/0xc4
     bus_for_each_drv+0x80/0xd0
     __device_attach+0xb0/0x1f0
     bus_probe_device+0x88/0x90
     deferred_probe_work_func+0x8c/0xc0
     process_one_work+0x23c/0x690
     worker_thread+0x34/0x488
     kthread+0xd4/0xfc
     ret_from_fork+0x14/0x3c
     0x0
    
    Cc: Saravana Kannan <saravanak@google.com>
    Cc: patches@armlinux.org.uk
    Fixes: f2d3b9a4 ("ARM: 9220/1: amba: Remove deferred device addition")
    Reported-by: default avatarGuenter Roeck <linux@roeck-us.net>
    Tested-by: default avatarGuenter Roeck <linux@roeck-us.net>
    Signed-off-by: default avatarIsaac J. Manjarres <isaacmanjarres@google.com>
    Signed-off-by: default avatarRussell King (Oracle) <rmk+kernel@armlinux.org.uk>
    25af7406
bus.c 16.7 KB