mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v3 for-6.16/block 0/3] brd: discard bugfix
@ 2025-05-06  6:17 Yu Kuai
  2025-05-06  6:17 ` [PATCH v3 for-6.16/block 1/3] brd: protect page with rcu Yu Kuai
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Yu Kuai @ 2025-05-06  6:17 UTC (permalink / raw)
  To: hch, axboe, kbusch
  Cc: linux-block, linux-kernel, yukuai3, yukuai1, yi.zhang, yangerkun,
	johnny.chenyi

From: Yu Kuai <yukuai3@huawei.com>

changes in v3:
 - rebase on the top of for-6.16/block
 - add comments in patch 1 about NULL page.

changes in v2:
 - rebase on the top of the other patchset:
 https://lore.kernel.org/all/20250421072641.1311040-1-hch@lst.de/
 - merge top 2 patches from v1 into one patch;
 - add reviewed-by for patch 2,3

Yu Kuai (3):
  brd: protect page with rcu
  brd: fix aligned_sector from brd_do_discard()
  brd: fix discard end sector

 drivers/block/brd.c | 31 ++++++++++++++++++++++++-------
 1 file changed, 24 insertions(+), 7 deletions(-)

-- 
2.39.2


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v3 for-6.16/block 1/3] brd: protect page with rcu
  2025-05-06  6:17 [PATCH v3 for-6.16/block 0/3] brd: discard bugfix Yu Kuai
@ 2025-05-06  6:17 ` Yu Kuai
  2025-05-06  6:27   ` Christoph Hellwig
  2025-05-06  6:17 ` [PATCH v3 for-6.16/block 2/3] brd: fix aligned_sector from brd_do_discard() Yu Kuai
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 6+ messages in thread
From: Yu Kuai @ 2025-05-06  6:17 UTC (permalink / raw)
  To: hch, axboe, kbusch
  Cc: linux-block, linux-kernel, yukuai3, yukuai1, yi.zhang, yangerkun,
	johnny.chenyi

From: Yu Kuai <yukuai3@huawei.com>

Currently, after fetching the page by xa_load() in IO path, there is no
protection and page can be freed concurrently by discard:

cpu0
brd_submit_bio
 brd_do_bvec
  page = brd_lookup_page
                          cpu1
                          brd_submit_bio
                           brd_do_discard
                            page = __xa_erase()
                            __free_page()
  // page UAF

Fix the problem by protecting page with rcu.

Meanwhile, if page is already freed, also prevent BUG_ON() by skipping
the write, and user will get zero data later if there is no page.

Fixes: 9ead7efc6f3f ("brd: implement discard support")
Signed-off-by: Yu Kuai <yukuai3@huawei.com>
---
 drivers/block/brd.c | 20 +++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)

diff --git a/drivers/block/brd.c b/drivers/block/brd.c
index fa1290992a7f..fc793d48a9c6 100644
--- a/drivers/block/brd.c
+++ b/drivers/block/brd.c
@@ -132,12 +132,18 @@ static bool brd_rw_bvec(struct brd_device *brd, struct bio *bio)
 		}
 	}
 
+	rcu_read_lock();
 	page = brd_lookup_page(brd, sector);
 
 	kaddr = bvec_kmap_local(&bv);
 	if (op_is_write(opf)) {
-		BUG_ON(!page);
-		memcpy_to_page(page, offset, kaddr, bv.bv_len);
+		/*
+		 * Page can be removed by concurrent discard, it's fine to skip
+		 * the write and user will read zero data if page does not
+		 * exist.
+		 */
+		if (page)
+			memcpy_to_page(page, offset, kaddr, bv.bv_len);
 	} else {
 		if (page)
 			memcpy_from_page(kaddr, page, offset, bv.bv_len);
@@ -145,11 +151,19 @@ static bool brd_rw_bvec(struct brd_device *brd, struct bio *bio)
 			memset(kaddr, 0, bv.bv_len);
 	}
 	kunmap_local(kaddr);
+	rcu_read_unlock();
 
 	bio_advance_iter_single(bio, &bio->bi_iter, bv.bv_len);
 	return true;
 }
 
