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