Skip to content

binder: add security module checks. #413

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion drivers/android/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ extern crate alloc;
use kernel::{
bindings,
prelude::*,
security,
sync::{Mutex, Ref},
Error,
};
Expand Down Expand Up @@ -51,7 +52,7 @@ impl Context {
if manager.node.is_some() {
return Err(Error::EBUSY);
}
// TODO: Call security_binder_set_context_mgr.
security::binder_set_context_mgr(&node_ref.node.owner.task)?;

// TODO: Get the actual caller id.
let caller_uid = bindings::kuid_t::default();
Expand Down
9 changes: 8 additions & 1 deletion drivers/android/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,9 @@ impl ProcessNodeRefs {
pub(crate) struct Process {
ctx: Ref<Context>,

// The task leader (process).
pub(crate) task: Task,

// TODO: For now this a mutex because we have allocations in RangeAllocator while holding the
// lock. We may want to split up the process state at some point to use a spin lock for the
// other fields.
Expand All @@ -293,6 +296,7 @@ impl Process {
Ok(Ref::pinned(Ref::try_new_and_init(
Self {
ctx,
task: Task::current().group_leader().clone(),
// SAFETY: `inner` is initialised in the call to `mutex_init` below.
inner: unsafe { Mutex::new(ProcessInner::new()) },
// SAFETY: `node_refs` is initialised in the call to `mutex_init` below.
Expand Down Expand Up @@ -917,7 +921,10 @@ impl FileOperations for Process {
}

fn mmap(this: &Ref<Process>, _file: &File, vma: &mut bindings::vm_area_struct) -> Result {
// TODO: Only group leader is allowed to create mappings.
// We don't allow mmap to be used in a different process.
if !Task::current().group_leader().eq(&this.task) {
return Err(Error::EINVAL);
}

if vma.vm_start == 0 {
return Err(Error::EINVAL);
Expand Down
18 changes: 15 additions & 3 deletions drivers/android/thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use kernel::{
io_buffer::{IoBufferReader, IoBufferWriter},
linked_list::{GetLinks, Links, List},
prelude::*,
security,
sync::{CondVar, Ref, SpinLock},
user_ptr::{UserSlicePtr, UserSlicePtrWriter},
Error,
Expand Down Expand Up @@ -388,17 +389,21 @@ impl Thread {
let ptr = unsafe { obj.__bindgen_anon_1.binder } as _;
let cookie = obj.cookie as _;
let flags = obj.flags as _;
Ok(self
let node = self
.process
.get_node(ptr, cookie, flags, strong, Some(self))?)
.get_node(ptr, cookie, flags, strong, Some(self))?;
security::binder_transfer_binder(&self.process.task, &view.alloc.process.task)?;
Ok(node)
})?;
}
BINDER_TYPE_WEAK_HANDLE | BINDER_TYPE_HANDLE => {
let strong = header.type_ == BINDER_TYPE_HANDLE;
view.transfer_binder_object(offset, strong, |obj| {
// SAFETY: `handle` is a `u32`; any bit pattern is a valid representation.
let handle = unsafe { obj.__bindgen_anon_1.handle } as _;
self.process.get_node_from_handle(handle, strong)
let node = self.process.get_node_from_handle(handle, strong)?;
security::binder_transfer_binder(&self.process.task, &view.alloc.process.task)?;
Ok(node)
})?;
}
BINDER_TYPE_FD => {
Expand All @@ -410,6 +415,11 @@ impl Thread {
// SAFETY: `fd` is a `u32`; any bit pattern is a valid representation.
let fd = unsafe { obj.__bindgen_anon_1.fd };
let file = File::from_fd(fd)?;
security::binder_transfer_file(
&self.process.task,
&view.alloc.process.task,
&file,
)?;
let field_offset =
kernel::offset_of!(bindings::binder_fd_object, __bindgen_anon_1.fd) as usize;
let file_info = Box::try_new(FileInfo::new(file, offset + field_offset))?;
Expand Down Expand Up @@ -598,6 +608,7 @@ impl Thread {
fn oneway_transaction_inner(self: &Arc<Self>, tr: &BinderTransactionData) -> BinderResult {
let handle = unsafe { tr.target.handle };
let node_ref = self.process.get_transaction_node(handle)?;
security::binder_transaction(&self.process.task, &node_ref.node.owner.task)?;
let completion = Arc::try_new(DeliverCode::new(BR_TRANSACTION_COMPLETE))?;
let transaction = Transaction::new(node_ref, None, self, tr)?;
self.inner.lock().push_work(completion);
Expand All @@ -609,6 +620,7 @@ impl Thread {
fn transaction_inner(self: &Arc<Self>, tr: &BinderTransactionData) -> BinderResult {
let handle = unsafe { tr.target.handle };
let node_ref = self.process.get_transaction_node(handle)?;
security::binder_transaction(&self.process.task, &node_ref.node.owner.task)?;
// TODO: We need to ensure that there isn't a pending transaction in the work queue. How
// could this happen?
let top = self.top_of_transaction_stack()?;
Expand Down
29 changes: 29 additions & 0 deletions rust/helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <linux/errname.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/security.h>

void rust_helper_BUG(void)
{
Expand Down Expand Up @@ -183,6 +184,34 @@ void rust_helper_put_task_struct(struct task_struct * t)
}
EXPORT_SYMBOL_GPL(rust_helper_put_task_struct);

int rust_helper_security_binder_set_context_mgr(struct task_struct *mgr)
{
return security_binder_set_context_mgr(mgr);
}
EXPORT_SYMBOL_GPL(rust_helper_security_binder_set_context_mgr);

int rust_helper_security_binder_transaction(struct task_struct *from,
struct task_struct *to)
{
return security_binder_transaction(from, to);
}
EXPORT_SYMBOL_GPL(rust_helper_security_binder_transaction);

int rust_helper_security_binder_transfer_binder(struct task_struct *from,
struct task_struct *to)
{
return security_binder_transfer_binder(from, to);
}
EXPORT_SYMBOL_GPL(rust_helper_security_binder_transfer_binder);

int rust_helper_security_binder_transfer_file(struct task_struct *from,
struct task_struct *to,
struct file *file)
{
return security_binder_transfer_file(from, to, file);
}
EXPORT_SYMBOL_GPL(rust_helper_security_binder_transfer_file);

/* We use bindgen's --size_t-is-usize option to bind the C size_t type
* as the Rust usize type, so we can use it in contexts where Rust
* expects a usize like slice (array) indices. usize is defined to be
Expand Down
1 change: 1 addition & 0 deletions rust/kernel/bindings_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <uapi/linux/android/binder.h>
#include <linux/platform_device.h>
#include <linux/of_platform.h>
#include <linux/security.h>

// `bindgen` gets confused at certain things
const gfp_t BINDINGS_GFP_KERNEL = GFP_KERNEL;
Expand Down
1 change: 1 addition & 0 deletions rust/kernel/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ pub mod file;
pub mod file_operations;
pub mod miscdev;
pub mod pages;
pub mod security;
pub mod str;
pub mod task;
pub mod traits;
Expand Down
79 changes: 79 additions & 0 deletions rust/kernel/security.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// SPDX-License-Identifier: GPL-2.0

//! Linux Security Modules (LSM).
//!
//! C header: [`include/linux/security.h`](../../../../include/linux/security.h).

use crate::{bindings, c_types, error::Error, file::File, task::Task, Result};

extern "C" {
#[allow(improper_ctypes)]
fn rust_helper_security_binder_set_context_mgr(
mgr: *mut bindings::task_struct,
) -> c_types::c_int;
#[allow(improper_ctypes)]
fn rust_helper_security_binder_transaction(
from: *mut bindings::task_struct,
to: *mut bindings::task_struct,
) -> c_types::c_int;
#[allow(improper_ctypes)]
fn rust_helper_security_binder_transfer_binder(
from: *mut bindings::task_struct,
to: *mut bindings::task_struct,
) -> c_types::c_int;
#[allow(improper_ctypes)]
fn rust_helper_security_binder_transfer_file(
from: *mut bindings::task_struct,
to: *mut bindings::task_struct,
file: *mut bindings::file,
) -> c_types::c_int;
}

/// Calls the security modules to determine if the given task can become the manager of a binder
/// context.
pub fn binder_set_context_mgr(mgr: &Task) -> Result {
// SAFETY: By the `Task` invariants, `mgr.ptr` is valid.
let ret = unsafe { rust_helper_security_binder_set_context_mgr(mgr.ptr) };
if ret != 0 {
Err(Error::from_kernel_errno(ret))
} else {
Ok(())
}
}

/// Calls the security modules to determine if binder transactions are allowed from task `from` to
/// task `to`.
pub fn binder_transaction(from: &Task, to: &Task) -> Result {
// SAFETY: By the `Task` invariants, `from.ptr` and `to.ptr` are valid.
let ret = unsafe { rust_helper_security_binder_transaction(from.ptr, to.ptr) };
if ret != 0 {
Err(Error::from_kernel_errno(ret))
} else {
Ok(())
}
}

/// Calls the security modules to determine if task `from` is allowed to send binder objects
/// (owned by itself or other processes) to task `to` through a binder transaction.
pub fn binder_transfer_binder(from: &Task, to: &Task) -> Result {
// SAFETY: By the `Task` invariants, `from.ptr` and `to.ptr` are valid.
let ret = unsafe { rust_helper_security_binder_transfer_binder(from.ptr, to.ptr) };
if ret != 0 {
Err(Error::from_kernel_errno(ret))
} else {
Ok(())
}
}

/// Calls the security modules to determine if task `from` is allowed to send the given file to
/// task `to` (which would get its own file descriptor) through a binder transaction.
pub fn binder_transfer_file(from: &Task, to: &Task, file: &File) -> Result {
// SAFETY: By the `Task` invariants, `from.ptr` and `to.ptr` are valid. Similarly, by the
// `File` invariants, `file.ptr` is also valid.
let ret = unsafe { rust_helper_security_binder_transfer_file(from.ptr, to.ptr, file.ptr) };
if ret != 0 {
Err(Error::from_kernel_errno(ret))
} else {
Ok(())
}
}