Function __bio_map_kern() allocates new fresh bio with bi_bdev field undefined and set to NULL. Than it calls bio_add_pc_page() which in turn calls merge_bvec_fn() callback if defined, passing bvec_megre_data structure pointer, with bi_bdev filesd initialized to "bio::bi_bdev" (equal to NULL). There are 9 of them so far. At least some of them (like "rbd_merge_bvec", "linear_mergeable_bvec") then dereference undefined "bvec_megre_data::bi_bdev" to get start sector of the device, resulting in NULL pointer dereference. This patch adds check for non-NULL bio->bi_bdev pointer to make sure, that the device is defined, otherwise there is no sense to call this callback at all.
Signed-of-by: Stanislav Kinsbursky <stanislav.kinsbur...@profitbricks.com> --- block/bio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block/bio.c b/block/bio.c index 0ec61c9..cb45186 100644 --- a/block/bio.c +++ b/block/bio.c @@ -725,7 +725,7 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page unsigned int prev_bv_len = prev->bv_len; prev->bv_len += len; - if (q->merge_bvec_fn) { + if (q->merge_bvec_fn && bio->bi_bdev) { struct bvec_merge_data bvm = { /* prev_bvec is already charged in bi_size, discharge it in order to @@ -787,7 +787,7 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page * depending on offset), it can specify a merge_bvec_fn in the * queue to get further control */ - if (q->merge_bvec_fn) { + if (q->merge_bvec_fn && bio->bi_bdev) { struct bvec_merge_data bvm = { .bi_bdev = bio->bi_bdev, .bi_sector = bio->bi_iter.bi_sector, -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/