Coly Li 7a60d3
From 3d32aaa7e66d5c1479a3c31d6c2c5d45dd0d3b89 Mon Sep 17 00:00:00 2001
Coly Li 7a60d3
From: Mike Snitzer <snitzer@kernel.org>
Coly Li 7a60d3
Date: Mon, 17 Apr 2023 11:59:56 -0400
Coly Li 7a60d3
Subject: [PATCH] dm ioctl: fix nested locking in table_clear() to remove
Coly Li 7a60d3
 deadlock concern
Coly Li 7a60d3
Git-commit: 3d32aaa7e66d5c1479a3c31d6c2c5d45dd0d3b89
Coly Li 7a60d3
Patch-mainline: v6.4-rc1
Coly Li 7a60d3
References: bsc#1210806
Coly Li 7a60d3
Coly Li 7a60d3
syzkaller found the following problematic rwsem locking (with write
Coly Li 7a60d3
lock already held):
Coly Li 7a60d3
Coly Li 7a60d3
 down_read+0x9d/0x450 kernel/locking/rwsem.c:1509
Coly Li 7a60d3
 dm_get_inactive_table+0x2b/0xc0 drivers/md/dm-ioctl.c:773
Coly Li 7a60d3
 __dev_status+0x4fd/0x7c0 drivers/md/dm-ioctl.c:844
Coly Li 7a60d3
 table_clear+0x197/0x280 drivers/md/dm-ioctl.c:1537
Coly Li 7a60d3
Coly Li 7a60d3
In table_clear, it first acquires a write lock
Coly Li 7a60d3
https://elixir.bootlin.com/linux/v6.2/source/drivers/md/dm-ioctl.c#L1520
Coly Li 7a60d3
down_write(&_hash_lock);
Coly Li 7a60d3
Coly Li 7a60d3
Then before the lock is released at L1539, there is a path shown above:
Coly Li 7a60d3
table_clear -> __dev_status -> dm_get_inactive_table ->  down_read
Coly Li 7a60d3
https://elixir.bootlin.com/linux/v6.2/source/drivers/md/dm-ioctl.c#L773
Coly Li 7a60d3
down_read(&_hash_lock);
Coly Li 7a60d3
Coly Li 7a60d3
It tries to acquire the same read lock again, resulting in the deadlock
Coly Li 7a60d3
problem.
Coly Li 7a60d3
Coly Li 7a60d3
Fix this by moving table_clear()'s __dev_status() call to after its
Coly Li 7a60d3
up_write(&_hash_lock);
Coly Li 7a60d3
Coly Li 7a60d3
Cc: stable@vger.kernel.org
Coly Li 7a60d3
Reported-by: Zheng Zhang <zheng.zhang@email.ucr.edu>
Coly Li 7a60d3
Signed-off-by: Mike Snitzer <snitzer@kernel.org>
Coly Li 7a60d3
Signed-off-by: Coly Li <colyli@suse.de>
Coly Li 7a60d3
---
Coly Li 7a60d3
 drivers/md/dm-ioctl.c | 7 ++++---
Coly Li 7a60d3
 1 file changed, 4 insertions(+), 3 deletions(-)
Coly Li 7a60d3
Coly Li 7a60d3
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
Coly Li 7a60d3
index 50a1259294d1..7d5c9c582ed2 100644
Coly Li 7a60d3
--- a/drivers/md/dm-ioctl.c
Coly Li 7a60d3
+++ b/drivers/md/dm-ioctl.c
Coly Li 7a60d3
@@ -1556,11 +1556,12 @@ static int table_clear(struct file *filp, struct dm_ioctl *param, size_t param_s
Coly Li 7a60d3
 		has_new_map = true;
Coly Li 7a60d3
 	}
Coly Li 7a60d3
 
Coly Li 7a60d3
-	param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
Coly Li 7a60d3
-
Coly Li 7a60d3
-	__dev_status(hc->md, param);
Coly Li 7a60d3
 	md = hc->md;
Coly Li 7a60d3
 	up_write(&_hash_lock);
Coly Li 7a60d3
+
Coly Li 7a60d3
+	param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
Coly Li 7a60d3
+	__dev_status(md, param);
Coly Li 7a60d3
+
Coly Li 7a60d3
 	if (old_map) {
Coly Li 7a60d3
 		dm_sync_table(md);
Coly Li 7a60d3
 		dm_table_destroy(old_map);
Coly Li 7a60d3
-- 
Coly Li 7a60d3
2.35.3
Coly Li 7a60d3