All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Eliot Courtney" <ecourtney@nvidia.com>
To: "Alexandre Courbot" <acourbot@nvidia.com>,
	"Eliot Courtney" <ecourtney@nvidia.com>
Cc: "Alice Ryhl" <aliceryhl@google.com>,
	"Burak Emir" <burak.emir@gmail.com>,
	"Yury Norov" <yury.norov@gmail.com>,
	"Miguel Ojeda" <ojeda@kernel.org>,
	"Boqun Feng" <boqun@kernel.org>, "Gary Guo" <gary@garyguo.net>,
	"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
	"Benno Lossin" <lossin@kernel.org>,
	"Andreas Hindborg" <a.hindborg@kernel.org>,
	"Trevor Gross" <tmgross@umich.edu>,
	"Danilo Krummrich" <dakr@kernel.org>,
	"Daniel Almeida" <daniel.almeida@collabora.com>,
	"Tamir Duberstein" <tamird@kernel.org>,
	"Onur Özkan" <work@onurozkan.dev>,
	"David Airlie" <airlied@gmail.com>,
	"Simona Vetter" <simona@ffwll.ch>,
	"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
	"John Hubbard" <jhubbard@nvidia.com>,
	"Alistair Popple" <apopple@nvidia.com>,
	"Timur Tabi" <ttabi@nvidia.com>, "Zhi Wang" <zhiw@nvidia.com>,
	rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org,
	nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org,
	dri-devel <dri-devel-bounces@lists.freedesktop.org>
Subject: Re: [PATCH v7 05/10] rust: bitmap: add contiguous area operations
Date: Tue, 25 Aug 2026 17:33:41 +0900	[thread overview]
Message-ID: <DKXVWSQ8Q627.31HTY1KERFBR8@nvidia.com> (raw)
In-Reply-To: <DKUGXCFA0Q77.36Q64A1AN6FX5@nvidia.com>

