Skip to content

Commit 64dafbc

Browse files
lgeaxboe
authored andcommitted
drbd: fix access after free
We have struct drbd_requests { ... struct bio *private_bio; ... } to hold a bio clone for local submission. On local IO completion, we put that bio, and in case we want to use the result later, we overload that member to hold the ERR_PTR() of the completion result, Which, before v4.3, used to be the passed in "int error", so we could first bio_put(), then assign. v4.3-rc1~100^2~21 4246a0b block: add a bi_error field to struct bio changed that: bio_put(req->private_bio); - req->private_bio = ERR_PTR(error); + req->private_bio = ERR_PTR(bio->bi_error); Which introduces an access after free, because it was non obvious that req->private_bio == bio. Impact of that was mostly unnoticable, because we only use that value in a multiple-failure case, and even then map any "unexpected" error code to EIO, so worst case we could potentially mask a more specific error with EIO in a multiple failure case. Unless the pointed to memory region was unmapped, as is the case with CONFIG_DEBUG_PAGEALLOC, in which case this results in BUG: unable to handle kernel paging request v4.13-rc1~70^2~75 4e4cbee block: switch bios to blk_status_t changes it further to bio_put(req->private_bio); req->private_bio = ERR_PTR(blk_status_to_errno(bio->bi_status)); And blk_status_to_errno() now contains a WARN_ON_ONCE() for unexpected values, which catches this "sometimes", if the memory has been reused quickly enough for other things. Should also go into stable since 4.3, with the trivial change around 4.13. Cc: [email protected] Fixes: 4246a0b block: add a bi_error field to struct bio Reported-by: Sarah Newman <[email protected]> Signed-off-by: Lars Ellenberg <[email protected]> Signed-off-by: Jens Axboe <[email protected]>
1 parent 9544bc5 commit 64dafbc

File tree

1 file changed

+1
-1
lines changed

1 file changed

+1
-1
lines changed

drivers/block/drbd/drbd_worker.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,8 +282,8 @@ void drbd_request_endio(struct bio *bio)
282282
what = COMPLETED_OK;
283283
}
284284

285-
bio_put(req->private_bio);
286285
req->private_bio = ERR_PTR(blk_status_to_errno(bio->bi_status));
286+
bio_put(bio);
287287

288288
/* not req_mod(), we need irqsave here! */
289289
spin_lock_irqsave(&device->resource->req_lock, flags);

0 commit comments

Comments
 (0)