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:
committed by
Treehugger Robot
parent
b3607a5503
commit
0a8dbd6b7b
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user