From: "Benno Lossin" <lossin@kernel.org>
To: "Boqun Feng" <boqun.feng@gmail.com>,
"Viresh Kumar" <viresh.kumar@linaro.org>
Cc: "Rafael J. Wysocki" <rafael@kernel.org>,
"Yury Norov" <yury.norov@gmail.com>,
"Miguel Ojeda" <ojeda@kernel.org>,
"Alex Gaynor" <alex.gaynor@gmail.com>,
"Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
"Danilo Krummrich" <dakr@kernel.org>,
"Vincent Guittot" <vincent.guittot@linaro.org>,
linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org,
rust-for-linux@vger.kernel.org
Subject: Re: [PATCH] rust: cpumask: Validate CPU number in set() and clear()
Date: Fri, 06 Jun 2025 10:11:13 +0200 [thread overview]
Message-ID: <DAFAR5SUQSU9.OSLB2UAXE9DY@kernel.org> (raw)
In-Reply-To: <aEJwm16HSwCyt7aB@Mac.home>
On Fri Jun 6, 2025 at 6:37 AM CEST, Boqun Feng wrote:
> On Fri, Jun 06, 2025 at 09:47:28AM +0530, Viresh Kumar wrote:
>> The C `cpumask_{set|clear}_cpu()` APIs emit a warning when given an
>> invalid CPU number - but only if `CONFIG_DEBUG_PER_CPU_MAPS=y` is set.
>>
>> Meanwhile, `cpumask_weight()` only considers CPUs up to `nr_cpu_ids`,
>> which can cause inconsistencies: a CPU number greater than `nr_cpu_ids`
>> may be set in the mask, yet the weight calculation won't reflect it.
>>
>> This leads to doctest failures when `nr_cpu_ids < 4`, as the test tries
>> to set CPUs 2 and 3:
>>
>> rust_doctest_kernel_cpumask_rs_0.location: rust/kernel/cpumask.rs:180
>> rust_doctest_kernel_cpumask_rs_0: ASSERTION FAILED at rust/kernel/cpumask.rs:190
>>
>> Fix this by validating the CPU number in the Rust `set()` and `clear()`
>> methods to prevent out-of-bounds modifications.
>>
>
> Thanks for the quick fix!
>
> While this can fix the current problem, but it's not a good solution for
> the long run. Because outside a test, we should never use an arbitrary
> i32 as a cpu number (we usually get it from smp_processor_id(), or
> something else). So the `< nr_cpu_ids` testing is not necessary in
> normal use cases.
>
> We should instead provide a wrapper for cpu id:
>
> /// # Invariants
> ///
> /// The number is always in [0..nr_cpu_ids) range.
> pub struct CpuId(i32);
>
> and
>
> impl CpuId {
> /// # Safety
> /// Callers must ensure `i` is a valid cpu id (i.e. 0 <= i <
> /// nr_cpu_ids).
> pub unsafe fn from_i32_unchecked(i: i32) -> Self {
> // INVARIANT: The function safety guarantees `i` is a valid
> // cpu id.
> CpuId(id);
> }
>
> pub fn from_i32(i: i32) -> Option<Self> {
> if i < 0 || i >= nr_cpu_ids {
> None
> } else {
> // SAFETY: `i` has just been checked as a valid cpu id.
> Some(unsafe { Self::from_i32_unchecked(i) })
> }
> }
>
> pub fn current() -> Self {
> // SAFETY: smp_processor_id() always return valid cpu id.
> unsafe { Self::from_i32_unchecked(smp_processor_id()) }
> }
> }
>
> All `Cpumask` functions then take `CpuId` instead of `i32` as the
> parameter. Needless to say if we were to have a cpumask_next() wrapper,
> the return value will be `CpuId` (or `Option<CpuId>`), i.e. if a bit was
> set in a cpumask, then it must represent a correct cpu id.
>
> Make sense?
Just to make sure, the `nr_cpu_ids` stays constant, right?
>> @@ -101,10 +108,16 @@ pub fn set(&mut self, cpu: u32) {
>> /// This mismatches kernel naming convention and corresponds to the C
>> /// function `__cpumask_clear_cpu()`.
>> #[inline]
>> - pub fn clear(&mut self, cpu: i32) {
>> + pub fn clear(&mut self, cpu: i32) -> Result {
>> + // SAFETY: It is safe to read `nr_cpu_ids`.
>> + if unsafe { cpu as u32 >= bindings::nr_cpu_ids } {
>
> You probably want to check whether `bindings::nr_cpu_ids` can be
> accessible if NR_CPUS == 1 or CONFIG_FORCE_NR_CPUS=y, because then
> nr_cpu_ids is a macro definition.
Just define a helper function?
---
Cheers,
Benno
next prev parent reply other threads:[~2025-06-06 8:11 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-06-06 4:17 [PATCH] rust: cpumask: Validate CPU number in set() and clear() Viresh Kumar
2025-06-06 4:37 ` Boqun Feng
2025-06-06 8:11 ` Benno Lossin [this message]
2025-06-06 13:34 ` Boqun Feng
2025-06-06 19:34 ` Benno Lossin
2025-06-06 19:40 ` Boqun Feng
2025-06-09 11:17 ` Viresh Kumar
2025-06-06 10:11 ` Miguel Ojeda
2025-06-09 2:36 ` Viresh Kumar
2025-06-06 23:23 ` kernel test robot
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=DAFAR5SUQSU9.OSLB2UAXE9DY@kernel.org \
--to=lossin@kernel.org \
--cc=a.hindborg@kernel.org \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=dakr@kernel.org \
--cc=gary@garyguo.net \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=ojeda@kernel.org \
--cc=rafael@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=tmgross@umich.edu \
--cc=vincent.guittot@linaro.org \
--cc=viresh.kumar@linaro.org \
--cc=yury.norov@gmail.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).