include!(concat!(env!("OUT_DIR"), "/permission_controller.rs"));
pub use android::os::IPermissionController::{
BnPermissionController, BpPermissionController, IPermissionController,
IPermissionControllerDefault, IPermissionControllerDefaultRef,
};
#[cfg(feature = "async")]
pub use android::os::IPermissionController::{
IPermissionControllerAsync, IPermissionControllerAsyncService,
};
use std::sync::{Arc, RwLock};
use crate::error::Result;
use crate::{hub, Caller, FromIBinder, Parcel, Strong};
pub const SERVICE_NAME: &str = "permission";
pub trait PermissionAuthority: Send + Sync {
fn check(&self, permission: &str, caller: &Caller) -> bool;
}
static AUTHORITY: RwLock<Option<Arc<dyn PermissionAuthority>>> = RwLock::new(None);
pub fn set_permission_authority(authority: Arc<dyn PermissionAuthority>) {
*AUTHORITY.write().expect("permission authority poisoned") = Some(authority);
}
pub fn clear_permission_authority() {
*AUTHORITY.write().expect("permission authority poisoned") = None;
}
pub fn default() -> Result<Strong<dyn IPermissionController>> {
let binder = hub::get_service(SERVICE_NAME).ok_or(crate::StatusCode::NameNotFound)?;
<dyn IPermissionController>::try_from(binder)
}
pub fn check_permission(reader: &Parcel, permission_name: &str) -> bool {
let authority = AUTHORITY
.read()
.expect("permission authority poisoned")
.clone();
if let Some(authority) = authority {
return crate::calling_caller()
.is_some_and(|caller| authority.check(permission_name, &caller));
}
if reader.is_for_rpc() {
warn_enforce_permission_over_rpc();
return false;
}
let calling_pid = crate::get_calling_pid();
let calling_uid = crate::get_calling_uid();
let Ok(pc) = default() else {
return false;
};
pc.checkPermission(permission_name, calling_pid as i32, calling_uid as i32)
.unwrap_or(false)
}
fn warn_enforce_permission_over_rpc() {
use std::sync::Once;
static WARNED: Once = Once::new();
WARNED.call_once(|| {
log::warn!(
"@EnforcePermission is unsupported over RPC and denies every \
guarded method (Plan 2-16 Phase A); use PeerIdentity / \
set_authorizer or uid ACLs for RPC authorization"
);
});
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_descriptor_matches_aosp_wire() {
assert_eq!(
<BpPermissionController as IPermissionController>::descriptor(),
"android.os.IPermissionController"
);
}
#[test]
fn test_service_name_matches_system_server_registration() {
assert_eq!(SERVICE_NAME, "permission");
}
#[cfg(feature = "rpc")]
#[serial_test::serial(authority)]
#[test]
fn check_permission_denies_rpc_parcel() {
let mut rpc_parcel = Parcel::new();
rpc_parcel.set_for_rpc(true);
assert!(
!check_permission(&rpc_parcel, "android.permission.INTERNET"),
"RPC parcel must fail-closed regardless of uid/PMS"
);
let kernel_parcel = Parcel::new();
assert!(!kernel_parcel.is_for_rpc());
}
#[cfg(feature = "rpc")]
#[serial_test::serial(authority)]
#[test]
fn injected_authority_overrides_default_rpc_deny() {
use crate::rpc::transport::PeerIdentity;
use crate::thread_state::RpcCallingGuard;
use crate::Caller;
use std::sync::Arc;
struct UidGrant {
allow_uid: u32,
permission: String,
}
impl PermissionAuthority for UidGrant {
fn check(&self, permission: &str, caller: &Caller) -> bool {
matches!(caller, Caller::Rpc(PeerIdentity::Local { uid, .. })
if *uid == self.allow_uid && permission == self.permission)
}
}
set_permission_authority(Arc::new(UidGrant {
allow_uid: 1000,
permission: "com.example.DO_THING".to_string(),
}));
let mut rpc_parcel = Parcel::new();
rpc_parcel.set_for_rpc(true);
{
let _g = RpcCallingGuard::install(Arc::new(PeerIdentity::Local { uid: 1000, pid: 7 }));
assert!(
check_permission(&rpc_parcel, "com.example.DO_THING"),
"authority must grant the allowed uid+permission over RPC"
);
assert!(
!check_permission(&rpc_parcel, "com.example.OTHER"),
"authority must deny an unknown permission"
);
}
{
let _g = RpcCallingGuard::install(Arc::new(PeerIdentity::Local { uid: 2000, pid: 7 }));
assert!(
!check_permission(&rpc_parcel, "com.example.DO_THING"),
"authority must deny a non-allowed uid"
);
}
assert!(!check_permission(&rpc_parcel, "com.example.DO_THING"));
clear_permission_authority();
let _g = RpcCallingGuard::install(Arc::new(PeerIdentity::Local { uid: 1000, pid: 7 }));
assert!(
!check_permission(&rpc_parcel, "com.example.DO_THING"),
"after clear, the default RPC deny is restored"
);
}
}