lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Date:   Thu, 18 Aug 2022 12:14:16 -0700
From:   Guenter Roeck <linux@...ck-us.net>
To:     "Isaac J. Manjarres" <isaacmanjarres@...gle.com>
Cc:     Russell King <linux@...linux.org.uk>,
        Saravana Kannan <saravanak@...gle.com>,
        "Russell King (Oracle)" <rmk+kernel@...linux.org.uk>,
        patches@...linux.org.uk, kernel-team@...roid.com,
        linux-kernel@...r.kernel.org
Subject: Re: [PATCH v1] amba: Fix use-after-free in amba_read_periphid()

On Wed, Aug 17, 2022 at 11:46:12AM -0700, Isaac J. Manjarres wrote:
> After commit f2d3b9a46e0e ("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@...gle.com>
> Cc: patches@...linux.org.uk
> Fixes: f2d3b9a46e0e ("ARM: 9220/1: amba: Remove deferred device addition")
> Reported-by: Guenter Roeck <linux@...ck-us.net>
> Signed-off-by: Isaac J. Manjarres <isaacmanjarres@...gle.com>

Tested-by: Guenter Roeck <linux@...ck-us.net>

> ---
>  drivers/amba/bus.c       | 8 +++++++-
>  include/linux/amba/bus.h | 1 +
>  2 files changed, 8 insertions(+), 1 deletion(-)
> 
> Guenter,
> 
> Thanks for testing this patch out. Can you please add your Tested-by?
> 
> Thanks,
> Isaac
> 
> diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
> index 32b0e0b930c1..110a535648d2 100644
> --- a/drivers/amba/bus.c
> +++ b/drivers/amba/bus.c
> @@ -209,6 +209,7 @@ static int amba_match(struct device *dev, struct device_driver *drv)
>  	struct amba_device *pcdev = to_amba_device(dev);
>  	struct amba_driver *pcdrv = to_amba_driver(drv);
>  
> +	mutex_lock(&pcdev->periphid_lock);
>  	if (!pcdev->periphid) {
>  		int ret = amba_read_periphid(pcdev);
>  
> @@ -218,11 +219,14 @@ static int amba_match(struct device *dev, struct device_driver *drv)
>  		 * permanent failure in reading pid and cid, simply map it to
>  		 * -EPROBE_DEFER.
>  		 */
> -		if (ret)
> +		if (ret) {
> +			mutex_unlock(&pcdev->periphid_lock);
>  			return -EPROBE_DEFER;
> +		}
>  		dev_set_uevent_suppress(dev, false);
>  		kobject_uevent(&dev->kobj, KOBJ_ADD);
>  	}
> +	mutex_unlock(&pcdev->periphid_lock);
>  
>  	/* When driver_override is set, only bind to the matching driver */
>  	if (pcdev->driver_override)
> @@ -532,6 +536,7 @@ static void amba_device_release(struct device *dev)
>  
>  	if (d->res.parent)
>  		release_resource(&d->res);
> +	mutex_destroy(&d->periphid_lock);
>  	kfree(d);
>  }
>  
> @@ -584,6 +589,7 @@ static void amba_device_initialize(struct amba_device *dev, const char *name)
>  	dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
>  	dev->dev.dma_parms = &dev->dma_parms;
>  	dev->res.name = dev_name(&dev->dev);
> +	mutex_init(&dev->periphid_lock);
>  }
>  
>  /**
> diff --git a/include/linux/amba/bus.h b/include/linux/amba/bus.h
> index e94cdf235f1d..5001e14c5c06 100644
> --- a/include/linux/amba/bus.h
> +++ b/include/linux/amba/bus.h
> @@ -67,6 +67,7 @@ struct amba_device {
>  	struct clk		*pclk;
>  	struct device_dma_parameters dma_parms;
>  	unsigned int		periphid;
> +	struct mutex		periphid_lock;
>  	unsigned int		cid;
>  	struct amba_cs_uci_id	uci;
>  	unsigned int		irq[AMBA_NR_IRQS];
> -- 
> 2.37.1.595.g718a3a8f04-goog
> 

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