use crate::cap::cnode; use crate::cap::object::ObjectTag; use crate::cap::ops; use crate::cap::pool::POOL; use crate::cap::table::Rights; use crate::error::KernelError; use crate::proc::PROCESSES; use crate::proc::context::CpuContext; use crate::syscall::{SyscallResult, try_syscall}; pub fn sys_cap_derive(ctx: &mut CpuContext) { let src_addr = ctx.rdi; let dest_addr = ctx.rsi; let rights_raw = try_syscall!(ctx, super::u16_from_reg(ctx.rdx)); let rights_mask = Rights::from_bits(rights_raw); let pid = crate::arch::syscall::current_pid(); let ptable = PROCESSES.lock(); let (cnode_id, cnode_gen, depth) = try_syscall!(ctx, cnode::cnode_coords(pid, &ptable)); let mut pool = POOL.lock_after(&ptable); ctx.rax = match ops::derive_via_cnode(&mut pool, cnode_id, cnode_gen, src_addr, dest_addr, depth, rights_mask) { Ok(()) => SyscallResult::ok().raw(), Err(e) => SyscallResult::error(e).raw(), }; } pub fn sys_cap_revoke(ctx: &mut CpuContext) { let address = ctx.rdi; let pid = crate::arch::syscall::current_pid(); let mut ptable = PROCESSES.lock(); if ptable.get(pid).is_none() { ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw(); return; } ctx.rax = match ops::revoke_via_cnode(pid, address, &mut ptable) { Ok(()) => SyscallResult::ok().raw(), Err(e) => SyscallResult::error(e).raw(), }; } pub fn sys_cap_identify(ctx: &mut CpuContext) { let address = ctx.rdi; let pid = crate::arch::syscall::current_pid(); let ptable = PROCESSES.lock(); let (cnode_id, cnode_gen, depth) = try_syscall!(ctx, cnode::cnode_coords(pid, &ptable)); let pool = POOL.lock_after(&ptable); match ops::identify_via_cnode(&pool, cnode_id, cnode_gen, address, depth) { Ok((tag, rights)) => { ctx.rdx = rights.bits() as u64; ctx.rax = tag as u8 as u64; } Err(e) => ctx.rax = SyscallResult::error(e).raw(), } } pub fn sys_cap_grant(ctx: &mut CpuContext) { let src_addr = ctx.rdi; let proc_cap_addr = ctx.rsi; let dest_addr = ctx.rdx; let rights_mask = match super::u16_from_reg(ctx.r10) { Ok(v) => Rights::from_bits(v), Err(e) => { ctx.rax = SyscallResult::error(e).raw(); return; } }; let pid = crate::arch::syscall::current_pid(); let ptable = PROCESSES.lock(); let (child_pid, cap_to_grant) = { let pool = POOL.lock_after(&ptable); let proc_cap = try_syscall!( ctx, cnode::resolve_caller_validate( pid, proc_cap_addr, ObjectTag::Process, Rights::WRITE, &ptable, &pool, ) ); let child_pid = try_syscall!(ctx, ops::resolve_process_cap(&proc_cap, &pool)); let src_cap = try_syscall!( ctx, cnode::resolve_caller_read(pid, src_addr, &ptable, &pool) ); if !src_cap.rights().contains(Rights::GRANT) { ctx.rax = SyscallResult::error(KernelError::InsufficientRights).raw(); return; } let granted = src_cap.with_rights(src_cap.rights() & rights_mask); (child_pid, granted) }; if ptable.get(child_pid).is_none() { ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw(); return; } let mut pool = POOL.lock_after(&ptable); if let Err(e) = pool.inc_ref(cap_to_grant.object_id(), cap_to_grant.generation()) { ctx.rax = SyscallResult::error(e).raw(); return; } ctx.rax = match cnode::resolve_caller_insert(child_pid, dest_addr, cap_to_grant, &ptable, &pool) { Ok(()) => SyscallResult::ok().raw(), Err(e) => { pool.dec_ref(cap_to_grant.object_id(), cap_to_grant.generation()); SyscallResult::error(e).raw() } }; }