+static void brd_free_one_page(struct rcu_head *head)
+{
+	struct page *page = container_of(head, struct page, rcu_head);
+
+	__free_page(page);
+}
+
 static void brd_do_discard(struct brd_device *brd, sector_t sector, u32 size)
 {
 	sector_t aligned_sector = (sector + PAGE_SECTORS) & ~PAGE_SECTORS;
@@ -160,7 +174,7 @@ static void brd_do_discard(struct brd_device *brd, sector_t sector, u32 size)
 	while (size >= PAGE_SIZE && aligned_sector < rd_size * 2) {
 		page = __xa_erase(&brd->brd_pages, aligned_sector >> PAGE_SECTORS_SHIFT);
 		if (page) {
-			__free_page(page);
+			call_rcu(&page->rcu_head, brd_free_one_page);
 			brd->brd_nr_pages--;
 		}
 		aligned_sector += PAGE_SECTORS;
-- 
2.39.2


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v3 for-6.16/block 2/3] brd: fix aligned_sector from brd_do_discard()
  2025-05-06  6:17 [PATCH v3 for-6.16/block 0/3] brd: discard bugfix Yu Kuai
  2025-05-06  6:17 ` [PATCH v3 for-6.16/block 1/3] brd: protect page with rcu Yu Kuai
@ 2025-05-06  6:17 ` Yu Kuai
  2025-05-06  6:17 ` [PATCH v3 for-6.16/block 3/3] brd: fix discard end sector Yu Kuai
  2025-05-06 13:48 ` [PATCH v3 for-6.16/block 0/3] brd: discard bugfix Jens Axboe
  3 siblings, 0 replies; 6+ messages in thread
From: Yu Kuai @ 2025-05-06  6:17 UTC (permalink / raw)
  To: hch, axboe, kbusch
  Cc: linux-block, linux-kernel, yukuai3, yukuai1, yi.zhang, yangerkun,
	johnny.chenyi

From: Yu Kuai <yukuai3@huawei.com>

The calculation is just wrong, fix it by round_up().

Fixes: 9ead7efc6f3f ("brd: implement discard support")
Signed-off-by: Yu Kuai <yukuai3@huawei.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 drivers/block/brd.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/block/brd.c b/drivers/block/brd.c
index fc793d48a9c6..2753fb21410b 100644
--- a/drivers/block/brd.c
+++ b/drivers/block/brd.c
@@ -166,7 +166,7 @@ static void brd_free_one_page(struct rcu_head *head)
 
 static void brd_do_discard(struct brd_device *brd, sector_t sector, u32 size)
 {
-	sector_t aligned_sector = (sector + PAGE_SECTORS) & ~PAGE_SECTORS;
+	sector_t aligned_sector = round_up(sector, PAGE_SECTORS);
 	struct page *page;
 
 	size -= (aligned_sector - sector) * SECTOR_SIZE;
-- 
2.39.2


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v3 for-6.16/block 3/3] brd: fix discard end sector
  2025-05-06  6:17 [PATCH v3 for-6.16/block 0/3] brd: discard bugfix Yu Kuai
  2025-05-06  6:17 ` [PATCH v3 for-6.16/block 1/3] brd: protect page with rcu Yu Kuai
  2025-05-06  6:17 ` [PATCH v3 for-6.16/block 2/3] brd: fix aligned_sector from brd_do_discard() Yu Kuai
@ 2025-05-06  6:17 ` Yu Kuai
  2025-05-06 13:48 ` [PATCH v3 for-6.16/block 0/3] brd: discard bugfix Jens Axboe
  3 siblings, 0 replies; 6+ messages in thread
From: Yu Kuai @ 2025-05-06  6:17 UTC (permalink / raw)
  To: hch, axboe, kbusch
  Cc: linux-block, linux-kernel, yukuai3, yukuai1, yi.zhang, yangerkun,
	johnny.chenyi

From: Yu Kuai <yukuai3@huawei.com>

brd_do_discard() just aligned start sector to page, this can only work
if the discard size if at least one page. For example:

blkdiscard /dev/ram0 -o 5120 -l 1024

In this case, size = (1024 - (8192 - 5120)), which is a huge value.

Fix the problem by round_down() the end sector.

Fixes: 9ead7efc6f3f ("brd: implement discard support")
Signed-off-by: Yu Kuai <yukuai3@huawei.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 drivers/block/brd.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/block/brd.c b/drivers/block/brd.c
index 2753fb21410b..a3725673cf16 100644
--- a/drivers/block/brd.c
+++ b/drivers/block/brd.c
@@ -167,18 +167,21 @@ static void brd_free_one_page(struct rcu_head *head)
 static void brd_do_discard(struct brd_device *brd, sector_t sector, u32 size)
 {
 	sector_t aligned_sector = round_up(sector, PAGE_SECTORS);
+	sector_t aligned_end = round_down(
+			sector + (size >> SECTOR_SHIFT), PAGE_SECTORS);
 	struct page *page;
 
-	size -= (aligned_sector - sector) * SECTOR_SIZE;
+	if (aligned_end <= aligned_sector)
+		return;
+
 	xa_lock(&brd->brd_pages);
-	while (size >= PAGE_SIZE && aligned_sector < rd_size * 2) {
+	while (aligned_sector < aligned_end && aligned_sector < rd_size * 2) {
 		page = __xa_erase(&brd->brd_pages, aligned_sector >> PAGE_SECTORS_SHIFT);
 		if (page) {
 			call_rcu(&page->rcu_head, brd_free_one_page);
 			brd->brd_nr_pages--;
 		}
 		aligned_sector += PAGE_SECTORS;
-		size -= PAGE_SIZE;
 	}
 	xa_unlock(&brd->brd_pages);
 }
-- 
2.39.2


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3 for-6.16/block 1/3] brd: protect page with rcu
  2025-05-06  6:17 ` [PATCH v3 for-6.16/block 1/3] brd: protect page with rcu Yu Kuai
@ 2025-05-06  6:27   ` Christoph Hellwig
  0 siblings, 0 replies; 6+ messages in thread
From: Christoph Hellwig @ 2025-05-06  6:27 UTC (permalink / raw)
  To: Yu Kuai
  Cc: hch, axboe, kbusch, linux-block, linux-kernel, yukuai3, yi.zhang,
	yangerkun, johnny.chenyi

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3 for-6.16/block 0/3] brd: discard bugfix
  2025-05-06  6:17 [PATCH v3 for-6.16/block 0/3] brd: discard bugfix Yu Kuai
                   ` (2 preceding siblings ...)
  2025-05-06  6:17 ` [PATCH v3 for-6.16/block 3/3] brd: fix discard end sector Yu Kuai
