Expose binder security context to rust binder services
This patch exposes AIBinder_setRequestingSid and AIBinder_getCallingSid
to binder services written in Rust. This is required by services to
effectively enforce SEPolicy because relying only on the caller's PID is
racy.
Bug: 165070170
Test: atest rustBinderTest
Change-Id: Iae25d4fedded7d133354ba4c82527f33e5d5e1ce
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index d55eafe..d8e0609 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -98,6 +98,9 @@
/// Send a ping transaction to this object
fn ping_binder(&mut self) -> Result<()>;
+ /// Indicate that the service intends to receive caller security contexts.
+ fn set_requesting_sid(&mut self, enable: bool);
+
/// Dump this object to the given file handle
fn dump<F: AsRawFd>(&mut self, fp: &F, args: &[&str]) -> Result<()>;
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index 13e5619..fde8b68 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -242,6 +242,12 @@
status_result(status)
}
+ fn set_requesting_sid(&mut self, enable: bool) {
+ unsafe {
+ sys::AIBinder_setRequestingSid(self.as_native_mut(), enable)
+ };
+ }
+
fn dump<F: AsRawFd>(&mut self, fp: &F, args: &[&str]) -> Result<()> {
let args: Vec<_> = args.iter().map(|a| CString::new(*a).unwrap()).collect();
let mut arg_ptrs: Vec<_> = args.iter().map(|a| a.as_ptr()).collect();
diff --git a/libs/binder/rust/src/state.rs b/libs/binder/rust/src/state.rs
index 992f074..0e05f10 100644
--- a/libs/binder/rust/src/state.rs
+++ b/libs/binder/rust/src/state.rs
@@ -98,4 +98,36 @@
sys::AIBinder_getCallingPid()
}
}
+
+ /// This function makes the client's security context available to the
+ /// service calling this function. This can be used for access control.
+ /// It does not suffer from the TOCTOU issues of get_calling_pid.
+ ///
+ /// Implementations of `check_permission` should use the given CStr
+ /// argument as context for selinux permission checks. If `None` is
+ /// given, the implementation should fall back to using the PID
+ /// instead.
+ ///
+ /// Note: `None` may be passed to the callback if the caller did not
+ /// `set_requesting_sid` on the serviced binder, or if the underlying
+ /// kernel is too old to support this feature.
+ pub fn with_calling_sid<T, F>(check_permission: F) -> T
+ where
+ for<'a> F: FnOnce(Option<&'a std::ffi::CStr>) -> T {
+ // Safety: AIBinder_getCallingSid returns a c-string pointer
+ // that is valid for a transaction. Also, the string returned
+ // is thread local. By restricting the lifetime of the CStr
+ // reference to the scope of the callback, we prevent it being
+ // used beyond the guaranteed lifetime.
+ check_permission(unsafe {
+ let sid = sys::AIBinder_getCallingSid();
+ // AIBinder_getCallingSid() returns a '\0' terminated string
+ // or NULL.
+ if sid.is_null() {
+ None
+ } else {
+ Some(std::ffi::CStr::from_ptr(sid))
+ }
+ })
+ }
}