Jiri Slaby ef7db2
From: Ilya Dryomov <idryomov@gmail.com>
Jiri Slaby ef7db2
Date: Fri, 24 Feb 2023 18:48:54 +0100
Jiri Slaby ef7db2
Subject: [PATCH] rbd: avoid use-after-free in do_rbd_add() when
Jiri Slaby ef7db2
 rbd_dev_create() fails
Jiri Slaby ef7db2
References: bsc#1012628
Jiri Slaby ef7db2
Patch-mainline: 6.2.3
Jiri Slaby ef7db2
Git-commit: f7c4d9b133c7a04ca619355574e96b6abf209fba
Jiri Slaby ef7db2
Jiri Slaby ef7db2
commit f7c4d9b133c7a04ca619355574e96b6abf209fba upstream.
Jiri Slaby ef7db2
Jiri Slaby ef7db2
If getting an ID or setting up a work queue in rbd_dev_create() fails,
Jiri Slaby ef7db2
use-after-free on rbd_dev->rbd_client, rbd_dev->spec and rbd_dev->opts
Jiri Slaby ef7db2
is triggered in do_rbd_add().  The root cause is that the ownership of
Jiri Slaby ef7db2
these structures is transfered to rbd_dev prematurely and they all end
Jiri Slaby ef7db2
up getting freed when rbd_dev_create() calls rbd_dev_free() prior to
Jiri Slaby ef7db2
returning to do_rbd_add().
Jiri Slaby ef7db2
Jiri Slaby ef7db2
Found by Linux Verification Center (linuxtesting.org) with SVACE, an
Jiri Slaby ef7db2
incomplete patch submitted by Natalia Petrova <n.petrova@fintech.ru>.
Jiri Slaby ef7db2
Jiri Slaby ef7db2
Cc: stable@vger.kernel.org
Jiri Slaby ef7db2
Fixes: 1643dfa4c2c8 ("rbd: introduce a per-device ordered workqueue")
Jiri Slaby ef7db2
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Jiri Slaby ef7db2
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Jiri Slaby ef7db2
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Jiri Slaby ef7db2
---
Jiri Slaby ef7db2
 drivers/block/rbd.c | 20 +++++++++-----------
Jiri Slaby ef7db2
 1 file changed, 9 insertions(+), 11 deletions(-)
Jiri Slaby ef7db2
Jiri Slaby ef7db2
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
Jiri Slaby ef7db2
index 04453f4a..60aed196 100644
Jiri Slaby ef7db2
--- a/drivers/block/rbd.c
Jiri Slaby ef7db2
+++ b/drivers/block/rbd.c
Jiri Slaby ef7db2
@@ -5292,8 +5292,7 @@ static void rbd_dev_release(struct device *dev)
Jiri Slaby ef7db2
 		module_put(THIS_MODULE);
Jiri Slaby ef7db2
 }
Jiri Slaby ef7db2
 
