* [PATCH v2] rust: allow Clang-native `RANDSTRUCT` configs
@ 2026-03-23 13:02 Miguel Ojeda
2026-03-23 13:46 ` Gary Guo
2026-03-26 3:18 ` kernel test robot
0 siblings, 2 replies; 4+ messages in thread
From: Miguel Ojeda @ 2026-03-23 13:02 UTC (permalink / raw)
To: Miguel Ojeda, Greg Kroah-Hartman, Arve Hjønnevåg,
Todd Kjos, Christian Brauner, Carlos Llamas, Alice Ryhl,
Nathan Chancellor, Nicolas Schier
Cc: Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Trevor Gross, Danilo Krummrich, rust-for-linux,
linux-kernel, Nick Desaulniers, Bill Wendling, Justin Stitt, llvm,
linux-kbuild, Aaron Ballman, Bill Wendling, Cole Nixon,
Connor Kuehl, Fangrui Song, James Foster, Jeff Takahashi,
Jordan Cantrell, Matthew Maurer, Nikk Forbus, Qing Zhao,
Sami Tolvanen, Tim Pugh, Kees Cook
The kernel supports `RANDSTRUCT_FULL` with Clang 16+, and `bindgen`
(which uses `libclang` under the hood) inherits the information, so the
generated bindings look correct.
For instance, running:
bindgen x.h -- -frandomize-layout-seed=100
with:
struct S1 {
int a;
int b;
};
struct S2 {
int a;
int b;
} __attribute__((randomize_layout));
struct S3 {
void (*a)(void);
void (*b)(void);
};
struct S4 {
void (*a)(void);
void (*b)(void);
} __attribute__((no_randomize_layout));
may swap `S2`'s and `S3`'s members, but not `S1`'s nor `S4`'s:
pub struct S1 {
pub a: ::std::os::raw::c_int,
pub b: ::std::os::raw::c_int,
}
pub struct S2 {
pub b: ::std::os::raw::c_int,
pub a: ::std::os::raw::c_int,
}
pub struct S3 {
pub b: ::std::option::Option<unsafe extern "C" fn()>,
pub a: ::std::option::Option<unsafe extern "C" fn()>,
}
pub struct S4 {
pub a: ::std::option::Option<unsafe extern "C" fn()>,
pub b: ::std::option::Option<unsafe extern "C" fn()>,
}
Thus allow those configurations by requiring a Clang compiler to use
`RANDSTRUCT`. In addition, remove the `!GCC_PLUGIN_RANDSTRUCT` check
since it is not needed.
A simpler alternative would be to remove the `!RANDSTRUCT` check (keeping
the `!GCC_PLUGIN_RANDSTRUCT` one). However, if in the future GCC starts
supporting `RANDSTRUCT` natively, it would be likely that it would not
work unless GCC and Clang agree on the exact semantics of the flag. And,
as far as I can see, so far the randomization in Clang does not seem to be
guaranteed to remain stable across versions or platforms, i.e. only for a
given compiler Clang binary, given it is not documented and that LLVM's
`HEAD` has the revert in place for the expected field names in the test
(LLVM commit 8dbc6b560055 ("Revert "[randstruct] Check final randomized
layout ordering"")) [1][2]. And the GCC plugin definitely does not match,
e.g. its RNG is different (`std::mt19937` vs Bob Jenkins').
And given it is not supposed to be guaranteed to remain stable across
versions, it is a good idea to match the Clang and `bindgen`'s
`libclang` versions -- we already have a warning for that in
`scripts/rust_is_available.sh`. In the future, it would also be good to
have a build test to double-check layouts do actually match (but that
is true regardless of this particular feature).
Finally, make a few required small changes to take into account the
anonymous struct used in `randomized_struct_fields_*` in `struct
task_struct`.
[ Andreas writes:
Tested with the rust null block driver patch series [1]. I did a
few functional verification tests and a set of performance tests.
For the rnull driver, enabling randstruct with this patch gives no
statistically significant change to the average performance of the set
of 120 workloads that we publish on [2]. Individual configurations see
around 10% change in throughput, both directions.
Link: https://lore.kernel.org/rust-for-linux/20260216-rnull-v6-19-rc5-send-v1-0-de9a7af4b469@kernel.org/ [1]
Link: https://rust-for-linux.com/null-block-driver [2]
- Miguel ]
Cc: Aaron Ballman <aaron@aaronballman.com>
Cc: Bill Wendling <isanbard@gmail.com>
Cc: Cole Nixon <nixontcole@gmail.com>
Cc: Connor Kuehl <cipkuehl@gmail.com>
Cc: Fangrui Song <i@maskray.me>
Cc: James Foster <jafosterja@gmail.com>
Cc: Jeff Takahashi <jeffrey.takahashi@gmail.com>
Cc: Jordan Cantrell <jordan.cantrell@mail.com>
Cc: Justin Stitt <justinstitt@google.com>
Cc: Matthew Maurer <mmaurer@google.com>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nicolas Schier <nsc@kernel.org>
Cc: Nikk Forbus <nicholas.forbus@gmail.com>
Cc: Qing Zhao <qing.zhao@oracle.com>
Cc: Sami Tolvanen <samitolvanen@google.com>
Cc: Tim Pugh <nwtpugh@gmail.com>
Link: https://reviews.llvm.org/D121556
Link: https://github.com/llvm/llvm-project/commit/8dbc6b560055ff5068ff45b550482ba62c36b5a5 [1]
Link: https://reviews.llvm.org/D124199 [2]
Reviewed-by: Kees Cook <kees@kernel.org>
Tested-by: Andreas Hindborg <a.hindborg@kernel.org>
Link: https://patch.msgid.link/20241119185747.862544-1-ojeda@kernel.org
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
Ok, here is a rebased one in case it helps. Nowadays we have a couple
more instances in Binder.
I ran all the KUnit tests (nowadays we have way more compared to the
days of v1) with a bunch of debug options and for a few architectures.
Also did a run of all released Rust versions with x86_64. It would still
be nice to get more actual testing like Andreas' did with his driver,
but we will probably only get that if we actually go ahead...
Kees: do you want to do the other change directly?
drivers/android/binder/deferred_close.rs | 29 ++++++++++++++++++---
init/Kconfig | 3 +--
rust/kernel/task.rs | 33 +++++++++++++++++++++---
3 files changed, 57 insertions(+), 8 deletions(-)
diff --git a/drivers/android/binder/deferred_close.rs b/drivers/android/binder/deferred_close.rs
index ac895c04d0cb..edda56b7c4c0 100644
--- a/drivers/android/binder/deferred_close.rs
+++ b/drivers/android/binder/deferred_close.rs
@@ -69,9 +69,20 @@ pub(crate) fn close_fd(self, fd: u32) -> Result<(), DeferredFdCloseError> {
// Task works are not available on kthreads.
let current = kernel::current!();
- // Check if this is a kthread.
// SAFETY: Reading `flags` from a task is always okay.
- if unsafe { ((*current.as_ptr()).flags & bindings::PF_KTHREAD) != 0 } {
+ let flags = unsafe {
+ #[cfg(not(CONFIG_RANDSTRUCT))]
+ {
+ (*current.as_ptr()).flags
+ }
+ #[cfg(CONFIG_RANDSTRUCT)]
+ {
+ (*current.as_ptr()).__bindgen_anon_1.flags
+ }
+ };
+
+ // Check if this is a kthread.
+ if (flags & bindings::PF_KTHREAD) != 0 {
return Err(DeferredFdCloseError::TaskWorkUnavailable);
}
@@ -135,6 +146,18 @@ pub(crate) fn close_fd(self, fd: u32) -> Result<(), DeferredFdCloseError> {
// SAFETY: The `file` pointer points at a file with a non-zero refcount.
unsafe { bindings::get_file(file) };
+ // SAFETY: Reading `files` from a task is always okay.
+ let files = unsafe {
+ #[cfg(not(CONFIG_RANDSTRUCT))]
+ {
+ (*current).files
+ }
+ #[cfg(CONFIG_RANDSTRUCT)]
+ {
+ (*current).__bindgen_anon_1.files
+ }
+ };
+
// This method closes the fd, consuming one of our two refcounts. There could be active
// light refcounts created from that fd, so we must ensure that the file has a positive
// refcount for the duration of those active light refcounts. We do that by holding on to
@@ -145,7 +168,7 @@ pub(crate) fn close_fd(self, fd: u32) -> Result<(), DeferredFdCloseError> {
// `current->files`.
//
// Note: fl_owner_t is currently a void pointer.
- unsafe { bindings::filp_close(file, (*current).files as bindings::fl_owner_t) };
+ unsafe { bindings::filp_close(file, files as bindings::fl_owner_t) };
// We update the file pointer that the task work is supposed to fput. This transfers
// ownership of our last refcount.
diff --git a/init/Kconfig b/init/Kconfig
index 444ce811ea67..d3d0e8c95fb3 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -2173,8 +2173,7 @@ config RUST
depends on RUST_IS_AVAILABLE
select EXTENDED_MODVERSIONS if MODVERSIONS
depends on !MODVERSIONS || GENDWARFKSYMS
- depends on !GCC_PLUGIN_RANDSTRUCT
- depends on !RANDSTRUCT
+ depends on !RANDSTRUCT || CC_IS_CLANG
depends on !DEBUG_INFO_BTF || (PAHOLE_HAS_LANG_EXCLUDE && !LTO)
depends on !CFI || HAVE_CFI_ICALL_NORMALIZE_INTEGERS_RUSTC
select CFI_ICALL_NORMALIZE_INTEGERS if CFI
diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs
index 049c8a4d45d8..a533f5be2469 100644
--- a/rust/kernel/task.rs
+++ b/rust/kernel/task.rs
@@ -207,7 +207,16 @@ pub fn as_ptr(&self) -> *mut bindings::task_struct {
pub fn pid(&self) -> Pid {
// SAFETY: The pid of a task never changes after initialization, so reading this field is
// not a data race.
- unsafe { *ptr::addr_of!((*self.as_ptr()).pid) }
+ unsafe {
+ #[cfg(not(CONFIG_RANDSTRUCT))]
+ {
+ *ptr::addr_of!((*self.as_ptr()).pid)
+ }
+ #[cfg(CONFIG_RANDSTRUCT)]
+ {
+ *ptr::addr_of!((*self.as_ptr()).__bindgen_anon_1.pid)
+ }
+ }
}
/// Returns the UID of the given task.
@@ -278,7 +287,16 @@ impl CurrentTask {
pub fn mm(&self) -> Option<&MmWithUser> {
// SAFETY: The `mm` field of `current` is not modified from other threads, so reading it is
// not a data race.
- let mm = unsafe { (*self.as_ptr()).mm };
+ let mm = unsafe {
+ #[cfg(not(CONFIG_RANDSTRUCT))]
+ {
+ (*self.as_ptr()).mm
+ }
+ #[cfg(CONFIG_RANDSTRUCT)]
+ {
+ (*self.as_ptr()).__bindgen_anon_1.mm
+ }
+ };
if mm.is_null() {
return None;
@@ -337,7 +355,16 @@ pub fn active_pid_ns(&self) -> Option<&PidNamespace> {
pub fn group_leader(&self) -> &Task {
// SAFETY: The group leader of a task never changes while the task is running, and `self`
// is the current task, which is guaranteed running.
- let ptr = unsafe { (*self.as_ptr()).group_leader };
+ let ptr = unsafe {
+ #[cfg(not(CONFIG_RANDSTRUCT))]
+ {
+ (*self.as_ptr()).group_leader
+ }
+ #[cfg(CONFIG_RANDSTRUCT)]
+ {
+ (*self.as_ptr()).__bindgen_anon_1.group_leader
+ }
+ };
// SAFETY: `current->group_leader` stays valid for at least the duration in which `current`
// is running, and the signature of this function ensures that the returned `&Task` can
base-commit: bf074eb6891be799174ff42e0051492681fdc045
--
2.53.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v2] rust: allow Clang-native `RANDSTRUCT` configs
2026-03-23 13:02 [PATCH v2] rust: allow Clang-native `RANDSTRUCT` configs Miguel Ojeda
@ 2026-03-23 13:46 ` Gary Guo
2026-03-23 14:24 ` Miguel Ojeda
2026-03-26 3:18 ` kernel test robot
1 sibling, 1 reply; 4+ messages in thread
From: Gary Guo @ 2026-03-23 13:46 UTC (permalink / raw)
To: Miguel Ojeda, Greg Kroah-Hartman, Arve Hjønnevåg,
Todd Kjos, Christian Brauner, Carlos Llamas, Alice Ryhl,
Nathan Chancellor, Nicolas Schier
Cc: Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Trevor Gross, Danilo Krummrich, rust-for-linux,
linux-kernel, Nick Desaulniers, Bill Wendling, Justin Stitt, llvm,
linux-kbuild, Aaron Ballman, Bill Wendling, Cole Nixon,
Connor Kuehl, Fangrui Song, James Foster, Jeff Takahashi,
Jordan Cantrell, Matthew Maurer, Nikk Forbus, Qing Zhao,
Sami Tolvanen, Tim Pugh, Kees Cook
On Mon Mar 23, 2026 at 1:02 PM GMT, Miguel Ojeda wrote:
> The kernel supports `RANDSTRUCT_FULL` with Clang 16+, and `bindgen`
> (which uses `libclang` under the hood) inherits the information, so the
> generated bindings look correct.
>
> For instance, running:
>
> bindgen x.h -- -frandomize-layout-seed=100
>
> with:
>
> struct S1 {
> int a;
> int b;
> };
>
> struct S2 {
> int a;
> int b;
> } __attribute__((randomize_layout));
>
> struct S3 {
> void (*a)(void);
> void (*b)(void);
> };
>
> struct S4 {
> void (*a)(void);
> void (*b)(void);
> } __attribute__((no_randomize_layout));
>
> may swap `S2`'s and `S3`'s members, but not `S1`'s nor `S4`'s:
>
> pub struct S1 {
> pub a: ::std::os::raw::c_int,
> pub b: ::std::os::raw::c_int,
> }
>
> pub struct S2 {
> pub b: ::std::os::raw::c_int,
> pub a: ::std::os::raw::c_int,
> }
>
> pub struct S3 {
> pub b: ::std::option::Option<unsafe extern "C" fn()>,
> pub a: ::std::option::Option<unsafe extern "C" fn()>,
> }
>
> pub struct S4 {
> pub a: ::std::option::Option<unsafe extern "C" fn()>,
> pub b: ::std::option::Option<unsafe extern "C" fn()>,
> }
>
> Thus allow those configurations by requiring a Clang compiler to use
> `RANDSTRUCT`. In addition, remove the `!GCC_PLUGIN_RANDSTRUCT` check
> since it is not needed.
>
> A simpler alternative would be to remove the `!RANDSTRUCT` check (keeping
> the `!GCC_PLUGIN_RANDSTRUCT` one). However, if in the future GCC starts
> supporting `RANDSTRUCT` natively, it would be likely that it would not
> work unless GCC and Clang agree on the exact semantics of the flag. And,
> as far as I can see, so far the randomization in Clang does not seem to be
> guaranteed to remain stable across versions or platforms, i.e. only for a
> given compiler Clang binary, given it is not documented and that LLVM's
> `HEAD` has the revert in place for the expected field names in the test
> (LLVM commit 8dbc6b560055 ("Revert "[randstruct] Check final randomized
> layout ordering"")) [1][2]. And the GCC plugin definitely does not match,
> e.g. its RNG is different (`std::mt19937` vs Bob Jenkins').
>
> And given it is not supposed to be guaranteed to remain stable across
> versions, it is a good idea to match the Clang and `bindgen`'s
> `libclang` versions -- we already have a warning for that in
> `scripts/rust_is_available.sh`. In the future, it would also be good to
> have a build test to double-check layouts do actually match (but that
> is true regardless of this particular feature).
>
> Finally, make a few required small changes to take into account the
> anonymous struct used in `randomized_struct_fields_*` in `struct
> task_struct`.
Can we avoid cfgs by always wrap things inside anonymous struct?
The comment says "This anon struct can add padding, so only enable it under
randstruct.", I wonder how much bigger the task_struct will be if this becomes
unconditional wrapping.
Best,
Gary
>
> [ Andreas writes:
>
> Tested with the rust null block driver patch series [1]. I did a
> few functional verification tests and a set of performance tests.
>
> For the rnull driver, enabling randstruct with this patch gives no
> statistically significant change to the average performance of the set
> of 120 workloads that we publish on [2]. Individual configurations see
> around 10% change in throughput, both directions.
>
> Link: https://lore.kernel.org/rust-for-linux/20260216-rnull-v6-19-rc5-send-v1-0-de9a7af4b469@kernel.org/ [1]
> Link: https://rust-for-linux.com/null-block-driver [2]
>
> - Miguel ]
>
> Cc: Aaron Ballman <aaron@aaronballman.com>
> Cc: Bill Wendling <isanbard@gmail.com>
> Cc: Cole Nixon <nixontcole@gmail.com>
> Cc: Connor Kuehl <cipkuehl@gmail.com>
> Cc: Fangrui Song <i@maskray.me>
> Cc: James Foster <jafosterja@gmail.com>
> Cc: Jeff Takahashi <jeffrey.takahashi@gmail.com>
> Cc: Jordan Cantrell <jordan.cantrell@mail.com>
> Cc: Justin Stitt <justinstitt@google.com>
> Cc: Matthew Maurer <mmaurer@google.com>
> Cc: Nathan Chancellor <nathan@kernel.org>
> Cc: Nicolas Schier <nsc@kernel.org>
> Cc: Nikk Forbus <nicholas.forbus@gmail.com>
> Cc: Qing Zhao <qing.zhao@oracle.com>
> Cc: Sami Tolvanen <samitolvanen@google.com>
> Cc: Tim Pugh <nwtpugh@gmail.com>
> Link: https://reviews.llvm.org/D121556
> Link: https://github.com/llvm/llvm-project/commit/8dbc6b560055ff5068ff45b550482ba62c36b5a5 [1]
> Link: https://reviews.llvm.org/D124199 [2]
> Reviewed-by: Kees Cook <kees@kernel.org>
> Tested-by: Andreas Hindborg <a.hindborg@kernel.org>
> Link: https://patch.msgid.link/20241119185747.862544-1-ojeda@kernel.org
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
> ---
> Ok, here is a rebased one in case it helps. Nowadays we have a couple
> more instances in Binder.
>
> I ran all the KUnit tests (nowadays we have way more compared to the
> days of v1) with a bunch of debug options and for a few architectures.
> Also did a run of all released Rust versions with x86_64. It would still
> be nice to get more actual testing like Andreas' did with his driver,
> but we will probably only get that if we actually go ahead...
>
> Kees: do you want to do the other change directly?
>
> drivers/android/binder/deferred_close.rs | 29 ++++++++++++++++++---
> init/Kconfig | 3 +--
> rust/kernel/task.rs | 33 +++++++++++++++++++++---
> 3 files changed, 57 insertions(+), 8 deletions(-)
>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v2] rust: allow Clang-native `RANDSTRUCT` configs
2026-03-23 13:46 ` Gary Guo
@ 2026-03-23 14:24 ` Miguel Ojeda
0 siblings, 0 replies; 4+ messages in thread
From: Miguel Ojeda @ 2026-03-23 14:24 UTC (permalink / raw)
To: Gary Guo
Cc: Miguel Ojeda, Greg Kroah-Hartman, Arve Hjønnevåg,
Todd Kjos, Christian Brauner, Carlos Llamas, Alice Ryhl,
Nathan Chancellor, Nicolas Schier, Boqun Feng,
Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Trevor Gross, Danilo Krummrich, rust-for-linux, linux-kernel,
Nick Desaulniers, Bill Wendling, Justin Stitt, llvm, linux-kbuild,
Aaron Ballman, Bill Wendling, Cole Nixon, Connor Kuehl,
Fangrui Song, James Foster, Jeff Takahashi, Jordan Cantrell,
Matthew Maurer, Nikk Forbus, Qing Zhao, Sami Tolvanen, Tim Pugh,
Kees Cook
On Mon, Mar 23, 2026 at 2:46 PM Gary Guo <gary@garyguo.net> wrote:
>
> Can we avoid cfgs by always wrap things inside anonymous struct?
>
> The comment says "This anon struct can add padding, so only enable it under
> randstruct.", I wonder how much bigger the task_struct will be if this becomes
> unconditional wrapping.
Yeah, we may want to do that -- please see
https://lore.kernel.org/rust-for-linux/202512092319.ECBB8613@keescook/
from v1.
Cheers,
Miguel
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v2] rust: allow Clang-native `RANDSTRUCT` configs
2026-03-23 13:02 [PATCH v2] rust: allow Clang-native `RANDSTRUCT` configs Miguel Ojeda
2026-03-23 13:46 ` Gary Guo
@ 2026-03-26 3:18 ` kernel test robot
1 sibling, 0 replies; 4+ messages in thread
From: kernel test robot @ 2026-03-26 3:18 UTC (permalink / raw)
To: Miguel Ojeda, Greg Kroah-Hartman, Arve Hjønnevåg,
Todd Kjos, Christian Brauner, Carlos Llamas, Alice Ryhl,
Nathan Chancellor, Nicolas Schier
Cc: llvm, oe-kbuild-all, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Trevor Gross, Danilo Krummrich,
rust-for-linux, linux-kernel, Nick Desaulniers, Bill Wendling,
Justin Stitt, linux-kbuild, Aaron Ballman, Cole Nixon,
Connor Kuehl, Fangrui Song, James Foster, Jeff Takahashi,
Jordan Cantrell
Hi Miguel,
kernel test robot noticed the following build errors:
[auto build test ERROR on bf074eb6891be799174ff42e0051492681fdc045]
url: https://github.com/intel-lab-lkp/linux/commits/Miguel-Ojeda/rust-allow-Clang-native-RANDSTRUCT-configs/20260325-210001
base: bf074eb6891be799174ff42e0051492681fdc045
patch link: https://lore.kernel.org/r/20260323130224.165738-1-ojeda%40kernel.org
patch subject: [PATCH v2] rust: allow Clang-native `RANDSTRUCT` configs
config: loongarch-allmodconfig (https://download.01.org/0day-ci/archive/20260326/202603261112.bLTUmUGa-lkp@intel.com/config)
compiler: clang version 19.1.7 (https://github.com/llvm/llvm-project cd708029e0b2869e80abe31ddb175f7c35361f90)
rustc: rustc 1.88.0 (6b00bc388 2025-06-23)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260326/202603261112.bLTUmUGa-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603261112.bLTUmUGa-lkp@intel.com/
All errors (new ones prefixed by >>):
>> error: kernel-address sanitizer is not supported for this target
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-03-26 3:19 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-23 13:02 [PATCH v2] rust: allow Clang-native `RANDSTRUCT` configs Miguel Ojeda
2026-03-23 13:46 ` Gary Guo
2026-03-23 14:24 ` Miguel Ojeda
2026-03-26 3:18 ` kernel test robot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox