diff options
author | Jens Axboe <axboe@suse.de> | 2005-04-16 18:25:40 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:25:40 -0400 |
commit | 4a534f93b371e8e6e87ae302757365f0f583e06b (patch) | |
tree | f9ed5470c81bd63dba86f425a2c3731802000c79 /drivers/block/ll_rw_blk.c | |
parent | 9c340d80f66faaea3522812d0d8c91d6a1b48a22 (diff) |
[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: Jens Axboe <axboe@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/block/ll_rw_blk.c')
-rw-r--r-- | drivers/block/ll_rw_blk.c | 5 |
1 files changed, 3 insertions, 2 deletions
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 02242e8ba996..2d6934a02867 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c | |||
@@ -2559,7 +2559,7 @@ EXPORT_SYMBOL(__blk_attempt_remerge); | |||
2559 | static int __make_request(request_queue_t *q, struct bio *bio) | 2559 | static int __make_request(request_queue_t *q, struct bio *bio) |
2560 | { | 2560 | { |
2561 | struct request *req, *freereq = NULL; | 2561 | struct request *req, *freereq = NULL; |
2562 | int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, err; | 2562 | int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, err, sync; |
2563 | sector_t sector; | 2563 | sector_t sector; |
2564 | 2564 | ||
2565 | sector = bio->bi_sector; | 2565 | sector = bio->bi_sector; |
@@ -2567,6 +2567,7 @@ static int __make_request(request_queue_t *q, struct bio *bio) | |||
2567 | cur_nr_sectors = bio_cur_sectors(bio); | 2567 | cur_nr_sectors = bio_cur_sectors(bio); |
2568 | 2568 | ||
2569 | rw = bio_data_dir(bio); | 2569 | rw = bio_data_dir(bio); |
2570 | sync = bio_sync(bio); | ||
2570 | 2571 | ||
2571 | /* | 2572 | /* |
2572 | * low level driver can indicate that it wants pages above a | 2573 | * low level driver can indicate that it wants pages above a |
@@ -2698,7 +2699,7 @@ get_rq: | |||
2698 | out: | 2699 | out: |
2699 | if (freereq) | 2700 | if (freereq) |
2700 | __blk_put_request(q, freereq); | 2701 | __blk_put_request(q, freereq); |
2701 | if (bio_sync(bio)) | 2702 | if (sync) |
2702 | __generic_unplug_device(q); | 2703 | __generic_unplug_device(q); |
2703 | 2704 | ||
2704 | spin_unlock_irq(q->queue_lock); | 2705 | spin_unlock_irq(q->queue_lock); |