Jiri Slaby ef7db2
-static struct rbd_device *__rbd_dev_create(struct rbd_client *rbdc,
Jiri Slaby ef7db2
-					   struct rbd_spec *spec)
Jiri Slaby ef7db2
+static struct rbd_device *__rbd_dev_create(struct rbd_spec *spec)
Jiri Slaby ef7db2
 {
Jiri Slaby ef7db2
 	struct rbd_device *rbd_dev;
Jiri Slaby ef7db2
 
Jiri Slaby ef7db2
@@ -5338,9 +5337,6 @@ static struct rbd_device *__rbd_dev_create(struct rbd_client *rbdc,
Jiri Slaby ef7db2
 	rbd_dev->dev.parent = &rbd_root_dev;
Jiri Slaby ef7db2
 	device_initialize(&rbd_dev->dev);
Jiri Slaby ef7db2
 
Jiri Slaby ef7db2
-	rbd_dev->rbd_client = rbdc;
Jiri Slaby ef7db2
-	rbd_dev->spec = spec;
Jiri Slaby ef7db2
-
Jiri Slaby ef7db2
 	return rbd_dev;
Jiri Slaby ef7db2
 }
Jiri Slaby ef7db2
 
Jiri Slaby ef7db2
@@ -5353,12 +5349,10 @@ static struct rbd_device *rbd_dev_create(struct rbd_client *rbdc,
Jiri Slaby ef7db2
 {
Jiri Slaby ef7db2
 	struct rbd_device *rbd_dev;
Jiri Slaby ef7db2
 
Jiri Slaby ef7db2
-	rbd_dev = __rbd_dev_create(rbdc, spec);
Jiri Slaby ef7db2
+	rbd_dev = __rbd_dev_create(spec);
Jiri Slaby ef7db2
 	if (!rbd_dev)
Jiri Slaby ef7db2
 		return NULL;
Jiri Slaby ef7db2
 
Jiri Slaby ef7db2
-	rbd_dev->opts = opts;
Jiri Slaby ef7db2
-
Jiri Slaby ef7db2
 	/* get an id and fill in device name */
Jiri Slaby ef7db2
 	rbd_dev->dev_id = ida_simple_get(&rbd_dev_id_ida, 0,
Jiri Slaby ef7db2
 					 minor_to_rbd_dev_id(1 << MINORBITS),
Jiri Slaby ef7db2
@@ -5375,6 +5369,10 @@ static struct rbd_device *rbd_dev_create(struct rbd_client *rbdc,
Jiri Slaby ef7db2
 	/* we have a ref from do_rbd_add() */
Jiri Slaby ef7db2
 	__module_get(THIS_MODULE);
Jiri Slaby ef7db2
 
Jiri Slaby ef7db2
+	rbd_dev->rbd_client = rbdc;
Jiri Slaby ef7db2
+	rbd_dev->spec = spec;
Jiri Slaby ef7db2
+	rbd_dev->opts = opts;
Jiri Slaby ef7db2
+
Jiri Slaby ef7db2
 	dout("%s rbd_dev %p dev_id %d\n", __func__, rbd_dev, rbd_dev->dev_id);
Jiri Slaby ef7db2
 	return rbd_dev;
Jiri Slaby ef7db2
 
Jiri Slaby ef7db2
@@ -6736,7 +6734,7 @@ static int rbd_dev_probe_parent(struct rbd_device *rbd_dev, int depth)
Jiri Slaby ef7db2
 		goto out_err;
Jiri Slaby ef7db2
 	}
Jiri Slaby ef7db2
 
Jiri Slaby ef7db2
-	parent = __rbd_dev_create(rbd_dev->rbd_client, rbd_dev->parent_spec);
Jiri Slaby ef7db2
+	parent = __rbd_dev_create(rbd_dev->parent_spec);
Jiri Slaby ef7db2
 	if (!parent) {
Jiri Slaby ef7db2
 		ret = -ENOMEM;
Jiri Slaby ef7db2
 		goto out_err;
Jiri Slaby ef7db2
@@ -6746,8 +6744,8 @@ static int rbd_dev_probe_parent(struct rbd_device *rbd_dev, int depth)
Jiri Slaby ef7db2
 	 * Images related by parent/child relationships always share
Jiri Slaby ef7db2
 	 * rbd_client and spec/parent_spec, so bump their refcounts.
Jiri Slaby ef7db2
 	 */
Jiri Slaby ef7db2
-	__rbd_get_client(rbd_dev->rbd_client);
Jiri Slaby ef7db2
-	rbd_spec_get(rbd_dev->parent_spec);
Jiri Slaby ef7db2
+	parent->rbd_client = __rbd_get_client(rbd_dev->rbd_client);
Jiri Slaby ef7db2
+	parent->spec = rbd_spec_get(rbd_dev->parent_spec);
Jiri Slaby ef7db2
 
Jiri Slaby ef7db2
 	__set_bit(RBD_DEV_FLAG_READONLY, &parent->flags);
Jiri Slaby ef7db2
 
Jiri Slaby ef7db2
-- 
Jiri Slaby ef7db2
2.35.3
Jiri Slaby ef7db2