From ba971cd36a98c0e5cd51d531e5d7d306a0ebae78 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Fri, 18 Apr 2025 21:50:30 +0000 Subject: [PATCH] ANDROID: ashmem: use strncpy_from_user in set_name Ashmem expected that it could always read ASHMEM_NAME_LEN bytes from the provided pointer even if the actual string was shorter. This assumption turns out to be false. Bug: 409422661 Change-Id: I617be6c91947d44ec80b894c41fabe0f5c539eae Signed-off-by: Alice Ryhl --- drivers/staging/android/ashmem_rust.rs | 17 ++++++++--------- rust/kernel/uaccess.rs | 13 +++++++++++++ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/staging/android/ashmem_rust.rs b/drivers/staging/android/ashmem_rust.rs index ba1ebce05af0..ad8bb318e824 100644 --- a/drivers/staging/android/ashmem_rust.rs +++ b/drivers/staging/android/ashmem_rust.rs @@ -284,17 +284,16 @@ impl MiscDevice for Ashmem { } impl Ashmem { - fn set_name(&self, mut reader: UserSliceReader) -> Result { + fn set_name(&self, reader: UserSliceReader) -> Result { let mut local_name = [0u8; ASHMEM_NAME_LEN]; - reader.read_slice(&mut local_name)?; + let mut len = reader.strncpy_from_user(&mut local_name)?; - // Find the zero terminator. If the zero terminator is missing, the string is truncated to - // `ASHMEM_NAME_LEN-1` so that `get_name` can return it and has enough space to add a zero - // terminator. - let len = local_name - .iter() - .position(|&c| c == 0) - .unwrap_or(local_name.len() - 1); + // If the zero terminator is missing, the string is truncated to `ASHMEM_NAME_LEN-1` so + // that `get_name` can return it and has enough space to add a zero terminator. + if len == ASHMEM_NAME_LEN { + len -= 1; + local_name[len] = 0; + } let mut v = KVec::with_capacity(len, GFP_KERNEL)?; v.extend_from_slice(&local_name[..len], GFP_KERNEL)?; diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs index 5a3c2d4df65f..e7ed6c412ab1 100644 --- a/rust/kernel/uaccess.rs +++ b/rust/kernel/uaccess.rs @@ -294,6 +294,19 @@ impl UserSliceReader { unsafe { buf.set_len(buf.len() + len) }; Ok(()) } + + /// Reads a nul-terminated string into the provided buffer and returns the length. + pub fn strncpy_from_user(self, buf: &mut [u8]) -> Result { + let max = usize::min(self.length, buf.len()) as isize; + // SAFETY: `buf` is valid for writing `buf.len()` bytes. + let res = + unsafe { bindings::strncpy_from_user(buf.as_mut_ptr(), self.ptr as *const u8, max) }; + if res >= 0 { + Ok(res as usize) + } else { + Err(Error::from_errno(res as i32)) + } + } } /// A writer for [`UserSlice`].