[Drbd-dev] [PATCH] drbd: avoid use-after-free in drbd_request_endio

Sarah Newman srn at prgmr.com
Mon Apr 30 03:19:18 CEST 2018


It appears that bio_put(req->private_bio) may put the bio being
passed in, after which point accessing bio will no longer be
valid. Make a local copy of bio->bi_error before then.

Without this patch, with CONFIG_DEBUG_PAGEALLOC the debug message

"role( Secondary -> Primary )"

is followed by

"BUG: unable to handle kernel paging request"

This applies to versions before 4e4cbee93d561, first released
in v4.13. v4.13+ appears to have a similar bug.

Signed-off-by: Sarah Newman <srn at prgmr.com>
---
 drivers/block/drbd/drbd_worker.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c
index c6755c9..e9992b8 100644
--- a/drivers/block/drbd/drbd_worker.c
+++ b/drivers/block/drbd/drbd_worker.c
@@ -209,6 +209,7 @@ void drbd_request_endio(struct bio *bio)
 	struct drbd_device *device = req->device;
 	struct bio_and_error m;
 	enum drbd_req_event what;
+	int bi_error = bio->bi_error;
 
 	/* If this request was aborted locally before,
 	 * but now was completed "successfully",
@@ -242,15 +243,15 @@ void drbd_request_endio(struct bio *bio)
 		if (__ratelimit(&drbd_ratelimit_state))
 			drbd_emerg(device, "delayed completion of aborted local request; disk-timeout may be too aggressive\n");
 
-		if (!bio->bi_error)
+		if (!bi_error)
 			drbd_panic_after_delayed_completion_of_aborted_request(device);
 	}
 
 	/* to avoid recursion in __req_mod */
-	if (unlikely(bio->bi_error)) {
+	if (unlikely(bi_error)) {
 		switch (bio_op(bio)) {
 		case REQ_OP_DISCARD:
-			if (bio->bi_error == -EOPNOTSUPP)
+			if (bi_error == -EOPNOTSUPP)
 				what = DISCARD_COMPLETED_NOTSUPP;
 			else
 				what = DISCARD_COMPLETED_WITH_ERROR;
@@ -270,7 +271,7 @@ void drbd_request_endio(struct bio *bio)
 	}
 
 	bio_put(req->private_bio);
-	req->private_bio = ERR_PTR(bio->bi_error);
+	req->private_bio = ERR_PTR(bi_error);
 
 	/* not req_mod(), we need irqsave here! */
 	spin_lock_irqsave(&device->resource->req_lock, flags);
-- 
1.9.1



More information about the drbd-dev mailing list