FAQ Search Today's Posts Mark Forums Read
» Video Reviews

» Linux Archive

Linux-archive is a website aiming to archive linux email lists and to make them easily accessible for linux users/developers.


» Sponsor

» Partners

» Sponsor

Go Back   Linux Archive > Redhat > Device-mapper Development

 
 
LinkBack Thread Tools
 
Old 09-20-2010, 12:01 AM
Michał Mirosław
 
Default dm: Fix possible NULL dereferences

bio_alloc_bioset() might return NULL. Or maybe passed
bio_sets are guaranteed to have enough free bios?

Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
---
drivers/md/dm.c | 48 ++++++++++++++++++++++++++++++++++++++----------
1 files changed, 38 insertions(+), 10 deletions(-)

diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index ac384b2..60cfacd 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -1129,6 +1129,9 @@ static struct bio *split_bvec(struct bio *bio, sector_t sector,
struct bio_vec *bv = bio->bi_io_vec + idx;

clone = bio_alloc_bioset(GFP_NOIO, 1, bs);
+ if (unlikely(!clone))
+ return NULL;
+
clone->bi_destructor = dm_bio_destructor;
*clone->bi_io_vec = *bv;

@@ -1142,7 +1145,10 @@ static struct bio *split_bvec(struct bio *bio, sector_t sector,
clone->bi_flags |= 1 << BIO_CLONED;

if (bio_integrity(bio)) {
- bio_integrity_clone(clone, bio, GFP_NOIO, bs);
+ if (bio_integrity_clone(clone, bio, GFP_NOIO, bs) < 0) {
+ bio_put(clone);
+ return NULL;
+ }
bio_integrity_trim(clone,
bio_sector_offset(bio, idx, offset), len);
}
@@ -1160,6 +1166,9 @@ static struct bio *clone_bio(struct bio *bio, sector_t sector,
struct bio *clone;

clone = bio_alloc_bioset(GFP_NOIO, bio->bi_max_vecs, bs);
+ if (unlikely(!clone))
+ return NULL;
+
__bio_clone(clone, bio);
clone->bi_rw &= ~REQ_HARDBARRIER;
clone->bi_destructor = dm_bio_destructor;
@@ -1170,7 +1179,10 @@ static struct bio *clone_bio(struct bio *bio, sector_t sector,
clone->bi_flags &= ~(1 << BIO_SEG_VALID);

if (bio_integrity(bio)) {
- bio_integrity_clone(clone, bio, GFP_NOIO, bs);
+ if (bio_integrity_clone(clone, bio, GFP_NOIO, bs) < 0) {
+ bio_put(clone);
+ return NULL;
+ }

if (idx != bio->bi_idx || clone->bi_size < bio->bi_size)
bio_integrity_trim(clone,
@@ -1192,7 +1204,7 @@ static struct dm_target_io *alloc_tio(struct clone_info *ci,
return tio;
}

-static void __issue_target_request(struct clone_info *ci, struct dm_target *ti,
+static int __issue_target_request(struct clone_info *ci, struct dm_target *ti,
unsigned request_nr, sector_t len)
{
struct dm_target_io *tio = alloc_tio(ci, ti);
@@ -1206,6 +1218,9 @@ static void __issue_target_request(struct clone_info *ci, struct dm_target *ti,
* and discard, so no need for concern about wasted bvec allocations.
*/
clone = bio_alloc_bioset(GFP_NOIO, ci->bio->bi_max_vecs, ci->md->bs);
+ if (unlikely(!clone))
+ return -EIO;
+
__bio_clone(clone, ci->bio);
clone->bi_destructor = dm_bio_destructor;
if (len) {
@@ -1214,15 +1229,18 @@ static void __issue_target_request(struct clone_info *ci, struct dm_target *ti,
}

__map_bio(ti, clone, tio);
+ return 0;
}

-static void __issue_target_requests(struct clone_info *ci, struct dm_target *ti,
+static int __issue_target_requests(struct clone_info *ci, struct dm_target *ti,
unsigned num_requests, sector_t len)
{
unsigned request_nr;

for (request_nr = 0; request_nr < num_requests; request_nr++)
- __issue_target_request(ci, ti, request_nr, len);
+ if (__issue_target_request(ci, ti, request_nr, len) < 0)
+ return -EIO;
+ return 0;
}

static int __clone_and_map_empty_barrier(struct clone_info *ci)
@@ -1231,7 +1249,8 @@ static int __clone_and_map_empty_barrier(struct clone_info *ci)
struct dm_target *ti;

while ((ti = dm_table_get_target(ci->map, target_nr++)))
- __issue_target_requests(ci, ti, ti->num_flush_requests, 0);
+ if (__issue_target_requests(ci, ti, ti->num_flush_requests, 0) < 0)
+ return -EIO;

ci->sector_count = 0;

@@ -1241,7 +1260,7 @@ static int __clone_and_map_empty_barrier(struct clone_info *ci)
/*
* Perform all io with a single clone.
*/
-static void __clone_and_map_simple(struct clone_info *ci, struct dm_target *ti)
+static int __clone_and_map_simple(struct clone_info *ci, struct dm_target *ti)
{
struct bio *clone, *bio = ci->bio;
struct dm_target_io *tio;
@@ -1250,8 +1269,11 @@ static void __clone_and_map_simple(struct clone_info *ci, struct dm_target *ti)
clone = clone_bio(bio, ci->sector, ci->idx,
bio->bi_vcnt - ci->idx, ci->sector_count,
ci->md->bs);
+ if (unlikely(!clone))
+ return -EIO;
__map_bio(ti, clone, tio);
ci->sector_count = 0;
+ return 0;
}

static int __clone_and_map_discard(struct clone_info *ci)
@@ -1274,7 +1296,8 @@ static int __clone_and_map_discard(struct clone_info *ci)

len = min(ci->sector_count, max_io_len_target_boundary(ci->sector, ti));

- __issue_target_requests(ci, ti, ti->num_discard_requests, len);
+ if (__issue_target_requests(ci, ti, ti->num_discard_requests, len) < 0)
+ return -EIO;

ci->sector += len;
} while (ci->sector_count -= len);
@@ -1306,7 +1329,7 @@ static int __clone_and_map(struct clone_info *ci)
* Optimise for the simple case where we can do all of
* the remaining io with a single clone.
*/
- __clone_and_map_simple(ci, ti);
+ return __clone_and_map_simple(ci, ti);

} else if (to_sector(bio->bi_io_vec[ci->idx].bv_len) <= max) {
/*
@@ -1330,6 +1353,8 @@ static int __clone_and_map(struct clone_info *ci)
tio = alloc_tio(ci, ti);
clone = clone_bio(bio, ci->sector, ci->idx, i - ci->idx, len,
ci->md->bs);
+ if (unlikely(!clone))
+ return -EIO;
__map_bio(ti, clone, tio);

ci->sector += len;
@@ -1359,7 +1384,8 @@ static int __clone_and_map(struct clone_info *ci)
clone = split_bvec(bio, ci->sector, ci->idx,
bv->bv_offset + offset, len,
ci->md->bs);
-
+ if (unlikely(!clone))
+ return -EIO;
__map_bio(ti, clone, tio);

ci->sector += len;
@@ -2510,6 +2536,8 @@ static int dm_rq_barrier(struct mapped_device *md)
ti = dm_table_get_target(map, i);
for (j = 0; j < ti->num_flush_requests; j++) {
clone = clone_rq(md->flush_request, md, GFP_NOIO);
+ if (unlikely(!clone))
+ return -EIO;
dm_rq_set_target_request_nr(clone, j);
atomic_inc(&md->pending[rq_data_dir(clone)]);
map_request(ti, clone, md);
--
1.7.1

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
 
Old 11-02-2010, 03:16 PM
Mike Snitzer
 
Default dm: Fix possible NULL dereferences

On Sun, Sep 19 2010 at 8:01pm -0400,
Michał Mirosław <mirq-linux@rere.qmqm.pl> wrote:

> bio_alloc_bioset() might return NULL. Or maybe passed
> bio_sets are guaranteed to have enough free bios?

The passed bio_set is allocated in dm_alloc_md_mempools() using
bioset_create() -- so it does have allocation guarantees.

Mike

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
 

Thread Tools




All times are GMT. The time now is 12:16 PM.

VBulletin, Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
Content Relevant URLs by vBSEO ©2007, Crawlability, Inc.
Copyright 2007 - 2008, www.linux-archive.org