From 1c7e6e5ef33d954e4ab6a680f033d31d45d18a60 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Tue, 21 Jan 2025 10:26:29 +0000 Subject: [PATCH] ANDROID: ashmem_rust: add toggle for PROT_EXEC The memfd type simulates SET_PROT_MASK using file seals, but there's no file seal to prevent mapping executable memory. Thus, add a toggle that removes the ability to unset the PROT_EXEC bit on an ashmem file. Bug: 370906207 Change-Id: Ia90c2cfca689d152fb1765f2abcf6bb3f60cd05d Signed-off-by: Alice Ryhl --- drivers/staging/android/ashmem_rust.rs | 10 +++++++++- drivers/staging/android/ashmem_toggle.rs | 15 ++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/drivers/staging/android/ashmem_rust.rs b/drivers/staging/android/ashmem_rust.rs index 4869b16a165d..ddf87dcf08b5 100644 --- a/drivers/staging/android/ashmem_rust.rs +++ b/drivers/staging/android/ashmem_rust.rs @@ -50,7 +50,7 @@ mod shmem; use shmem::ShmemFile; mod ashmem_toggle; -use ashmem_toggle::{AshmemToggleMisc, AshmemToggleRead, AshmemToggleShrinker}; +use ashmem_toggle::{AshmemToggleExec, AshmemToggleMisc, AshmemToggleRead, AshmemToggleShrinker}; /// Does PROT_READ imply PROT_EXEC for this task? fn read_implies_exec(task: &Task) -> bool { @@ -67,6 +67,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); fn shrinker_should_stop() -> bool { NUM_PIN_IOCTLS_WAITING.load(Ordering::Relaxed) > 0 @@ -84,6 +85,7 @@ struct AshmemModule { _misc: Pin>>, _toggle_unpin: Pin>>>, _toggle_read: Pin>>>, + _toggle_exec: Pin>>>, } impl kernel::Module for AshmemModule { @@ -108,6 +110,7 @@ impl kernel::Module for AshmemModule { )?, _toggle_unpin: AshmemToggleMisc::::new()?, _toggle_read: AshmemToggleMisc::::new()?, + _toggle_exec: AshmemToggleMisc::::new()?, }) } } @@ -348,6 +351,11 @@ impl Ashmem { prot |= asma.prot_mask & PROT_READ; } + if IGNORE_UNSET_PROT_EXEC.load(Ordering::Relaxed) { + // Add back PROT_EXEC if asma.prot_mask has it. + prot |= asma.prot_mask & PROT_EXEC; + } + // The user can only remove, not add, protection bits. if (asma.prot_mask & prot) != prot { return Err(EINVAL); diff --git a/drivers/staging/android/ashmem_toggle.rs b/drivers/staging/android/ashmem_toggle.rs index 5cde50e4fffa..741d5e8569bd 100644 --- a/drivers/staging/android/ashmem_toggle.rs +++ b/drivers/staging/android/ashmem_toggle.rs @@ -4,7 +4,7 @@ //! Provides knobs for Rust ashmem. -use crate::{ashmem_range, IGNORE_UNSET_PROT_READ}; +use crate::{ashmem_range, IGNORE_UNSET_PROT_EXEC, IGNORE_UNSET_PROT_READ}; use core::{marker::PhantomData, sync::atomic::Ordering}; use kernel::{ c_str, @@ -92,3 +92,16 @@ impl AshmemToggle for AshmemToggleRead { IGNORE_UNSET_PROT_READ.load(Ordering::Relaxed) } } + +pub(crate) struct AshmemToggleExec; + +impl AshmemToggle for AshmemToggleExec { + const NAME: &'static CStr = c_str!("ashmem_ignore_unset_prot_exec"); + fn set(enabled: bool) -> Result<()> { + IGNORE_UNSET_PROT_EXEC.store(enabled, Ordering::Relaxed); + Ok(()) + } + fn get() -> bool { + IGNORE_UNSET_PROT_EXEC.load(Ordering::Relaxed) + } +}