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 <aliceryhl@google.com>
This commit is contained in:
Alice Ryhl
2024-09-13 13:12:05 +00:00
committed by Treehugger Robot
parent b3607a5503
commit 0a8dbd6b7b
2 changed files with 38 additions and 0 deletions
+37
View File
@@ -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<Vec<u8>>,
}
@@ -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<isize> {
Ok(self.inner.lock().size as isize)
}
fn set_prot_mask(&self, mut prot: usize) -> Result<isize> {
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<isize> {
Ok(self.inner.lock().prot_mask as isize)
}
}
+1
View File
@@ -22,6 +22,7 @@
#include <linux/list_lru.h>
#include <linux/mdio.h>
#include <linux/miscdevice.h>
#include <linux/mman.h>
#include <linux/phy.h>
#include <linux/pid_namespace.h>
#include <linux/poll.h>