From e8bed58ffdca2bdf348bda92ac4d177f83fe602a Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Tue, 10 Dec 2024 14:37:57 +0000 Subject: [PATCH] ANDROID: ashmem_rust: add toggle for PROT_READ The memfd type simulates SET_PROT_MASK using file seals, but there's no file seal to prevent mapping readable memory. Thus, add a toggle that removes the ability to unset the PROT_READ bit on an ashmem file. Bug: 370906207 Change-Id: I2d0347ce124d7d6d543cff765f77b28202cf327f Signed-off-by: Alice Ryhl --- drivers/staging/android/ashmem_rust.rs | 12 ++++++++++-- drivers/staging/android/ashmem_toggle.rs | 17 +++++++++++++++-- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/drivers/staging/android/ashmem_rust.rs b/drivers/staging/android/ashmem_rust.rs index 354484f5adef..4869b16a165d 100644 --- a/drivers/staging/android/ashmem_rust.rs +++ b/drivers/staging/android/ashmem_rust.rs @@ -13,7 +13,7 @@ use core::{ ffi::c_int, pin::Pin, - sync::atomic::{AtomicUsize, Ordering}, + sync::atomic::{AtomicBool, AtomicUsize, Ordering}, }; use kernel::{ bindings::{self, ASHMEM_GET_PIN_STATUS, ASHMEM_PIN, ASHMEM_UNPIN}, @@ -50,7 +50,7 @@ mod shmem; use shmem::ShmemFile; mod ashmem_toggle; -use ashmem_toggle::{AshmemToggleMisc, AshmemToggleShrinker}; +use ashmem_toggle::{AshmemToggleMisc, AshmemToggleRead, AshmemToggleShrinker}; /// Does PROT_READ imply PROT_EXEC for this task? fn read_implies_exec(task: &Task) -> bool { @@ -66,6 +66,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); fn shrinker_should_stop() -> bool { NUM_PIN_IOCTLS_WAITING.load(Ordering::Relaxed) > 0 @@ -82,6 +83,7 @@ module! { struct AshmemModule { _misc: Pin>>, _toggle_unpin: Pin>>>, + _toggle_read: Pin>>>, } impl kernel::Module for AshmemModule { @@ -105,6 +107,7 @@ impl kernel::Module for AshmemModule { GFP_KERNEL, )?, _toggle_unpin: AshmemToggleMisc::::new()?, + _toggle_read: AshmemToggleMisc::::new()?, }) } } @@ -340,6 +343,11 @@ impl Ashmem { prot |= PROT_EXEC; } + if IGNORE_UNSET_PROT_READ.load(Ordering::Relaxed) { + // Add back PROT_READ if asma.prot_mask has it. + prot |= asma.prot_mask & PROT_READ; + } + // 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 852fba71684f..5cde50e4fffa 100644 --- a/drivers/staging/android/ashmem_toggle.rs +++ b/drivers/staging/android/ashmem_toggle.rs @@ -4,8 +4,8 @@ //! Provides knobs for Rust ashmem. -use crate::ashmem_range; -use core::marker::PhantomData; +use crate::{ashmem_range, IGNORE_UNSET_PROT_READ}; +use core::{marker::PhantomData, sync::atomic::Ordering}; use kernel::{ c_str, error::to_result, @@ -79,3 +79,16 @@ impl AshmemToggle for AshmemToggleShrinker { ashmem_range::get_shrinker_enabled() } } + +pub(crate) struct AshmemToggleRead; + +impl AshmemToggle for AshmemToggleRead { + const NAME: &'static CStr = c_str!("ashmem_ignore_unset_prot_read"); + fn set(enabled: bool) -> Result<()> { + IGNORE_UNSET_PROT_READ.store(enabled, Ordering::Relaxed); + Ok(()) + } + fn get() -> bool { + IGNORE_UNSET_PROT_READ.load(Ordering::Relaxed) + } +}