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 <aliceryhl@google.com>
This commit is contained in:
Alice Ryhl
2025-01-21 10:26:29 +00:00
committed by Suren Baghdasaryan
parent e8bed58ffd
commit 1c7e6e5ef3
2 changed files with 23 additions and 2 deletions
+9 -1
View File
@@ -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<Box<MiscDeviceRegistration<Ashmem>>>,
_toggle_unpin: Pin<Box<MiscDeviceRegistration<AshmemToggleMisc<AshmemToggleShrinker>>>>,
_toggle_read: Pin<Box<MiscDeviceRegistration<AshmemToggleMisc<AshmemToggleRead>>>>,
_toggle_exec: Pin<Box<MiscDeviceRegistration<AshmemToggleMisc<AshmemToggleExec>>>>,
}
impl kernel::Module for AshmemModule {
@@ -108,6 +110,7 @@ impl kernel::Module for AshmemModule {
)?,
_toggle_unpin: AshmemToggleMisc::<AshmemToggleShrinker>::new()?,
_toggle_read: AshmemToggleMisc::<AshmemToggleRead>::new()?,
_toggle_exec: AshmemToggleMisc::<AshmemToggleExec>::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);
+14 -1
View File
@@ -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)
}
}