* [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 related [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 related [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 related [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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.