linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] drbd: fix access after free
@ 2018-06-25  9:39 Lars Ellenberg
  2018-07-02 11:27 ` Lars Ellenberg
  0 siblings, 1 reply; 3+ messages in thread
From: Lars Ellenberg @ 2018-06-25  9:39 UTC (permalink / raw)
  To: Jens Axboe
  Cc: drbd-dev, linux-block, linux-kernel, Philipp Reisner, Lars Ellenberg

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 4246a0b63bd8 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 4e4cbee93d56 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: stable@vger.kernel.org
Fixes: 4246a0b63bd8 block: add a bi_error field to struct bio
Reported-by: Sarah Newman <srn@prgmr.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
---
 drivers/block/drbd/drbd_worker.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c
index 1476cb3439f4..5e793dd7adfb 100644
--- a/drivers/block/drbd/drbd_worker.c
+++ b/drivers/block/drbd/drbd_worker.c
@@ -282,8 +282,8 @@ void drbd_request_endio(struct bio *bio)
 		what = COMPLETED_OK;
 	}
 
-	bio_put(req->private_bio);
 	req->private_bio = ERR_PTR(blk_status_to_errno(bio->bi_status));
+	bio_put(bio);
 
 	/* not req_mod(), we need irqsave here! */
 	spin_lock_irqsave(&device->resource->req_lock, flags);
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH] drbd: fix access after free
  2018-06-25  9:39 [PATCH] drbd: fix access after free Lars Ellenberg
@ 2018-07-02 11:27 ` Lars Ellenberg
  2018-07-02 14:22   ` Jens Axboe
  0 siblings, 1 reply; 3+ messages in thread
From: Lars Ellenberg @ 2018-07-02 11:27 UTC (permalink / raw)
  To: Jens Axboe; +Cc: drbd-dev, linux-block, linux-kernel, Philipp Reisner

Jens, I had hoped you'd apply this "oneliner" into 4.18 already?
Did you miss it?

Cheers,

	Lars


On Mon, Jun 25, 2018 at 11:39:52AM +0200, Lars Ellenberg wrote:
>   	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.

>   	bio_put(req->private_bio);
>   	req->private_bio = ERR_PTR(blk_status_to_errno(bio->bi_status));

> Should also go into stable since 4.3, with the trivial change around 4.13.
> 
> Cc: stable@vger.kernel.org
> Fixes: 4246a0b63bd8 block: add a bi_error field to struct bio
> Reported-by: Sarah Newman <srn@prgmr.com>
> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
> ---
>  drivers/block/drbd/drbd_worker.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c
> index 1476cb3439f4..5e793dd7adfb 100644
> --- a/drivers/block/drbd/drbd_worker.c
> +++ b/drivers/block/drbd/drbd_worker.c
> @@ -282,8 +282,8 @@ void drbd_request_endio(struct bio *bio)
>  		what = COMPLETED_OK;
>  	}
>  
> -	bio_put(req->private_bio);
>  	req->private_bio = ERR_PTR(blk_status_to_errno(bio->bi_status));
> +	bio_put(bio);
>  
>  	/* not req_mod(), we need irqsave here! */
>  	spin_lock_irqsave(&device->resource->req_lock, flags);
> -- 
> 2.17.1

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] drbd: fix access after free
  2018-07-02 11:27 ` Lars Ellenberg
@ 2018-07-02 14:22   ` Jens Axboe
  0 siblings, 0 replies; 3+ messages in thread
From: Jens Axboe @ 2018-07-02 14:22 UTC (permalink / raw)
  To: drbd-dev, linux-block, linux-kernel, Philipp Reisner

On 7/2/18 5:27 AM, Lars Ellenberg wrote:
> Jens, I had hoped you'd apply this "oneliner" into 4.18 already?
> Did you miss it?

I did miss it, applied it now, thanks.

-- 
Jens Axboe


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2018-07-02 14:23 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-06-25  9:39 [PATCH] drbd: fix access after free Lars Ellenberg
2018-07-02 11:27 ` Lars Ellenberg
2018-07-02 14:22   ` Jens Axboe

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).