| From 5380c7f6335cc6d77eb77d065105e81155c4d9d3 Mon Sep 17 00:00:00 2001 |
| From: Mikulas Patocka <mpatocka@redhat.com> |
| Date: Mon, 27 Jul 2026 22:27:07 +0200 |
| Subject: dm: fix race when loading and unloading a table |
| |
| From: Mikulas Patocka <mpatocka@redhat.com> |
| |
| commit 5380c7f6335cc6d77eb77d065105e81155c4d9d3 upstream. |
| |
| If the userspace calls two concurrent table load ioctls and one of them |
| succeeds and the other fails, there is a race condition because |
| dm_setup_md_queue walks &md->table_devices without any lock. If the walk |
| races with dm_table_destroy -> free_devices -> dm_put_table_device, there |
| is access to invalid memory. |
| |
| Fix this race by extending the lock over the list walk. |
| |
| Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> |
| Cc: stable@vger.kernel.org |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/md/dm.c | 12 ++++++++---- |
| 1 file changed, 8 insertions(+), 4 deletions(-) |
| |
| --- a/drivers/md/dm.c |
| +++ b/drivers/md/dm.c |
| @@ -2369,9 +2369,10 @@ int dm_setup_md_queue(struct mapped_devi |
| */ |
| mutex_lock(&md->table_devices_lock); |
| r = add_disk(md->disk); |
| - mutex_unlock(&md->table_devices_lock); |
| - if (r) |
| + if (r) { |
| + mutex_unlock(&md->table_devices_lock); |
| return r; |
| + } |
| |
| /* |
| * Register the holder relationship for devices added before the disk |
| @@ -2382,18 +2383,21 @@ int dm_setup_md_queue(struct mapped_devi |
| if (r) |
| goto out_undo_holders; |
| } |
| + mutex_unlock(&md->table_devices_lock); |
| |
| r = dm_sysfs_init(md); |
| if (r) |
| - goto out_undo_holders; |
| + goto lock_out_undo_holders; |
| |
| md->type = type; |
| + |
| return 0; |
| |
| +lock_out_undo_holders: |
| + mutex_lock(&md->table_devices_lock); |
| out_undo_holders: |
| list_for_each_entry_continue_reverse(td, &md->table_devices, list) |
| bd_unlink_disk_holder(td->dm_dev.bdev, md->disk); |
| - mutex_lock(&md->table_devices_lock); |
| del_gendisk(md->disk); |
| mutex_unlock(&md->table_devices_lock); |
| return r; |