From 6bdbae6ea9fc0d678d3e43800150f43e0dd7ac81 Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Fri, 27 Jun 2025 15:07:30 +0000 Subject: [PATCH] ANDROID: ashmem_rust: Add is_ashmem_file() The minidump module iterates over open files and VMAs for each process and reports information that is useful for debugging. A useful piece of information is what ashmem files are currently referenced either via a userspace memory mapping or a file descriptor. Therefore, add is_ashmem_file() to aid in identifying those references. Unfortunately, the logic that exports Rust symbols to other kernel modules only considers the crates under the rust/ directory at the root of the kernel repository. Since there's no support to include symbols from crates defined outside of that repository, add ashmem_rust_exports.c to export is_ashmem_file(). Changes from older versions of this patch: - Reworded commit message for clarity. - Implemented is_ashmem_file() in Rust, since android16-6.12+ will use Rust for ashmem. Bug: 193397560 Change-Id: I5b7816ad4775e5cf2c4f41c28b1c8dacc2c85b7e Signed-off-by: Isaac J. Manjarres --- drivers/staging/android/Makefile | 1 + drivers/staging/android/ashmem.h | 2 + drivers/staging/android/ashmem_rust.rs | 38 +++++++++++++++---- drivers/staging/android/ashmem_rust_exports.c | 19 ++++++++++ 4 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 drivers/staging/android/ashmem_rust_exports.c diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile index 55a4320bbf8e..647dfa00906f 100644 --- a/drivers/staging/android/Makefile +++ b/drivers/staging/android/Makefile @@ -3,3 +3,4 @@ ccflags-y += -I$(src) # needed for trace events obj-$(CONFIG_ASHMEM_C) += ashmem.o obj-$(CONFIG_ASHMEM_RUST) += ashmem_rust.o +ashmem_rust-objs += ashmem_rust.o ashmem_rust_exports.o diff --git a/drivers/staging/android/ashmem.h b/drivers/staging/android/ashmem.h index fcacbfc9bd99..f649afa0d963 100644 --- a/drivers/staging/android/ashmem.h +++ b/drivers/staging/android/ashmem.h @@ -31,4 +31,6 @@ enum { }; #endif +bool is_ashmem_file(struct file *file); + #endif /* _LINUX_ASHMEM_H */ diff --git a/drivers/staging/android/ashmem_rust.rs b/drivers/staging/android/ashmem_rust.rs index 8021380c8ed8..e3f1165f1ed4 100644 --- a/drivers/staging/android/ashmem_rust.rs +++ b/drivers/staging/android/ashmem_rust.rs @@ -12,7 +12,8 @@ use core::{ pin::Pin, - sync::atomic::{AtomicBool, AtomicUsize, Ordering}, + ptr::null_mut, + sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize, Ordering}, }; use kernel::{ bindings::{self, ASHMEM_GET_PIN_STATUS, ASHMEM_PIN, ASHMEM_UNPIN}, @@ -71,6 +72,7 @@ fn has_cap_sys_admin() -> bool { static NUM_PIN_IOCTLS_WAITING: AtomicUsize = AtomicUsize::new(0); static IGNORE_UNSET_PROT_READ: AtomicBool = AtomicBool::new(false); static IGNORE_UNSET_PROT_EXEC: AtomicBool = AtomicBool::new(false); +static ASHMEM_FOPS_PTR: AtomicPtr = AtomicPtr::new(null_mut()); fn shrinker_should_stop() -> bool { NUM_PIN_IOCTLS_WAITING.load(Ordering::Relaxed) > 0 @@ -104,13 +106,20 @@ impl kernel::Module for AshmemModule { ashmem_range::set_shrinker_enabled(true)?; + let ashmem_miscdevice_registration = KBox::pin_init( + MiscDeviceRegistration::register(MiscDeviceOptions { + name: c_str!("ashmem"), + }), + GFP_KERNEL, + )?; + let ashmem_miscdevice_ptr = ashmem_miscdevice_registration.as_raw(); + // SAFETY: ashmem_miscdevice_registration is pinned and is never destroyed, so reading + // and storing the fops pointer this way should be fine. + let fops_ptr = unsafe { (*ashmem_miscdevice_ptr).fops }; + ASHMEM_FOPS_PTR.store(fops_ptr.cast_mut(), Ordering::Relaxed); + Ok(Self { - _misc: KBox::pin_init( - MiscDeviceRegistration::register(MiscDeviceOptions { - name: c_str!("ashmem"), - }), - GFP_KERNEL, - )?, + _misc: ashmem_miscdevice_registration, _toggle_unpin: AshmemToggleMisc::::new()?, _toggle_read: AshmemToggleMisc::::new()?, _toggle_exec: AshmemToggleMisc::::new()?, @@ -638,3 +647,18 @@ fn ashmem_memfd_ioctl_inner(file: &File, cmd: u32, arg: usize) -> Result _ => Err(EINVAL), } } + +/// # Safety +/// +/// The caller must ensure that `file` is valid for the duration of this function. +#[no_mangle] +unsafe extern "C" fn is_ashmem_file(file: *mut bindings::file) -> bool { + let ashmem_fops_ptr = ASHMEM_FOPS_PTR.load(Ordering::Relaxed); + if file.is_null() || ashmem_fops_ptr.is_null() { + return false; + } + + // SAFETY: Accessing the f_op field of a non-NULL file structure is always okay. + let fops_ptr = unsafe { (*file).f_op }; + fops_ptr == ashmem_fops_ptr +} diff --git a/drivers/staging/android/ashmem_rust_exports.c b/drivers/staging/android/ashmem_rust_exports.c new file mode 100644 index 000000000000..1de744975ca8 --- /dev/null +++ b/drivers/staging/android/ashmem_rust_exports.c @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Symbols exported from the Ashmem Rust driver for loadable kernel modules to use. + * + * Copyright (c) 2025, Google LLC. + */ + +#include + +#include "ashmem.h" + +/* + * List symbols that need to be exported to loadable kernel modules below. This is needed because + * the logic that exports symbols from Rust crates only considers the crates under the rust/ + * directory at the root of the kernel repo. It currently does not support exporting symbols from + * other crates. + */ +EXPORT_SYMBOL_GPL(is_ashmem_file);