From 82993b05d316fb69242356283949bc39eee6b3da Mon Sep 17 00:00:00 2001 From: Ashwin Naren Date: Tue, 13 Jan 2026 23:52:36 -0800 Subject: [PATCH] implement PR_CAPBSET_DROP, PR_GET_SECUREBITS, PR_GET_NO_NEW_PRIVS, and PR_CAP_AMBIENT --- libkernel/src/proc/caps.rs | 8 +++ src/arch/arm64/exceptions/syscall.rs | 2 +- src/process/prctl.rs | 81 ++++++++++++++++++++++++---- 3 files changed, 81 insertions(+), 10 deletions(-) diff --git a/libkernel/src/proc/caps.rs b/libkernel/src/proc/caps.rs index 30d1d19..7a37449 100644 --- a/libkernel/src/proc/caps.rs +++ b/libkernel/src/proc/caps.rs @@ -145,10 +145,18 @@ impl Capabilities { self.ambient } + pub fn ambient_mut(&mut self) -> &mut CapabilitiesFlags { + &mut self.ambient + } + pub fn bounding(&self) -> CapabilitiesFlags { self.bounding } + pub fn bounding_mut(&mut self) -> &mut CapabilitiesFlags { + &mut self.bounding + } + /// Checks if a capability is effective, as in if it can be used. pub fn is_capable(&self, cap: CapabilitiesFlags) -> bool { self.effective.contains(cap) diff --git a/src/arch/arm64/exceptions/syscall.rs b/src/arch/arm64/exceptions/syscall.rs index 33c2280..0f91e85 100644 --- a/src/arch/arm64/exceptions/syscall.rs +++ b/src/arch/arm64/exceptions/syscall.rs @@ -388,7 +388,7 @@ pub async fn handle_syscall() { 0xa0 => sys_uname(TUA::from_value(arg1 as _)).await, 0xa3 => Err(KernelError::InvalidValue), 0xa6 => sys_umask(arg1 as _).map_err(|e| match e {}), - 0xa7 => sys_prctl(arg1 as _, arg2).await, + 0xa7 => sys_prctl(arg1 as _, arg2, arg3).await, 0xa9 => sys_gettimeofday(TUA::from_value(arg1 as _), TUA::from_value(arg2 as _)).await, 0xac => sys_getpid().map_err(|e| match e {}), 0xad => sys_getppid().map_err(|e| match e {}), diff --git a/src/process/prctl.rs b/src/process/prctl.rs index 3837613..747cc5b 100644 --- a/src/process/prctl.rs +++ b/src/process/prctl.rs @@ -2,23 +2,55 @@ use crate::memory::uaccess::copy_to_user_slice; use crate::memory::uaccess::cstr::UserCStr; use crate::process::Comm; use crate::sched::current::current_task_shared; +use bitflags::Flags; use core::ffi::c_char; use libkernel::error::{KernelError, Result}; use libkernel::memory::address::TUA; +use libkernel::proc::caps::CapabilitiesFlags; const PR_CAPBSET_READ: i32 = 23; +const PR_CAPBSET_DROP: i32 = 24; const PR_SET_NAME: i32 = 15; const PR_GET_NAME: i32 = 16; -const CAP_MAX: usize = 40; +const PR_GET_SECUREBITS: i32 = 27; +const PR_GET_NO_NEW_PRIVS: i32 = 39; +const PR_CAP_AMBIENT: i32 = 47; -fn pr_read_capset(what: usize) -> Result { - // Validate the argument - if what > CAP_MAX { - return Err(KernelError::InvalidValue); +#[derive(Debug)] +enum AmbientCapOp { + IsSet = 1, + Raise = 2, + Lower = 3, + ClearAll = 4, +} + +impl TryFrom for AmbientCapOp { + type Error = KernelError; + + fn try_from(value: u64) -> Result { + match value { + 1 => Ok(AmbientCapOp::IsSet), + 2 => Ok(AmbientCapOp::Raise), + 3 => Ok(AmbientCapOp::Lower), + 4 => Ok(AmbientCapOp::ClearAll), + _ => Err(KernelError::InvalidValue), + } } +} - // Assume we have *all* the capabilities. - Ok(1) +fn pr_read_capbset(what: usize) -> Result { + let what = CapabilitiesFlags::from_bits(1u64 << what).ok_or(KernelError::InvalidValue)?; + let task = current_task_shared(); + let creds = task.creds.lock_save_irq(); + Ok(creds.caps.bounding().contains(what) as _) +} + +async fn pr_drop_capbset(what: usize) -> Result { + let what = CapabilitiesFlags::from_bits(1u64 << what).ok_or(KernelError::InvalidValue)?; + let task = current_task_shared(); + let mut creds = task.creds.lock_save_irq(); + creds.caps.bounding_mut().remove(what); + Ok(0) } async fn pr_get_name(str: TUA) -> Result { @@ -36,11 +68,42 @@ async fn pr_set_name(str: TUA) -> Result { Ok(0) } -pub async fn sys_prctl(op: i32, arg1: u64) -> Result { +async fn pr_cap_ambient(op: u64, arg1: u64) -> Result { + let op = AmbientCapOp::try_from(op)?; + let task = current_task_shared(); + match op { + AmbientCapOp::ClearAll => { + let mut creds = task.creds.lock_save_irq(); + creds.caps.ambient_mut().clear(); + Ok(0) + } + AmbientCapOp::IsSet => { + let what = + CapabilitiesFlags::from_bits(1u64 << arg1).ok_or(KernelError::InvalidValue)?; + let creds = task.creds.lock_save_irq(); + let is_set = creds.caps.ambient().contains(what); + Ok(is_set as _) + } + AmbientCapOp::Lower => { + let what = + CapabilitiesFlags::from_bits(1u64 << arg1).ok_or(KernelError::InvalidValue)?; + let mut creds = task.creds.lock_save_irq(); + creds.caps.ambient_mut().remove(what); + Ok(0) + } + op => todo!("prctl PR_CAP_AMBIENT op: {:?}", op), + } +} + +pub async fn sys_prctl(op: i32, arg1: u64, arg2: u64) -> Result { match op { PR_SET_NAME => pr_set_name(TUA::from_value(arg1 as usize)).await, PR_GET_NAME => pr_get_name(TUA::from_value(arg1 as usize)).await, - PR_CAPBSET_READ => pr_read_capset(arg1 as usize), + PR_CAPBSET_READ => pr_read_capbset(arg1 as usize), + PR_CAPBSET_DROP => pr_drop_capbset(arg1 as usize).await, + PR_GET_SECUREBITS => Ok(0), + PR_GET_NO_NEW_PRIVS => Ok(0), + PR_CAP_AMBIENT => pr_cap_ambient(arg1, arg2).await, _ => todo!("prctl op: {}", op), } }