From 0a8dbd6b7bf199a44f306f967163db57da882fdf Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Fri, 13 Sep 2024 13:12:05 +0000 Subject: [PATCH] ANDROID: ashmem_rust: add GET/SET_PROT_MASK It's really important for ashmem's security model that once you give up protection bits, you can't get them back. Another important factor is that this will not affect existing mmaps. This means that if you mmap a writable ashmem fd, and then give up all of your permissions, then even if you accidentally send the fd to another process, that other process will not be able to access the contents. The mman.h header is for the PROT_* constants. Bug: 370906207 Change-Id: I5046126ffd1c2ac99936eaeaee89087961092649 Signed-off-by: Alice Ryhl --- drivers/staging/android/ashmem_rust.rs | 37 ++++++++++++++++++++++++++ rust/bindings/bindings_helper.h | 1 + 2 files changed, 38 insertions(+) diff --git a/drivers/staging/android/ashmem_rust.rs b/drivers/staging/android/ashmem_rust.rs index cbf8266fa38a..8085e05d8c3a 100644 --- a/drivers/staging/android/ashmem_rust.rs +++ b/drivers/staging/android/ashmem_rust.rs @@ -19,11 +19,24 @@ use kernel::{ miscdevice::{MiscDevice, MiscDeviceOptions, MiscDeviceRegistration}, prelude::*, sync::{new_mutex, Mutex}, + task::Task, uaccess::{UserSlice, UserSliceReader, UserSliceWriter}, }; const ASHMEM_NAME_LEN: usize = bindings::ASHMEM_NAME_LEN as usize; +const PROT_READ: usize = bindings::PROT_READ as usize; +const PROT_EXEC: usize = bindings::PROT_EXEC as usize; +const PROT_WRITE: usize = bindings::PROT_WRITE as usize; +const PROT_MASK: usize = PROT_EXEC | PROT_READ | PROT_WRITE; + +/// Does PROT_READ imply PROT_EXEC for this task? +fn read_implies_exec(task: &Task) -> bool { + // SAFETY: Always safe to read. + let personality = unsafe { (*task.as_ptr()).personality }; + (personality & bindings::READ_IMPLIES_EXEC) != 0 +} + module! { type: AshmemModule, name: "ashmem_rust", @@ -60,6 +73,7 @@ struct Ashmem { struct AshmemInner { size: usize, + prot_mask: usize, /// If set, then this holds the ashmem name without the dev/ashmem/ prefix. No zero terminator. name: Option>, } @@ -74,6 +88,7 @@ impl MiscDevice for Ashmem { Ashmem { inner <- new_mutex!(AshmemInner { size: 0, + prot_mask: PROT_MASK, name: None, }), } @@ -89,6 +104,8 @@ impl MiscDevice for Ashmem { bindings::ASHMEM_GET_NAME => me.get_name(UserSlice::new(arg, size).writer()), bindings::ASHMEM_SET_SIZE => me.set_size(arg), bindings::ASHMEM_GET_SIZE => me.get_size(), + bindings::ASHMEM_SET_PROT_MASK => me.set_prot_mask(arg), + bindings::ASHMEM_GET_PROT_MASK => me.get_prot_mask(), _ => Err(EINVAL), } } @@ -145,4 +162,24 @@ impl Ashmem { fn get_size(&self) -> Result { Ok(self.inner.lock().size as isize) } + + fn set_prot_mask(&self, mut prot: usize) -> Result { + let mut asma = self.inner.lock(); + + if (prot & PROT_READ != 0) && read_implies_exec(current!()) { + prot |= PROT_EXEC; + } + + // The user can only remove, not add, protection bits. + if (asma.prot_mask & prot) != prot { + return Err(EINVAL); + } + + asma.prot_mask = prot; + Ok(0) + } + + fn get_prot_mask(&self) -> Result { + Ok(self.inner.lock().prot_mask as isize) + } } diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index cc0387de3b72..e0084b22fa26 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include