* [PATCH] io_uring: fix out-of-bounds bvec access in io_vec_fill_kern_bvec
@ 2026-10-01 14:23 Ömer Mete Kaya
2026-10-01 15:36 ` Gabriel Krisman Bertazi
0 siblings, 1 reply; 4+ messages in thread
From: Ömer Mete Kaya @ 2026-10-01 14:23 UTC (permalink / raw)
To: axboe; +Cc: io-uring, linux-kernel, Ömer Mete Kaya
for_each_mp_bvec() dereferences src_bvec[bi_idx] in the loop condition
before the body is entered, with no guard against bi_idx reaching
imu->nr_bvecs. iov_kern_bvec_size() stops iterating when i reaches
imu->nr_bvecs even if bi_size is still non-zero, so the fill loop can
walk past the end of the bvec array and overrun res_bvec[].
Open-code the loop with an explicit bi_idx < imu->nr_bvecs check before
the dereference, matching the termination condition in
iov_kern_bvec_size().
Fixes: 1045afae4b88 ("io_uring: support vectored kernel fixed buffer")
Signed-off-by: Ömer Mete Kaya <omermetekaya0@gmail.com>
---
io_uring/rsrc.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/io_uring/rsrc.c b/io_uring/rsrc.c
index 51b46e624..3d29a0c7b 100644
--- a/io_uring/rsrc.c
+++ b/io_uring/rsrc.c
@@ -1614,8 +1614,13 @@ static int io_vec_fill_kern_bvec(int ddir, struct iov_iter *iter,
struct bio_vec bv;
bvec_iter_advance(src_bvec, &bi, offset);
- for_each_mp_bvec(bv, src_bvec, bi, bi)
+ while (bi.bi_size) {
+ if (bi.bi_idx >= imu->nr_bvecs)
+ return -EFAULT;
+ bv = mp_bvec_iter_bvec(src_bvec, bi);
res_bvec[res_idx++] = bv;
+ bvec_iter_advance_single(src_bvec, &bi, bv.bv_len);
+ }
total_len += iov_len;
}
iov_iter_bvec(iter, ddir, res_bvec, res_idx, total_len);
--
2.55.0
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH] io_uring: fix out-of-bounds bvec access in io_vec_fill_kern_bvec
2026-10-01 14:23 [PATCH] io_uring: fix out-of-bounds bvec access in io_vec_fill_kern_bvec Ömer Mete Kaya
@ 2026-10-01 15:36 ` Gabriel Krisman Bertazi
2026-10-01 19:55 ` Ömer Mete Kaya
0 siblings, 1 reply; 4+ messages in thread
From: Gabriel Krisman Bertazi @ 2026-10-01 15:36 UTC (permalink / raw)
To: Ömer Mete Kaya, axboe; +Cc: io-uring, linux-kernel, Ömer Mete Kaya
Ömer Mete Kaya <omermetekaya0@gmail.com> writes:
> for_each_mp_bvec() dereferences src_bvec[bi_idx] in the loop condition
> before the body is entered, with no guard against bi_idx reaching
> imu->nr_bvecs. iov_kern_bvec_size() stops iterating when i reaches
> imu->nr_bvecs even if bi_size is still non-zero, so the fill loop can
> walk past the end of the bvec array and overrun res_bvec[].
>
> Open-code the loop with an explicit bi_idx < imu->nr_bvecs check before
> the dereference, matching the termination condition in
> iov_kern_bvec_size().
Do you have a reproducer? This should be checked in iov_kern_bvec_size.
We make sure it doesn't go through imu->len which should match bv_len,
IIUC.
>
> Fixes: 1045afae4b88 ("io_uring: support vectored kernel fixed buffer")
> Signed-off-by: Ömer Mete Kaya <omermetekaya0@gmail.com>
> ---
> io_uring/rsrc.c | 7 ++++++-
> 1 file changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/io_uring/rsrc.c b/io_uring/rsrc.c
> index 51b46e624..3d29a0c7b 100644
> --- a/io_uring/rsrc.c
> +++ b/io_uring/rsrc.c
> @@ -1614,8 +1614,13 @@ static int io_vec_fill_kern_bvec(int ddir, struct iov_iter *iter,
> struct bio_vec bv;
>
> bvec_iter_advance(src_bvec, &bi, offset);
> - for_each_mp_bvec(bv, src_bvec, bi, bi)
> + while (bi.bi_size) {
bi.bi_size is the first condition of for_each_mp_bvec. Do you really
need an open coded loop? If there is an issue, can we just add the
check below?
> + if (bi.bi_idx >= imu->nr_bvecs)
> + return -EFAULT;
> + bv = mp_bvec_iter_bvec(src_bvec, bi);
> res_bvec[res_idx++] = bv;
> + bvec_iter_advance_single(src_bvec, &bi, bv.bv_len);
> + }
> total_len += iov_len;
> }
> iov_iter_bvec(iter, ddir, res_bvec, res_idx, total_len);
> --
> 2.55.0
>
--
Gabriel Krisman Bertazi
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH] io_uring: fix out-of-bounds bvec access in io_vec_fill_kern_bvec
2026-10-01 15:36 ` Gabriel Krisman Bertazi
@ 2026-10-01 19:55 ` Ömer Mete Kaya
2026-10-02 6:04 ` Ming Lei
0 siblings, 1 reply; 4+ messages in thread
From: Ömer Mete Kaya @ 2026-10-01 19:55 UTC (permalink / raw)
To: Gabriel Krisman Bertazi, axboe; +Cc: io-uring, linux-kernel
On 10/1/26 18:36, Gabriel Krisman Bertazi wrote:
> Ömer Mete Kaya <omermetekaya0@gmail.com> writes:
>
>> for_each_mp_bvec() dereferences src_bvec[bi_idx] in the loop condition
>> before the body is entered, with no guard against bi_idx reaching
>> imu->nr_bvecs. iov_kern_bvec_size() stops iterating when i reaches
>> imu->nr_bvecs even if bi_size is still non-zero, so the fill loop can
>> walk past the end of the bvec array and overrun res_bvec[].
>>
>> Open-code the loop with an explicit bi_idx < imu->nr_bvecs check before
>> the dereference, matching the termination condition in
>> iov_kern_bvec_size().
>
> Do you have a reproducer? This should be checked in iov_kern_bvec_size.
> We make sure it doesn't go through imu->len which should match bv_len,
> IIUC.
Yes I checked more and looks like the *bug* is unreachable via existing
in-tree callers.>>
>> Fixes: 1045afae4b88 ("io_uring: support vectored kernel fixed buffer")
It doesnt fix something broken actually, more like a defensive refactoring.
>> Signed-off-by: Ömer Mete Kaya <omermetekaya0@gmail.com>
>> ---
>> io_uring/rsrc.c | 7 ++++++-
>> 1 file changed, 6 insertions(+), 1 deletion(-)
>>
>> diff --git a/io_uring/rsrc.c b/io_uring/rsrc.c
>> index 51b46e624..3d29a0c7b 100644
>> --- a/io_uring/rsrc.c
>> +++ b/io_uring/rsrc.c
>> @@ -1614,8 +1614,13 @@ static int io_vec_fill_kern_bvec(int ddir, struct iov_iter *iter,
>> struct bio_vec bv;
>>
>> bvec_iter_advance(src_bvec, &bi, offset);
>> - for_each_mp_bvec(bv, src_bvec, bi, bi)
>> + while (bi.bi_size) {
>
> bi.bi_size is the first condition of for_each_mp_bvec. Do you really
> need an open coded loop? If there is an issue, can we just add the
> check below?
mp_bvec_iter_bvec() is called in the for-loop condition not the body:
for (iter = (start);
(iter).bi_size &&
((bvl = mp_bvec_iter_bvec((bio_vec), (iter))), 1); <-***
bvec_iter_advance_single(...))
src_bvec[bi_idx] is dereferenced before the loop body is entered.
A check inside the body executes after the out-of-bounds read has
already occurred. The open-coded loop is the way to check bi_idx
before the dereference. The question is "should the kernel be defensive
itself or trust the callers?". If you find these kinds of defensive
controls unnecessary, happy to withdraw the patch instead of releasing v2.
kind regards,
Ömer
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH] io_uring: fix out-of-bounds bvec access in io_vec_fill_kern_bvec
2026-10-01 19:55 ` Ömer Mete Kaya
@ 2026-10-02 6:04 ` Ming Lei
0 siblings, 0 replies; 4+ messages in thread
From: Ming Lei @ 2026-10-02 6:04 UTC (permalink / raw)
To: Ömer Mete Kaya
Cc: Gabriel Krisman Bertazi, axboe, io-uring, linux-kernel
On Thu, Oct 1, 2026 at 2:55 PM Ömer Mete Kaya <omermetekaya0@gmail.com> wrote:
>
>
>
> On 10/1/26 18:36, Gabriel Krisman Bertazi wrote:
> > Ömer Mete Kaya <omermetekaya0@gmail.com> writes:
> >
> >> for_each_mp_bvec() dereferences src_bvec[bi_idx] in the loop condition
> >> before the body is entered, with no guard against bi_idx reaching
> >> imu->nr_bvecs. iov_kern_bvec_size() stops iterating when i reaches
> >> imu->nr_bvecs even if bi_size is still non-zero, so the fill loop can
> >> walk past the end of the bvec array and overrun res_bvec[].
> >>
> >> Open-code the loop with an explicit bi_idx < imu->nr_bvecs check before
> >> the dereference, matching the termination condition in
> >> iov_kern_bvec_size().
> >
> > Do you have a reproducer? This should be checked in iov_kern_bvec_size.
> > We make sure it doesn't go through imu->len which should match bv_len,
> > IIUC.
>
> Yes I checked more and looks like the *bug* is unreachable via existing
> in-tree callers.>>
> >> Fixes: 1045afae4b88 ("io_uring: support vectored kernel fixed buffer")
>
> It doesnt fix something broken actually, more like a defensive refactoring.
>
> >> Signed-off-by: Ömer Mete Kaya <omermetekaya0@gmail.com>
> >> ---
> >> io_uring/rsrc.c | 7 ++++++-
> >> 1 file changed, 6 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/io_uring/rsrc.c b/io_uring/rsrc.c
> >> index 51b46e624..3d29a0c7b 100644
> >> --- a/io_uring/rsrc.c
> >> +++ b/io_uring/rsrc.c
> >> @@ -1614,8 +1614,13 @@ static int io_vec_fill_kern_bvec(int ddir, struct iov_iter *iter,
> >> struct bio_vec bv;
> >>
> >> bvec_iter_advance(src_bvec, &bi, offset);
> >> - for_each_mp_bvec(bv, src_bvec, bi, bi)
> >> + while (bi.bi_size) {
> >
> > bi.bi_size is the first condition of for_each_mp_bvec. Do you really
> > need an open coded loop? If there is an issue, can we just add the
> > check below?
>
> mp_bvec_iter_bvec() is called in the for-loop condition not the body:
>
> for (iter = (start);
> (iter).bi_size &&
> ((bvl = mp_bvec_iter_bvec((bio_vec), (iter))), 1); <-***
> bvec_iter_advance_single(...))
>
> src_bvec[bi_idx] is dereferenced before the loop body is entered.
> A check inside the body executes after the out-of-bounds read has
> already occurred. The open-coded loop is the way to check bi_idx
> before the dereference. The question is "should the kernel be defensive
> itself or trust the callers?". If you find these kinds of defensive
> controls unnecessary, happy to withdraw the patch instead of releasing v2.
bio/bvec iterator is written in this way from begining.
So it looks you should work on improving the iterator helper, instead of open
code for the single user only.
Thanks,
Ming Lei
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-10-02 6:04 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-01 14:23 [PATCH] io_uring: fix out-of-bounds bvec access in io_vec_fill_kern_bvec Ömer Mete Kaya
2026-10-01 15:36 ` Gabriel Krisman Bertazi
2026-10-01 19:55 ` Ömer Mete Kaya
2026-10-02 6:04 ` Ming Lei
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox