Commit 4a534f93 authored by Jens Axboe's avatar Jens Axboe Committed by Linus Torvalds

[PATCH] possible use-after-free of bio

There is a possibility that a bio will be accessed after it has been freed
on SCSI.  It happens if you submit a bio with BIO_SYNC marked and the
auto-unplugging kicks the request_fn, SCSI re-enables interrupts in-between
so if the request completes between the add_request() in __make_request()
and the bio_sync() call, we could be looking at a dead bio.  It's a slim
race, but it has been triggered in the Real World.

So assign bio_sync() to a local variable instead.
Signed-off-by: default avatarJens Axboe <axboe@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 9c340d80
...@@ -2559,7 +2559,7 @@ EXPORT_SYMBOL(__blk_attempt_remerge); ...@@ -2559,7 +2559,7 @@ EXPORT_SYMBOL(__blk_attempt_remerge);
static int __make_request(request_queue_t *q, struct bio *bio) static int __make_request(request_queue_t *q, struct bio *bio)
{ {
struct request *req, *freereq = NULL; struct request *req, *freereq = NULL;
int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, err; int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, err, sync;
sector_t sector; sector_t sector;
sector = bio->bi_sector; sector = bio->bi_sector;
...@@ -2567,6 +2567,7 @@ static int __make_request(request_queue_t *q, struct bio *bio) ...@@ -2567,6 +2567,7 @@ static int __make_request(request_queue_t *q, struct bio *bio)
cur_nr_sectors = bio_cur_sectors(bio); cur_nr_sectors = bio_cur_sectors(bio);
rw = bio_data_dir(bio); rw = bio_data_dir(bio);
sync = bio_sync(bio);
/* /*
* low level driver can indicate that it wants pages above a * low level driver can indicate that it wants pages above a
...@@ -2698,7 +2699,7 @@ static int __make_request(request_queue_t *q, struct bio *bio) ...@@ -2698,7 +2699,7 @@ static int __make_request(request_queue_t *q, struct bio *bio)
out: out:
if (freereq) if (freereq)
__blk_put_request(q, freereq); __blk_put_request(q, freereq);
if (bio_sync(bio)) if (sync)
__generic_unplug_device(q); __generic_unplug_device(q);
spin_unlock_irq(q->queue_lock); spin_unlock_irq(q->queue_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment