From: Justin Tee justin.tee@broadcom.com
mainline inclusion from mainline-v5.5-rc1 commit ece841abbed2da71fa10710c687c9ce9efb6bf69 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I8ZZ4S CVE: NA
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
--------------------------------
7c20f11680a4 ("bio-integrity: stop abusing bi_end_io") moves bio_integrity_free from bio_uninit() to bio_integrity_verify_fn() and bio_endio(). This way looks wrong because bio may be freed without calling bio_endio(), for example, blk_rq_unprep_clone() is called from dm_mq_queue_rq() when the underlying queue of dm-mpath is busy.
So memory leak of bio integrity data is caused by commit 7c20f11680a4.
Fixes this issue by re-adding bio_integrity_free() to bio_uninit().
Fixes: 7c20f11680a4 ("bio-integrity: stop abusing bi_end_io") Reviewed-by: Christoph Hellwig hch@lst.de Signed-off-by Justin Tee justin.tee@broadcom.com
Add commit log, and simplify/fix the original patch wroten by Justin.
Signed-off-by: Ming Lei ming.lei@redhat.com Signed-off-by: Jens Axboe axboe@kernel.dk
Conflicts: block/bio.c commit 6f70fb66182b ("blkcg: remove bio_disassociate_task()") replaced bio_disassociate_task() with bio_disassociate_blkg(); block/blk.h commit 4316b79e4321 ("block: kill legacy parts of timeout handling") deleted declaration of blk_timeout_work(); commit 43b729bfe9cf ("block: move integrity_req_gap_{back,front}_merge to blk.h") add comment of "CONFIG_BLK_DEV_INTEGRITY" Signed-off-by: Li Lingfeng lilingfeng3@huawei.com --- block/bio-integrity.c | 2 +- block/bio.c | 3 +++ block/blk.h | 4 ++++ 3 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/block/bio-integrity.c b/block/bio-integrity.c index 2e22a3f7466a..f6f94ba56a82 100644 --- a/block/bio-integrity.c +++ b/block/bio-integrity.c @@ -114,7 +114,7 @@ EXPORT_SYMBOL(bio_integrity_alloc); * Description: Used to free the integrity portion of a bio. Usually * called from bio_free(). */ -static void bio_integrity_free(struct bio *bio) +void bio_integrity_free(struct bio *bio) { struct bio_integrity_payload *bip = bio_integrity(bio); struct bio_set *bs = bio->bi_pool; diff --git a/block/bio.c b/block/bio.c index 06193e854577..df7cecce0278 100644 --- a/block/bio.c +++ b/block/bio.c @@ -245,6 +245,9 @@ struct bio_vec *bvec_alloc(gfp_t gfp_mask, int nr, unsigned long *idx, void bio_uninit(struct bio *bio) { bio_disassociate_task(bio); + + if (bio_integrity(bio)) + bio_integrity_free(bio); } EXPORT_SYMBOL(bio_uninit);
diff --git a/block/blk.h b/block/blk.h index 965e9c507654..6d188b275fe9 100644 --- a/block/blk.h +++ b/block/blk.h @@ -178,6 +178,7 @@ static inline void blk_queue_enter_live(struct request_queue *q) #ifdef CONFIG_BLK_DEV_INTEGRITY void blk_flush_integrity(void); bool __bio_integrity_endio(struct bio *); +void bio_integrity_free(struct bio *bio); static inline bool bio_integrity_endio(struct bio *bio) { if (bio_integrity(bio)) @@ -192,6 +193,9 @@ static inline bool bio_integrity_endio(struct bio *bio) { return true; } +static inline void bio_integrity_free(struct bio *bio) +{ +} #endif
void blk_timeout_work(struct work_struct *work);