[PATCH v2 1/2] rust: debugfs: avoid borrowing seq_file in write

From: Tamir Duberstein

Date: Tue May 26 2026 - 14:11:55 EST


Commit 40ecc49466c8 ("rust: debugfs: Add support for callback-based
files") introduced `write()`, which creates a mutable Rust reference to
the `seq_file` stored in `file->private_data`.

File operation callbacks may execute concurrently for the same open
file. Creating that reference assumes exclusive access to the
`seq_file`, so overlapping calls can create aliased mutable references,
which violates Rust aliasing rules [1].

`write()` only needs the callback data stored in `seq_file::private`.
Read that field through a raw pointer instead, without borrowing the
containing C object.

Fixes: 40ecc49466c8 ("rust: debugfs: Add support for callback-based files")
Link: https://doc.rust-lang.org/reference/behavior-considered-undefined.html#undefined-behavior [1]
Assisted-by: Codex:gpt-5
Signed-off-by: Tamir Duberstein <tamird@xxxxxxxxxx>
---
rust/kernel/debugfs/file_ops.rs | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/rust/kernel/debugfs/file_ops.rs b/rust/kernel/debugfs/file_ops.rs
index f15908f71c4a..2bb2cbe156a3 100644
--- a/rust/kernel/debugfs/file_ops.rs
+++ b/rust/kernel/debugfs/file_ops.rs
@@ -159,7 +159,7 @@ fn read<T: Reader + Sync>(data: &T, buf: *const c_char, count: usize) -> isize {
///
/// `file` must be a valid pointer to a `file` struct.
/// The `private_data` of the file must contain a valid pointer to a `seq_file` whose
-/// `private` data in turn points to a `T` that implements `Reader`.
+/// `private` data is valid to convert to a shared reference to `T`.
/// `buf` must be a valid user-space buffer.
pub(crate) unsafe extern "C" fn write<T: Reader + Sync>(
file: *mut bindings::file,
@@ -168,9 +168,10 @@ fn read<T: Reader + Sync>(data: &T, buf: *const c_char, count: usize) -> isize {
_ppos: *mut bindings::loff_t,
) -> isize {
// SAFETY: The file was opened with `single_open`, which sets `private_data` to a `seq_file`.
- let seq = unsafe { &mut *((*file).private_data.cast::<bindings::seq_file>()) };
- // SAFETY: By caller precondition, this pointer is live and points to a value of type `T`.
- let data = unsafe { &*(seq.private as *const T) };
+ let seq = unsafe { (*file).private_data.cast::<bindings::seq_file>() };
+ // SAFETY: By caller precondition, `seq` points to a live `seq_file` whose
+ // `private` data is valid to convert to a shared reference to `T`.
+ let data = unsafe { &*((*seq).private as *const T) };
read(data, buf, count)
}


--
2.54.0