dm_put_live_table_bio is called from the end of dm_submit_bio. However, at
this point, the bio may be already finished and the caller may have freed
the bio. Consequently, dm_put_live_table_bio accesses the stale "bio"
pointer.

This patch fixes the bug by loading the bi_opf value and passing this
value to dm_get_live_table_bio and dm_put_live_table_bio
instead of the bio.

This bug was found by running the lvm testsuite with kasan.

Signed-off-by: Mikulas Patocka <[email protected]>
Fixes: 563a225c9fd20 ("dm: introduce dm_{get,put}_live_table_bio called from 
dm_submit_bio")

---
 drivers/md/dm.c |   13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

Index: linux-2.6/drivers/md/dm.c
===================================================================
--- linux-2.6.orig/drivers/md/dm.c      2022-06-13 13:01:16.000000000 +0200
+++ linux-2.6/drivers/md/dm.c   2022-06-16 09:20:45.000000000 +0200
@@ -711,18 +711,18 @@ static void dm_put_live_table_fast(struc
 }
 
 static inline struct dm_table *dm_get_live_table_bio(struct mapped_device *md,
-                                                    int *srcu_idx, struct bio 
*bio)
+                                                    int *srcu_idx, unsigned 
bio_opf)
 {
-       if (bio->bi_opf & REQ_NOWAIT)
+       if (bio_opf & REQ_NOWAIT)
                return dm_get_live_table_fast(md);
        else
                return dm_get_live_table(md, srcu_idx);
 }
 
 static inline void dm_put_live_table_bio(struct mapped_device *md, int 
srcu_idx,
-                                        struct bio *bio)
+                                        unsigned bio_opf)
 {
-       if (bio->bi_opf & REQ_NOWAIT)
+       if (bio_opf & REQ_NOWAIT)
                dm_put_live_table_fast(md);
        else
                dm_put_live_table(md, srcu_idx);
@@ -1711,8 +1711,9 @@ static void dm_submit_bio(struct bio *bi
        struct mapped_device *md = bio->bi_bdev->bd_disk->private_data;
        int srcu_idx;
        struct dm_table *map;
+       unsigned bio_opf = bio->bi_opf;
 
-       map = dm_get_live_table_bio(md, &srcu_idx, bio);
+       map = dm_get_live_table_bio(md, &srcu_idx, bio_opf);
 
        /* If suspended, or map not yet available, queue this IO for later */
        if (unlikely(test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags)) ||
@@ -1728,7 +1729,7 @@ static void dm_submit_bio(struct bio *bi
 
        dm_split_and_process_bio(md, map, bio);
 out:
-       dm_put_live_table_bio(md, srcu_idx, bio);
+       dm_put_live_table_bio(md, srcu_idx, bio_opf);
 }
 
 static bool dm_poll_dm_io(struct dm_io *io, struct io_comp_batch *iob,
--
dm-devel mailing list
[email protected]
https://listman.redhat.com/mailman/listinfo/dm-devel

Reply via email to