From: Qu Wenruo wqu@suse.com
mainline inclusion from mainline-v5.2-rc2 commit 3065976b045f77a910809fa7699f99a1e7c0dbbb category: bugfix bugzilla: 13690 CVE: CVE-2019-19377
Introduce end_write_bio() for CVE-2019-19377. -------------------------------------------------
Since now flush_write_bio() could return error, kill the BUG_ON() first. Then don't call flush_write_bio() unconditionally, instead we check the return value from __extent_writepage() first.
If __extent_writepage() fails, we do cleanup, and return error without submitting the possible corrupted or half-baked bio.
If __extent_writepage() successes, then we call flush_write_bio() and return the result.
Signed-off-by: Qu Wenruo wqu@suse.com Reviewed-by: David Sterba dsterba@suse.com Signed-off-by: David Sterba dsterba@suse.com Conflicts: fs/btrfs/extent_io.c [yyl: adjust context]
Signed-off-by: Yang Yingliang yangyingliang@huawei.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- fs/btrfs/extent_io.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 11efb4f..7f2990f 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -2731,6 +2731,16 @@ static int __must_check submit_one_bio(struct bio *bio, int mirror_num, return blk_status_to_errno(ret); }
+/* Cleanup unsubmitted bios */ +static void end_write_bio(struct extent_page_data *epd, int ret) +{ + if (epd->bio) { + epd->bio->bi_status = errno_to_blk_status(ret); + bio_endio(epd->bio); + epd->bio = NULL; + } +} + /* * @opf: bio REQ_OP_* and REQ_* flags as one value * @tree: tree so we can call our merge_bio hook @@ -3438,6 +3448,9 @@ static noinline_for_stack int __extent_writepage_io(struct inode *inode, * records are inserted to lock ranges in the tree, and as dirty areas * are found, they are marked writeback. Then the lock bits are removed * and the end_io handler clears the writeback ranges + * + * Return 0 if everything goes well. + * Return <0 for error. */ static int __extent_writepage(struct page *page, struct writeback_control *wbc, struct extent_page_data *epd) @@ -3505,6 +3518,7 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc, end_extent_writepage(page, ret, start, page_end); } unlock_page(page); + ASSERT(ret <= 0); return ret;
done_unlocked: @@ -4054,6 +4068,11 @@ int extent_write_full_page(struct page *page, struct writeback_control *wbc) };
ret = __extent_writepage(page, wbc, &epd); + ASSERT(ret <= 0); + if (ret < 0) { + end_write_bio(&epd, ret); + return ret; + }
flush_write_bio(&epd); return ret;