rust: Return Option from page_align and ensure no usize overflow

Change `page_align()` to return `Option<usize>` to allow validation
of the provided `addr` value. This ensures that any value that is
within one `PAGE_SIZE` of `usize::MAX` will not panic, and instead
returns `None` to indicate overflow.

Signed-off-by: Brendan Shephard <bshephar@bne-home.net>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
Link: https://patch.msgid.link/20251223055647.9761-1-bshephar@bne-home.net
[ Use kernel vertical style for imports; use markdown in comments.
  - Danilo ]
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
This commit is contained in:
Brendan Shephard
2025-12-23 15:56:47 +10:00
committed by Danilo Krummrich
parent 51293e589b
commit f91ffed95c

View File

@@ -25,14 +25,36 @@
/// A bitmask that gives the page containing a given address.
pub const PAGE_MASK: usize = !(PAGE_SIZE - 1);
/// Round up the given number to the next multiple of [`PAGE_SIZE`].
/// Rounds up to the next multiple of [`PAGE_SIZE`].
///
/// It is incorrect to pass an address where the next multiple of [`PAGE_SIZE`] doesn't fit in a
/// [`usize`].
pub const fn page_align(addr: usize) -> usize {
// Parentheses around `PAGE_SIZE - 1` to avoid triggering overflow sanitizers in the wrong
// cases.
(addr + (PAGE_SIZE - 1)) & PAGE_MASK
/// Returns [`None`] on integer overflow.
///
/// # Examples
///
/// ```
/// use kernel::page::{
/// page_align,
/// PAGE_SIZE,
/// };
///
/// // Requested address is already aligned.
/// assert_eq!(page_align(0x0), Some(0x0));
/// assert_eq!(page_align(PAGE_SIZE), Some(PAGE_SIZE));
///
/// // Requested address needs alignment up.
/// assert_eq!(page_align(0x1), Some(PAGE_SIZE));
/// assert_eq!(page_align(PAGE_SIZE + 1), Some(2 * PAGE_SIZE));
///
/// // Requested address causes overflow (returns `None`).
/// let overflow_addr = usize::MAX - (PAGE_SIZE / 2);
/// assert_eq!(page_align(overflow_addr), None);
/// ```
#[inline(always)]
pub const fn page_align(addr: usize) -> Option<usize> {
let Some(sum) = addr.checked_add(PAGE_SIZE - 1) else {
return None;
};
Some(sum & PAGE_MASK)
}
/// Representation of a non-owning reference to a [`Page`].