On Fri Aug 21, 2026 at 5:11 PM JST, Alexandre Courbot wrote:
> On Mon Aug 17, 2026 at 4:04 PM JST, Eliot Courtney wrote:
>> Add bindings for area operations on bitmaps. Each one is
>> made safe by adding some extra checks compared to the underlying C code
>> (for example, checking bounds) and with additional checks to catch
>> likely erroneous usage if `CONFIG_RUST_BITMAP_HARDENED` is on.
>>
>> Add tests demonstrating the edge cases.
>>
>> Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
>> ---
>>  rust/kernel/bitmap.rs | 242 +++++++++++++++++++++++++++++++++++++++++++++++++-
>>  1 file changed, 240 insertions(+), 2 deletions(-)
>>
>> diff --git a/rust/kernel/bitmap.rs b/rust/kernel/bitmap.rs
>> index fdcfc0409773..a4997022ff0f 100644
>> --- a/rust/kernel/bitmap.rs
>> +++ b/rust/kernel/bitmap.rs
>> @@ -10,7 +10,11 @@
>>  use crate::bindings;
>>  #[cfg(not(CONFIG_RUST_BITMAP_HARDENED))]
>>  use crate::pr_err;
>> -use core::ptr::NonNull;
>> +use crate::ptr::Alignment;
>> +use core::{
>> +    num::NonZero,
>> +    ptr::NonNull, //
>> +};
>>  
>>  /// Represents a C bitmap. Wraps underlying C bitmap API.
>>  ///
>> @@ -523,13 +527,160 @@ pub fn next_zero_bit(&self, start: usize) -> Option<usize> {
>>              Some(index)
>>          }
>>      }
>> +
>> +    /// Finds a contiguous area of `nbits` zero bits at or after `start`, where the area plus
>> +    /// `align_offset` is aligned to `align`.
>> +    ///
>> +    /// Returns the bit index of the start of the area, or [`None`] if no such area fitting in
>> +    /// the bitmap exists.
>> +    ///
>> +    /// The returned index plus `align_offset` is a multiple of `align`.
>> +    ///
>> +    /// # Panics
>> +    ///
>> +    /// Panics if CONFIG_RUST_BITMAP_HARDENED is enabled and `start` is out of bounds.
>> +    #[inline]
>> +    pub fn next_zero_area_off(
>> +        &self,
>> +        start: usize,
>> +        nbits: NonZero<usize>,
>> +        align: Alignment,
>> +        align_offset: usize,
>> +    ) -> Option<usize> {
>> +        bitmap_assert!(
>> +            start < self.len(),
>> +            "`start` must be < {}, was {}",
>> +            self.len(),
>> +            start
>> +        );
>
> Do we need to potentially panic here if `start >= self.len()`? The
> question "is there an area of `nbits` bits after my bounds" can be
> answered by "there is `None`" without semantically sounding weird; and
> this test doesn't cover `start + nbits >= self.len()`, which should
> logically also be considered to be consistent. It seems like the C API
> also tolerates this, so as this is not a safety issue I guess the Rust
> one should do the same?
>
> If anything I'd say we should remove these tests from
> `next_bit`/`next_zero_bit` as well.
>
> Mutating methods should definitely keep that check, but for querying
> this looks like a legitimate way to use the API.

Yeah, I am following the convention of this file - e.g. `next_zero_bit`
has this same check as you have noted, presumably because these bindings
want to consider calling with start >= self.len() to be not intended
behaviour that's worth warning on? I personally don't mind, but I think
we should either have it on all of them or on none of them. For now, I
have kept them in to match the file convention but we could remove them
or convert to debug_assert! in a follow-up?

>
>> +
>> +        let nr = u32::try_from(nbits.get()).ok()?;
>> +        let align_mask = align.as_usize() - 1;
>> +
>> +        // The C alignment and end arithmetic must not overflow, or it can read out of bounds.
>> +        // Overflow is only possible on 32-bit.
>> +        #[cfg(not(CONFIG_64BIT))]
>> +        align_mask
>> +            .checked_add(self.len())?
>> +            .checked_add(nbits.get())?;
>
> Is it ok to not consider `align_offset` here? The C code adds it, and
> the result could overflow on large values, even on 64-bit.

It is ok not to consider it but the reason is very subtle. The tldr is
that align_offset only affects the important value by at most
`align_mask`.

Here is the latest `bitmap_find_next_zero_area_off` code on
bitmap-for-next:
```
unsigned long bitmap_find_next_zero_area_off(unsigned long *map,
					     unsigned long size,
					     unsigned long start,
					     unsigned int nr,
					     unsigned long align_mask,
					     unsigned long align_offset)
{
	unsigned long end, i, off;

	for_each_clear_bit_from(start, map, size) {
		start = __ALIGN_MASK(start + align_offset, align_mask) - align_offset;
		end = start + nr;
		if (end > size)
			break;

		off = round_down(start, BITS_PER_LONG);
		i = find_last_bit(map + start / BITS_PER_LONG, end - off) + off;
		if (i >= end || i < start)
			return start;

		start = i;
	}

	return size;
}
```

It has
```
start = __ALIGN_MASK(start + align_offset, align_mask) - align_offset;
```

__ALIGN_MASK does this:
```
(((x) + (mask)) & ~(mask))
```

So it's

```
((start + align_offset + align_mask) & ~align_mask) - align_offset
```

A & ~B where B is (2**k - 1) == A - A % 2**k, so we have

```
start + align_offset + align_mask - (start + align_offset + align_mask)%2**k - align_offset
```

So you can cancel the two align_offsets and get

```
start + align_mask - (start + align_offset + align_mask)%2**k
```

Since (start + align_offset + align_mask)%2**k <= align_mask, the only
way you can overflow your expression is through align_mask, not
align_offset. The upper bound of the expression is start' <= `start +
align_mask`.

We get the overflow/OOB read path if end overflows so `if (end > size)`
becomes wrong. `for_each_clear_bit_from` guarantees that start < size in
the body of the loop. So when we compute `end = start' + nr`, the upper
bound is `start + align_mask + nr` - that's the check here. We know
start < i32::MAX (thanks to the invariants we added) and align_mask <=
isize::MAX, and nr <= u32::MAX. So the total upper bound is `i32::MAX +
isize::MAX + u32::MAX`. This fits into `unsigned long` on 64 bit but not
on 32 bit, hence the cfg to only 32-bit.


  parent reply	other threads:[~2026-08-25  8:33 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-17  7:04 [PATCH v7 00/10] rust: Add support for reserving of ranges of IDs Eliot Courtney
2026-08-17  7:04 ` [PATCH v7 01/10] rust: bitmap: use function-level cfg on kunit test Eliot Courtney
2026-08-17 10:29   ` Gary Guo
2026-08-17 19:42     ` Burak Emir
2026-08-17  7:04 ` [PATCH v7 02/10] rust: bitmap: restrict bitmap length to at most i32::MAX Eliot Courtney
2026-08-17 19:51   ` Burak Emir
2026-08-21  7:37   ` Alexandre Courbot
2026-08-24 12:04     ` Eliot Courtney
2026-08-17  7:04 ` [PATCH v7 03/10] rust: num: add nz! macro for compile time NonZero values Eliot Courtney
2026-08-19 20:07   ` Gary Guo
2026-08-25 11:10     ` Eliot Courtney
2026-08-21  7:39   ` Alexandre Courbot
2026-08-17  7:04 ` [PATCH v7 04/10] rust: sizes: implement SizeConstants for Alignment Eliot Courtney
2026-08-17  7:12   ` sashiko-bot
2026-08-21  7:46   ` Alexandre Courbot
2026-08-25  6:59     ` Eliot Courtney
2026-08-17  7:04 ` [PATCH v7 05/10] rust: bitmap: add contiguous area operations Eliot Courtney
2026-08-17 20:12   ` Burak Emir
2026-08-21  8:11   ` Alexandre Courbot
2026-08-21  8:31     ` Miguel Ojeda
2026-08-21 11:04       ` Alexandre Courbot
2026-08-21 19:35         ` Miguel Ojeda
2026-08-25  8:33     ` Eliot Courtney [this message]
2026-08-17  7:04 ` [PATCH v7 06/10] rust: id_pool: take a NonZero capacity in with_capacity Eliot Courtney
2026-08-17  7:12   ` sashiko-bot
2026-08-17 20:13   ` Burak Emir
2026-08-21  8:39   ` Alexandre Courbot
2026-08-25 11:09     ` Eliot Courtney
2026-08-25 13:12       ` Alice Ryhl
2026-08-25 23:43         ` Eliot Courtney
2026-08-25 12:10   ` Alice Ryhl
2026-08-17  7:04 ` [PATCH v7 07/10] rust: id_pool: add contiguous ID reservation Eliot Courtney
2026-08-17  7:14   ` sashiko-bot
2026-08-17 20:21   ` Burak Emir
2026-08-21  8:30   ` Alexandre Courbot
2026-08-17  7:04 ` [PATCH v7 08/10] rust: id_pool: do not round capacity up to BitmapVec::MAX_INLINE_LEN Eliot Courtney
2026-08-17 20:39   ` Burak Emir
2026-08-17  7:04 ` [PATCH v7 09/10] gpu: nova-core: add ChannelIdPool Eliot Courtney
2026-08-17  7:04 ` [PATCH v7 10/10] rust: use Alignment size constants Eliot Courtney
2026-08-21 11:04   ` Alexandre Courbot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=DKXVWSQ8Q627.31HTY1KERFBR8@nvidia.com \
    --to=ecourtney@nvidia.com \
    --cc=a.hindborg@kernel.org \
    --cc=acourbot@nvidia.com \
    --cc=airlied@gmail.com \
    --cc=aliceryhl@google.com \
    --cc=apopple@nvidia.com \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun@kernel.org \
    --cc=burak.emir@gmail.com \
    --cc=dakr@kernel.org \
    --cc=daniel.almeida@collabora.com \
    --cc=dri-devel-bounces@lists.freedesktop.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=gary@garyguo.net \
    --cc=gregkh@linuxfoundation.org \
    --cc=jhubbard@nvidia.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lossin@kernel.org \
    --cc=nova-gpu@lists.linux.dev \
    --cc=ojeda@kernel.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=simona@ffwll.ch \
    --cc=tamird@kernel.org \
    --cc=tmgross@umich.edu \
    --cc=ttabi@nvidia.com \
    --cc=work@onurozkan.dev \
    --cc=yury.norov@gmail.com \
    --cc=zhiw@nvidia.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.