@ 2025-05-06 13:48 ` Jens Axboe
  3 siblings, 0 replies; 6+ messages in thread
From: Jens Axboe @ 2025-05-06 13:48 UTC (permalink / raw)
  To: hch, kbusch, Yu Kuai
  Cc: linux-block, linux-kernel, yukuai3, yi.zhang, yangerkun, johnny.chenyi


On Tue, 06 May 2025 14:17:53 +0800, Yu Kuai wrote:
> changes in v3:
>  - rebase on the top of for-6.16/block
>  - add comments in patch 1 about NULL page.
> 
> changes in v2:
>  - rebase on the top of the other patchset:
>  https://lore.kernel.org/all/20250421072641.1311040-1-hch@lst.de/
>  - merge top 2 patches from v1 into one patch;
>  - add reviewed-by for patch 2,3
> 
> [...]

Applied, thanks!

[1/3] brd: protect page with rcu
      commit: 0e8acffc1be10d53e909b3aa43831d6c2d25a579
[2/3] brd: fix aligned_sector from brd_do_discard()
      commit: d4099f8893b057ad7e8d61df76bdeaf807ebd679
[3/3] brd: fix discard end sector
      commit: a26a339a654b9403f0ee1004f1db4c2b2a355460

Best regards,
-- 
Jens Axboe




^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2025-05-06 13:48 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-05-06  6:17 [PATCH v3 for-6.16/block 0/3] brd: discard bugfix Yu Kuai
2025-05-06  6:17 ` [PATCH v3 for-6.16/block 1/3] brd: protect page with rcu Yu Kuai
2025-05-06  6:27   ` Christoph Hellwig
2025-05-06  6:17 ` [PATCH v3 for-6.16/block 2/3] brd: fix aligned_sector from brd_do_discard() Yu Kuai
2025-05-06  6:17 ` [PATCH v3 for-6.16/block 3/3] brd: fix discard end sector Yu Kuai
2025-05-06 13:48 ` [PATCH v3 for-6.16/block 0/3] brd: discard bugfix Jens Axboe

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®