Skip to content

Commit 91e1062

Browse files
Milan Brozkergon
authored andcommitted
dm crypt: use bio_add_page
Fix possible max_phys_segments violation in cloned dm-crypt bio. In write operation dm-crypt needs to allocate new bio request and run crypto operation on this clone. Cloned request has always the same size, but number of physical segments can be increased and violate max_phys_segments restriction. This can lead to data corruption and serious hardware malfunction. This was observed when using XFS over dm-crypt and at least two HBA controller drivers (arcmsr, cciss) recently. Fix it by using bio_add_page() call (which tests for other restrictions too) instead of constructing own biovec. All versions of dm-crypt are affected by this bug. Cc: stable@kernel.org Cc: dm-crypt@saout.de Signed-off-by: Milan Broz <mbroz@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com>
1 parent 9121250 commit 91e1062

File tree

1 file changed

+11
-13
lines changed

1 file changed

+11
-13
lines changed

drivers/md/dm-crypt.c

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,8 @@ static struct bio *crypt_alloc_buffer(struct dm_crypt_io *io, unsigned size)
398398
struct bio *clone;
399399
unsigned int nr_iovecs = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
400400
gfp_t gfp_mask = GFP_NOIO | __GFP_HIGHMEM;
401-
unsigned int i;
401+
unsigned i, len;
402+
struct page *page;
402403

403404
clone = bio_alloc_bioset(GFP_NOIO, nr_iovecs, cc->bs);
404405
if (!clone)
@@ -407,10 +408,8 @@ static struct bio *crypt_alloc_buffer(struct dm_crypt_io *io, unsigned size)
407408
clone_init(io, clone);
408409

409410
for (i = 0; i < nr_iovecs; i++) {
410-
struct bio_vec *bv = bio_iovec_idx(clone, i);
411-
412-
bv->bv_page = mempool_alloc(cc->page_pool, gfp_mask);
413-
if (!bv->bv_page)
411+
page = mempool_alloc(cc->page_pool, gfp_mask);
412+
if (!page)
414413
break;
415414

416415
/*
@@ -421,15 +420,14 @@ static struct bio *crypt_alloc_buffer(struct dm_crypt_io *io, unsigned size)
421420
if (i == (MIN_BIO_PAGES - 1))
422421
gfp_mask = (gfp_mask | __GFP_NOWARN) & ~__GFP_WAIT;
423422

424-
bv->bv_offset = 0;
425-
if (size > PAGE_SIZE)
426-
bv->bv_len = PAGE_SIZE;
427-
else
428-
bv->bv_len = size;
423+
len = (size > PAGE_SIZE) ? PAGE_SIZE : size;
424+
425+
if (!bio_add_page(clone, page, len, 0)) {
426+
mempool_free(page, cc->page_pool);
427+
break;
428+
}
429429

430-
clone->bi_size += bv->bv_len;
431-
clone->bi_vcnt++;
432-
size -= bv->bv_len;
430+
size -= len;
433431
}
434432

435433
if (!clone->bi_size) {

0 commit comments

Comments
 (0)