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