Re: [PATCH v2] ata: pata_parport: Fix use-after-free in new_device_store

Pei Xiao <[email protected]>
Newsgroups org.kernel.vger.linux-ide,org.kernel.vger.linux-kernel
Message-ID <[email protected]>

在 2026/7/30 11:16, Pei Xiao 写道:
> The function new_device_store() calls driver_find() without any
> protection against concurrent driver unregistration. This can lead
> to a use-after-free (UAF) when a driver is unloaded (via rmmod)
> in parallel with a new device addition via sysfs.
> 
> The race window exists because driver_find() returns a pointer to
> the driver's private data, but does not increase its reference
> count. The caller is responsible for ensuring the driver remains
> valid, but new_device_store() did not hold any lock or reference
> during the lookup and subsequent use.
> 
> Concurrently, pata_parport_unregister_driver() releases the
> pi_mutex before calling driver_unregister(), allowing new_device_store
> to proceed with a stale pointer after the driver has been freed.
> 
> Fix this by expanding the critical section protected by pi_mutex
> in both functions:
> 
> - In new_device_store(): acquire pi_mutex before calling driver_find(),
>   and keep it held until all uses of the found driver pointer are
>   completed.
> - In pata_parport_unregister_driver(): hold pi_mutex throughout the
>   entire unregistration process, including the driver_unregister()
>   call, so that no concurrent lookup can see a partially removed
>   driver.
> 
> Thread A (new_device_store)       | Thread B (pata_parport_unregister_driver)
>   driver_find("ate")              |
>                                   |   mutex_lock(&pi_mutex)
>                                   |   idr_remove(&protocols, id)
>                                   |   mutex_unlock(&pi_mutex)
>                                   |   driver_unregister(&pr->driver)
>                                   |   (frees driver_private)
>   /* continues using stale driv */|
>   -> UAF!                         |
> 
> Logs:
> BUG: KASAN: slab-use-after-free in driver_find+0xd0/0xd4
> Read of size 8 at addr ffffff9f970dc690 by task sh/4737
> Call trace:
>  show_stack+0x14/0x1c (C)
>  dump_stack_lvl+0x70/0x84
>  print_report+0xf4/0x5a4
>  kasan_report+0xa0/0xe4
>  __asan_report_load8_noabort+0x18/0x20
>  driver_find+0xd0/0xd4
>  new_device_store+0x140/0x30c [pata_parport]
>  bus_attr_store+0x5c/0x94
>  sysfs_kf_write+0x1c4/0x25c
>  ...
> 
> Allocated by task 4734:
>  kasan_save_stack+0x28/0x4c
>  kasan_save_track+0x1c/0x34
>  kasan_save_alloc_info+0x3c/0x4c
>  __kasan_kmalloc+0x98/0xac
>  __kmalloc_cache_noprof+0x158/0x3cc
>  bus_add_driver+0x70/0x4d8
>  driver_register+0xf0/0x3b0
>  pata_parport_register_driver+0xb8/0x1c4 [pata_parport]
>  0xffffffc07f5ce014
>  do_one_initcall+0xb8/0x36c
>  do_init_module+0x230/0x6d4
>  ...
> 
> Freed by task 4737:
>  kasan_save_stack+0x28/0x4c
>  kasan_save_track+0x1c/0x34
>  kasan_save_free_info+0x48/0x8c
>  __kasan_slab_free+0x5c/0x84
>  kfree+0x174/0x3e0
>  driver_release+0x1c/0x7c
>  kobject_put+0x178/0x47c
>  driver_find+0x78/0xd4
>  new_device_store+0x140/0x30c [pata_parport]
>  bus_attr_store+0x5c/0x94
>  sysfs_kf_write+0x1c4/0x25c
>  ...
> 
> Fixes: 246a1c4c6b7f ("ata: pata_parport: add driver (PARIDE replacement)")
Hi Cassel,
 I have already the fix tag.

thanks!
Pei.
> Reported-by: Shuangpeng Bai <[email protected]>
> Closes: https://lore.kernel.org/lkml/[email protected]/
> Signed-off-by: Pei Xiao <[email protected]>
> ---
> changes in v2:
> 1.Modify to use the correct fix ID.
> 2.Use mutex_lock instead of guard.
> ---
>  drivers/ata/pata_parport/pata_parport.c | 7 ++++---
>  1 file changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/ata/pata_parport/pata_parport.c b/drivers/ata/pata_parport/pata_parport.c
> index 40baeac594a9..cf81a6128f55 100644
> --- a/drivers/ata/pata_parport/pata_parport.c
> +++ b/drivers/ata/pata_parport/pata_parport.c
> @@ -618,8 +618,9 @@ void pata_parport_unregister_driver(struct pi_protocol *pr)
>  			break;
>  	}
>  	idr_remove(&protocols, id);
> -	mutex_unlock(&pi_mutex);
>  	driver_unregister(&pr->driver);
> +	mutex_unlock(&pi_mutex);
> +
>  }
>  EXPORT_SYMBOL_GPL(pata_parport_unregister_driver);
>  
> @@ -646,18 +647,18 @@ static ssize_t new_device_store(const struct bus_type *bus, const char *buf, siz
>  		port_wanted = -1;
>  	}
>  
> +	mutex_lock(&pi_mutex);
>  	drv = driver_find(protocol, &pata_parport_bus_type);
>  	if (!drv) {
>  		if (strcmp(protocol, "auto")) {
>  			pr_err("protocol %s not found\n", protocol);
> +			mutex_unlock(&pi_mutex);
>  			return -EINVAL;
>  		}
>  		pr_wanted = NULL;
>  	} else {
>  		pr_wanted = container_of(drv, struct pi_protocol, driver);
>  	}
> -
> -	mutex_lock(&pi_mutex);
>  	/* walk all parports */
>  	idr_for_each_entry(&parport_list, parport, port_num) {
>  		if (port_num == port_wanted || port_wanted == -1) {
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.