* [PATCH v2] block: Fix general protection fault in bio_integrity_map_user() @ 2026-03-30 23:02 ` Sungwoo Kim 2026-03-31 7:16 ` Christoph Hellwig 2026-03-31 8:47 ` Kanchan Joshi 0 siblings, 2 replies; 6+ messages in thread From: Sungwoo Kim @ 2026-03-30 23:02 UTC (permalink / raw) To: Jens Axboe, Keith Busch Cc: Sungwoo Kim, Chao Shi, Weidong Zhu, Dave Tian, linux-block, linux-kernel pin_user_pages_fast() can partially succeed and return the number of pages that were actually pinned. However, the bio_integrity_map_user() does not handle this partial pinning. This leads to a general protection fault since bvec_from_pages() dereferences an unpinned page address, which is 0. To fix this, add a check to verify that all requested memory is pinned. KASAN splat: Oops: general protection fault, probably for non-canonical address 0xdffffc0000000001: 0000 [#1] PREEMPT SMP KASAN PTI KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f] RIP: 0010:_compound_head home/wukong/fuzznvme/linux/./include/linux/page-flags.h:240 [inline] RIP: 0010:bvec_from_pages home/wukong/fuzznvme/linux/block/bio-integrity.c:290 [inline] Fixes: 492c5d455969 ("block: bio-integrity: directly map user buffers") Acked-by: Chao Shi <cshi008@fiu.edu> Acked-by: Weidong Zhu <weizhu@fiu.edu> Acked-by: Dave Tian <daveti@purdue.edu> Signed-off-by: Sungwoo Kim <iam@sung-woo.kim> --- V1: https://lore.kernel.org/linux-block/20260308001358.1675543-2-iam@sung-woo.kim/T/#u V1->V2: - v1 incorrectly assumed pin_user_pages_fast() returns bytes. Fixed. block/bio-integrity.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/block/bio-integrity.c b/block/bio-integrity.c index 20f5d301d32d..992ce39e8ab9 100644 --- a/block/bio-integrity.c +++ b/block/bio-integrity.c @@ -338,6 +338,15 @@ int bio_integrity_map_user(struct bio *bio, struct iov_iter *iter) extraction_flags, &offset); if (unlikely(ret < 0)) goto free_bvec; + if (unlikely(ret != nr_vecs)) { + for (int i = 0; i < ret; i++) + unpin_user_page(pages[i]); + + if (pages != stack_pages) + kvfree(pages); + ret = -EFAULT; + goto free_bvec; + } nr_bvecs = bvec_from_pages(bvec, pages, nr_vecs, bytes, offset, &is_p2p); -- 2.47.3 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v2] block: Fix general protection fault in bio_integrity_map_user() 2026-03-30 23:02 ` [PATCH v2] block: Fix general protection fault in bio_integrity_map_user() Sungwoo Kim @ 2026-03-31 7:16 ` Christoph Hellwig 2026-04-02 18:03 ` Sungwoo Kim 2026-03-31 8:47 ` Kanchan Joshi 1 sibling, 1 reply; 6+ messages in thread From: Christoph Hellwig @ 2026-03-31 7:16 UTC (permalink / raw) To: Sungwoo Kim Cc: Jens Axboe, Keith Busch, Chao Shi, Weidong Zhu, Dave Tian, linux-block, linux-kernel On Mon, Mar 30, 2026 at 07:02:56PM -0400, Sungwoo Kim wrote: > pin_user_pages_fast() can partially succeed and return the number of > pages that were actually pinned. However, the bio_integrity_map_user() > does not handle this partial pinning. This leads to a general protection > fault since bvec_from_pages() dereferences an unpinned page address, > which is 0. Can you share the reproducer, or even better wire it up to blktests? > > To fix this, add a check to verify that all requested memory is pinned. > > KASAN splat: > > Oops: general protection fault, probably for non-canonical address 0xdffffc0000000001: 0000 [#1] PREEMPT SMP KASAN PTI > KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f] > RIP: 0010:_compound_head home/wukong/fuzznvme/linux/./include/linux/page-flags.h:240 [inline] > RIP: 0010:bvec_from_pages home/wukong/fuzznvme/linux/block/bio-integrity.c:290 [inline] > > Fixes: 492c5d455969 ("block: bio-integrity: directly map user buffers") > Acked-by: Chao Shi <cshi008@fiu.edu> > Acked-by: Weidong Zhu <weizhu@fiu.edu> > Acked-by: Dave Tian <daveti@purdue.edu> > Signed-off-by: Sungwoo Kim <iam@sung-woo.kim> > --- > V1: https://lore.kernel.org/linux-block/20260308001358.1675543-2-iam@sung-woo.kim/T/#u > V1->V2: > - v1 incorrectly assumed pin_user_pages_fast() returns bytes. Fixed. > > block/bio-integrity.c | 9 +++++++++ > 1 file changed, 9 insertions(+) > > diff --git a/block/bio-integrity.c b/block/bio-integrity.c > index 20f5d301d32d..992ce39e8ab9 100644 > --- a/block/bio-integrity.c > +++ b/block/bio-integrity.c > @@ -338,6 +338,15 @@ int bio_integrity_map_user(struct bio *bio, struct iov_iter *iter) > extraction_flags, &offset); > if (unlikely(ret < 0)) > goto free_bvec; > + if (unlikely(ret != nr_vecs)) { > + for (int i = 0; i < ret; i++) > + unpin_user_page(pages[i]); I guess this works fine even for a negative ret, but it looks really odd. > + if (pages != stack_pages) > + kvfree(pages); > + ret = -EFAULT; > + goto free_bvec; This now loses the original return value if it alredy was negative. I think the better fix here would be to switch to iov_iter_extract_bvecs, but that might be a bit too big for a backportable bugfix, so I guess we should merge your patch first once it is fixed up. ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2] block: Fix general protection fault in bio_integrity_map_user() 2026-03-31 7:16 ` Christoph Hellwig @ 2026-04-02 18:03 ` Sungwoo Kim 2026-04-06 5:39 ` Christoph Hellwig 0 siblings, 1 reply; 6+ messages in thread From: Sungwoo Kim @ 2026-04-02 18:03 UTC (permalink / raw) To: Christoph Hellwig Cc: Jens Axboe, Keith Busch, Chao Shi, Weidong Zhu, Dave Tian, linux-block, linux-kernel On Tue, Mar 31, 2026 at 4:16 PM Christoph Hellwig <hch@infradead.org> wrote: > > On Mon, Mar 30, 2026 at 07:02:56PM -0400, Sungwoo Kim wrote: > > pin_user_pages_fast() can partially succeed and return the number of > > pages that were actually pinned. However, the bio_integrity_map_user() > > does not handle this partial pinning. This leads to a general protection > > fault since bvec_from_pages() dereferences an unpinned page address, > > which is 0. > > Can you share the reproducer, or even better wire it up to blktests? Thank you for letting me know about blktests. I'm learning this and finding a way to reproduce this bug. If blktests is not suitable for reproducing this - it might be too early to think about this though - I have another idea to reproduce this. I can modify the pin_user_pages_fast() source to make it always partial success, so there are always some unpinned pages, which is a precondition of this bug. I'd like to ask for comments on this if it doesn't make sense. > > > > > To fix this, add a check to verify that all requested memory is pinned. > > > > KASAN splat: > > > > Oops: general protection fault, probably for non-canonical address 0xdffffc0000000001: 0000 [#1] PREEMPT SMP KASAN PTI > > KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f] > > RIP: 0010:_compound_head home/wukong/fuzznvme/linux/./include/linux/page-flags.h:240 [inline] > > RIP: 0010:bvec_from_pages home/wukong/fuzznvme/linux/block/bio-integrity.c:290 [inline] > > > > Fixes: 492c5d455969 ("block: bio-integrity: directly map user buffers") > > Acked-by: Chao Shi <cshi008@fiu.edu> > > Acked-by: Weidong Zhu <weizhu@fiu.edu> > > Acked-by: Dave Tian <daveti@purdue.edu> > > Signed-off-by: Sungwoo Kim <iam@sung-woo.kim> > > --- > > V1: https://lore.kernel.org/linux-block/20260308001358.1675543-2-iam@sung-woo.kim/T/#u > > V1->V2: > > - v1 incorrectly assumed pin_user_pages_fast() returns bytes. Fixed. > > > > block/bio-integrity.c | 9 +++++++++ > > 1 file changed, 9 insertions(+) > > > > diff --git a/block/bio-integrity.c b/block/bio-integrity.c > > index 20f5d301d32d..992ce39e8ab9 100644 > > --- a/block/bio-integrity.c > > +++ b/block/bio-integrity.c > > @@ -338,6 +338,15 @@ int bio_integrity_map_user(struct bio *bio, struct iov_iter *iter) > > extraction_flags, &offset); > > if (unlikely(ret < 0)) > > goto free_bvec; > > + if (unlikely(ret != nr_vecs)) { > > + for (int i = 0; i < ret; i++) > > + unpin_user_page(pages[i]); > > I guess this works fine even for a negative ret, but it looks really > odd. > > > + if (pages != stack_pages) > > + kvfree(pages); > > + ret = -EFAULT; > > + goto free_bvec; > > This now loses the original return value if it alredy was > negative. > > I think the better fix here would be to switch to > iov_iter_extract_bvecs, but that might be a bit too big for > a backportable bugfix, so I guess we should merge your patch > first once it is fixed up. > Okay. I'll find a reproducer first. And then let's discuss about a fix. Thanks again for your review. Sungwoo. ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2] block: Fix general protection fault in bio_integrity_map_user() 2026-04-02 18:03 ` Sungwoo Kim @ 2026-04-06 5:39 ` Christoph Hellwig 0 siblings, 0 replies; 6+ messages in thread From: Christoph Hellwig @ 2026-04-06 5:39 UTC (permalink / raw) To: Sungwoo Kim Cc: Christoph Hellwig, Jens Axboe, Keith Busch, Chao Shi, Weidong Zhu, Dave Tian, linux-block, linux-kernel On Fri, Apr 03, 2026 at 03:03:00AM +0900, Sungwoo Kim wrote: > Thank you for letting me know about blktests. I'm learning this and > finding a way to reproduce this bug. > If blktests is not suitable for reproducing this - it might be too > early to think about this though - I have another idea to reproduce > this. > I can modify the pin_user_pages_fast() source to make it always > partial success, so there are always some unpinned pages, which is a > precondition of this bug. > I'd like to ask for comments on this if it doesn't make sense. Using the failure injection framework to reproduce this sounds like a good idea. ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2] block: Fix general protection fault in bio_integrity_map_user() 2026-03-30 23:02 ` [PATCH v2] block: Fix general protection fault in bio_integrity_map_user() Sungwoo Kim 2026-03-31 7:16 ` Christoph Hellwig @ 2026-03-31 8:47 ` Kanchan Joshi 2026-04-02 18:24 ` Sungwoo Kim 1 sibling, 1 reply; 6+ messages in thread From: Kanchan Joshi @ 2026-03-31 8:47 UTC (permalink / raw) To: Sungwoo Kim, Jens Axboe, Keith Busch Cc: Chao Shi, Weidong Zhu, Dave Tian, linux-block, linux-kernel On 3/31/2026 4:32 AM, Sungwoo Kim wrote: > pin_user_pages_fast() can partially succeed and return the number of > pages that were actually pinned. However, the bio_integrity_map_user() > does not handle this partial pinning. This leads to a general protection > fault since bvec_from_pages() dereferences an unpinned page address, > which is 0. > > To fix this, add a check to verify that all requested memory is pinned. > > KASAN splat: > > Oops: general protection fault, probably for non-canonical address 0xdffffc0000000001: 0000 [#1] PREEMPT SMP KASAN PTI > KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f] > RIP: 0010:_compound_head home/wukong/fuzznvme/linux/./include/linux/page-flags.h:240 [inline] > RIP: 0010:bvec_from_pages home/wukong/fuzznvme/linux/block/bio-integrity.c:290 [inline] > > Fixes: 492c5d455969 ("block: bio-integrity: directly map user buffers") > Acked-by: Chao Shi<cshi008@fiu.edu> > Acked-by: Weidong Zhu<weizhu@fiu.edu> > Acked-by: Dave Tian<daveti@purdue.edu> > Signed-off-by: Sungwoo Kim<iam@sung-woo.kim> > --- > V1:https://lore.kernel.org/linux-block/20260308001358.1675543-2-iam@sung- > woo.kim/T/#u > V1->V2: > - v1 incorrectly assumed pin_user_pages_fast() returns bytes. Fixed. But this function does not call pin_user_pages_fast(). It calls iov_iter_extract_pages() which returns in bytes. So v1 maybe better than this patch? > > block/bio-integrity.c | 9 +++++++++ > 1 file changed, 9 insertions(+) > > diff --git a/block/bio-integrity.c b/block/bio-integrity.c > index 20f5d301d32d..992ce39e8ab9 100644 > --- a/block/bio-integrity.c > +++ b/block/bio-integrity.c > @@ -338,6 +338,15 @@ int bio_integrity_map_user(struct bio *bio, struct iov_iter *iter) > extraction_flags, &offset); > if (unlikely(ret < 0)) > goto free_bvec; > + if (unlikely(ret != nr_vecs)) { ret is in bytes and nr_vecs is in pages. Almost always we will go inside and throw failures for perfectly valid case. No? > + for (int i = 0; i < ret; i++) > + unpin_user_page(pages[i]); And out-of-bounds access here. > + > + if (pages != stack_pages) > + kvfree(pages); > + ret = -EFAULT; ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2] block: Fix general protection fault in bio_integrity_map_user() 2026-03-31 8:47 ` Kanchan Joshi @ 2026-04-02 18:24 ` Sungwoo Kim 0 siblings, 0 replies; 6+ messages in thread From: Sungwoo Kim @ 2026-04-02 18:24 UTC (permalink / raw) To: Kanchan Joshi Cc: Jens Axboe, Keith Busch, Chao Shi, Weidong Zhu, Dave Tian, linux-block, linux-kernel [snip] > > --- > > V1:https://lore.kernel.org/linux-block/20260308001358.1675543-2-iam@sung- > > woo.kim/T/#u > > V1->V2: > > - v1 incorrectly assumed pin_user_pages_fast() returns bytes. Fixed. > > But this function does not call pin_user_pages_fast(). It calls > iov_iter_extract_pages() which returns in bytes. So v1 maybe better than > this patch? Thank you for your review. If iov_iter_extract_pages() returns bytes, this patch is completely wrong. > > > > block/bio-integrity.c | 9 +++++++++ > > 1 file changed, 9 insertions(+) > > > > diff --git a/block/bio-integrity.c b/block/bio-integrity.c > > index 20f5d301d32d..992ce39e8ab9 100644 > > --- a/block/bio-integrity.c > > +++ b/block/bio-integrity.c > > @@ -338,6 +338,15 @@ int bio_integrity_map_user(struct bio *bio, struct iov_iter *iter) > > extraction_flags, &offset); > > if (unlikely(ret < 0)) > > goto free_bvec; > > + if (unlikely(ret != nr_vecs)) { > > ret is in bytes and nr_vecs is in pages. Almost always we will go inside > and throw failures for perfectly valid case. No? > Right. > > + for (int i = 0; i < ret; i++) > > + unpin_user_page(pages[i]); > > And out-of-bounds access here. I assume blktests can catch this. So, it might be a good idea to confirm the patch with blktests. I will do this in v3. Thank you again for your review. Sungwoo. > > > + > > + if (pages != stack_pages) > > + kvfree(pages); > > + ret = -EFAULT; > > ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-04-06 5:39 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <CGME20260330230512epcas5p3edfcbd6e163aab8b238c317418abb7a2@epcas5p3.samsung.com>
2026-03-30 23:02 ` [PATCH v2] block: Fix general protection fault in bio_integrity_map_user() Sungwoo Kim
2026-03-31 7:16 ` Christoph Hellwig
2026-04-02 18:03 ` Sungwoo Kim
2026-04-06 5:39 ` Christoph Hellwig
2026-03-31 8:47 ` Kanchan Joshi
2026-04-02 18:24 ` Sungwoo Kim
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox