FROMGIT: rust: uaccess: add strncpy_from_user

This patch adds a direct wrapper around the C function of the same name.
It's not really intended for direct use by Rust code since
strncpy_from_user has a somewhat unfortunate API where it only
nul-terminates the buffer if there's space for the nul-terminator. This
means that a direct Rust wrapper around it could not return a &CStr
since the buffer may not be a cstring. However, we still add the method
to build more convenient APIs on top of it, which will happen in
subsequent patches.

Reviewed-by: Danilo Krummrich <dakr@kernel.org>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Boqun Feng <boqun.feng@gmail.com>
Reviewed-by: Benno Lossin <lossin@kernel.org>
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
Link: https://lore.kernel.org/r/20250616-strncpy-from-user-v5-1-2d3fb0e1f5af@google.com
[ Reworded title. - Miguel ]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

Bug: 414339114
(cherry picked from commit 8da881d39c1b7fd4a211587ba40f1c936909a11a
 https://github.com/Rust-for-Linux/linux.git rust-next)
Change-Id: I1455d14afbec4a4af1386618985f01a21b6dcf97
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
This commit is contained in:
Alice Ryhl
2025-06-16 12:41:47 +00:00
committed by Isaac Manjarres
parent bd6df18cfd
commit 0cb01a7d86
+35 -1
View File
@@ -8,7 +8,7 @@ use crate::{
alloc::{Allocator, Flags},
bindings,
error::Result,
ffi::c_void,
ffi::{c_char, c_void},
prelude::*,
types::{AsBytes, FromBytes},
};
@@ -370,3 +370,37 @@ impl UserSliceWriter {
Ok(())
}
}
/// Reads a nul-terminated string into `dst` and returns the length.
///
/// This reads from userspace until a NUL byte is encountered, or until `dst.len()` bytes have been
/// read. Fails with [`EFAULT`] if a read happens on a bad address (some data may have been
/// copied). When the end of the buffer is encountered, no NUL byte is added, so the string is
/// *not* guaranteed to be NUL-terminated when `Ok(dst.len())` is returned.
///
/// # Guarantees
///
/// When this function returns `Ok(len)`, it is guaranteed that the first `len` bytes of `dst` are
/// initialized and non-zero. Furthermore, if `len < dst.len()`, then `dst[len]` is a NUL byte.
#[inline]
#[expect(dead_code)]
fn raw_strncpy_from_user(dst: &mut [MaybeUninit<u8>], src: UserPtr) -> Result<usize> {
// CAST: Slice lengths are guaranteed to be `<= isize::MAX`.
let len = dst.len() as isize;
// SAFETY: `dst` is valid for writing `dst.len()` bytes.
let res = unsafe {
bindings::strncpy_from_user(dst.as_mut_ptr().cast::<c_char>(), src as *const c_char, len)
};
if res < 0 {
return Err(Error::from_errno(res as i32));
}
#[cfg(CONFIG_RUST_OVERFLOW_CHECKS)]
assert!(res <= len);
// GUARANTEES: `strncpy_from_user` was successful, so `dst` has contents in accordance with the
// guarantees of this function.
Ok(res as usize)
}