From a7a1c366930965a893faabdff4c6ee71efb00a90 Mon Sep 17 00:00:00 2001 From: Ashwin Naren Date: Sat, 4 Apr 2026 20:34:47 -0700 Subject: [PATCH] implement setuid, setgid, setreuid, setregid, setresuid, setresgid --- etc/syscalls_linux_aarch64.md | 12 +- src/arch/arm64/exceptions/syscall.rs | 9 +- src/process/creds.rs | 228 ++++++++++++++++++++++++++- 3 files changed, 240 insertions(+), 9 deletions(-) diff --git a/etc/syscalls_linux_aarch64.md b/etc/syscalls_linux_aarch64.md index 698e6610..56ee2383 100644 --- a/etc/syscalls_linux_aarch64.md +++ b/etc/syscalls_linux_aarch64.md @@ -143,13 +143,13 @@ | 0x8c (140) | setpriority | (int which, int who, int niceval) | __arm64_sys_setpriority | false | | 0x8d (141) | getpriority | (int which, int who) | __arm64_sys_getpriority | false | | 0x8e (142) | reboot | (int magic1, int magic2, unsigned int cmd, void *arg) | __arm64_sys_reboot | partially | -| 0x8f (143) | setregid | (gid_t rgid, gid_t egid) | __arm64_sys_setregid | false | -| 0x90 (144) | setgid | (gid_t gid) | __arm64_sys_setgid | false | -| 0x91 (145) | setreuid | (uid_t ruid, uid_t euid) | __arm64_sys_setreuid | false | -| 0x92 (146) | setuid | (uid_t uid) | __arm64_sys_setuid | false | -| 0x93 (147) | setresuid | (uid_t ruid, uid_t euid, uid_t suid) | __arm64_sys_setresuid | false | +| 0x8f (143) | setregid | (gid_t rgid, gid_t egid) | __arm64_sys_setregid | true | +| 0x90 (144) | setgid | (gid_t gid) | __arm64_sys_setgid | true | +| 0x91 (145) | setreuid | (uid_t ruid, uid_t euid) | __arm64_sys_setreuid | true | +| 0x92 (146) | setuid | (uid_t uid) | __arm64_sys_setuid | true | +| 0x93 (147) | setresuid | (uid_t ruid, uid_t euid, uid_t suid) | __arm64_sys_setresuid | true | | 0x94 (148) | getresuid | (uid_t *ruidp, uid_t *euidp, uid_t *suidp) | __arm64_sys_getresuid | true | -| 0x95 (149) | setresgid | (gid_t rgid, gid_t egid, gid_t sgid) | __arm64_sys_setresgid | false | +| 0x95 (149) | setresgid | (gid_t rgid, gid_t egid, gid_t sgid) | __arm64_sys_setresgid | true | | 0x96 (150) | getresgid | (gid_t *rgidp, gid_t *egidp, gid_t *sgidp) | __arm64_sys_getresgid | true | | 0x97 (151) | setfsuid | (uid_t uid) | __arm64_sys_setfsuid | false | | 0x98 (152) | setfsgid | (gid_t gid) | __arm64_sys_setfsgid | false | diff --git a/src/arch/arm64/exceptions/syscall.rs b/src/arch/arm64/exceptions/syscall.rs index bd93a222..4ef21fb4 100644 --- a/src/arch/arm64/exceptions/syscall.rs +++ b/src/arch/arm64/exceptions/syscall.rs @@ -71,7 +71,8 @@ use crate::{ clone::sys_clone, creds::{ sys_getegid, sys_geteuid, sys_getgid, sys_getresgid, sys_getresuid, sys_getsid, - sys_gettid, sys_getuid, sys_setfsgid, sys_setfsuid, sys_setsid, + sys_gettid, sys_getuid, sys_setfsgid, sys_setfsuid, sys_setgid, sys_setregid, + sys_setresgid, sys_setresuid, sys_setreuid, sys_setsid, sys_setuid, }, exec::sys_execve, exit::{sys_exit, sys_exit_group}, @@ -537,6 +538,11 @@ pub async fn handle_syscall(mut ctx: ProcessCtx) { return; } 0x8e => sys_reboot(&ctx, arg1 as _, arg2 as _, arg3 as _, arg4 as _).await, + 0x8f => sys_setregid(&ctx, arg1 as _, arg2 as _), + 0x90 => sys_setgid(&ctx, arg1 as _), + 0x91 => sys_setreuid(&ctx, arg1 as _, arg2 as _), + 0x92 => sys_setuid(&ctx, arg1 as _), + 0x93 => sys_setresuid(&ctx, arg1 as _, arg2 as _, arg3 as _), 0x94 => { sys_getresuid( &ctx, @@ -546,6 +552,7 @@ pub async fn handle_syscall(mut ctx: ProcessCtx) { ) .await } + 0x95 => sys_setresgid(&ctx, arg1 as _, arg2 as _, arg3 as _), 0x96 => { sys_getresgid( &ctx, diff --git a/src/process/creds.rs b/src/process/creds.rs index af62d8d1..5e635672 100644 --- a/src/process/creds.rs +++ b/src/process/creds.rs @@ -6,10 +6,10 @@ use crate::{ sched::syscall_ctx::ProcessCtx, }; use libkernel::{ - error::Result, + error::{KernelError, Result}, memory::address::TUA, proc::{ - caps::Capabilities, + caps::{Capabilities, CapabilitiesFlags}, ids::{Gid, Uid}, }, }; @@ -94,6 +94,230 @@ pub fn sys_getegid(ctx: &ProcessCtx) -> core::result::Result Ok(gid as _) } +pub fn sys_setuid(ctx: &ProcessCtx, uid: usize) -> Result { + let mut creds = ctx.shared().creds.lock_save_irq(); + let new_uid = Uid::new(uid as u32); + + if creds.caps.is_capable(CapabilitiesFlags::CAP_SETUID) { + creds.uid = new_uid; + creds.euid = new_uid; + creds.suid = new_uid; + } else { + if new_uid == creds.uid || new_uid == creds.suid { + creds.euid = new_uid; + } else { + return Err(KernelError::NotPermitted); + } + } + + Ok(0) +} + +pub fn sys_setgid(ctx: &ProcessCtx, gid: usize) -> Result { + let mut creds = ctx.shared().creds.lock_save_irq(); + let new_gid = Gid::new(gid as u32); + + if creds.caps.is_capable(CapabilitiesFlags::CAP_SETGID) { + creds.gid = new_gid; + creds.egid = new_gid; + creds.sgid = new_gid; + } else { + if new_gid == creds.gid || new_gid == creds.sgid { + creds.egid = new_gid; + } else { + return Err(KernelError::NotPermitted); + } + } + + Ok(0) +} + +pub fn sys_setreuid(ctx: &ProcessCtx, ruid: usize, euid: usize) -> Result { + let mut creds = ctx.shared().creds.lock_save_irq(); + let new_ruid = if ruid == usize::MAX { + creds.uid + } else { + Uid::new(ruid as u32) + }; + let new_euid = if euid == usize::MAX { + creds.euid + } else { + Uid::new(euid as u32) + }; + + let capable = creds.caps.is_capable(CapabilitiesFlags::CAP_SETUID); + + if !capable { + if ruid != usize::MAX + && new_ruid != creds.uid + && new_ruid != creds.euid + && new_ruid != creds.suid + { + return Err(KernelError::NotPermitted); + } + if euid != usize::MAX + && new_euid != creds.uid + && new_euid != creds.euid + && new_euid != creds.suid + { + return Err(KernelError::NotPermitted); + } + } + + if ruid != usize::MAX || (euid != usize::MAX && new_euid != creds.uid) { + creds.suid = new_euid; + } + + creds.uid = new_ruid; + creds.euid = new_euid; + + Ok(0) +} + +pub fn sys_setregid(ctx: &ProcessCtx, rgid: usize, egid: usize) -> Result { + let mut creds = ctx.shared().creds.lock_save_irq(); + let new_rgid = if rgid == usize::MAX { + creds.gid + } else { + Gid::new(rgid as u32) + }; + let new_egid = if egid == usize::MAX { + creds.egid + } else { + Gid::new(egid as u32) + }; + + let capable = creds.caps.is_capable(CapabilitiesFlags::CAP_SETGID); + + if !capable { + if rgid != usize::MAX + && new_rgid != creds.gid + && new_rgid != creds.egid + && new_rgid != creds.sgid + { + return Err(KernelError::NotPermitted); + } + if egid != usize::MAX + && new_egid != creds.gid + && new_egid != creds.egid + && new_egid != creds.sgid + { + return Err(KernelError::NotPermitted); + } + } + + if rgid != usize::MAX || (egid != usize::MAX && new_egid != creds.gid) { + creds.sgid = new_egid; + } + + creds.gid = new_rgid; + creds.egid = new_egid; + + Ok(0) +} + +pub fn sys_setresuid(ctx: &ProcessCtx, ruid: usize, euid: usize, suid: usize) -> Result { + let mut creds = ctx.shared().creds.lock_save_irq(); + let new_ruid = if ruid == usize::MAX { + creds.uid + } else { + Uid::new(ruid as u32) + }; + let new_euid = if euid == usize::MAX { + creds.euid + } else { + Uid::new(euid as u32) + }; + let new_suid = if suid == usize::MAX { + creds.suid + } else { + Uid::new(suid as u32) + }; + + let capable = creds.caps.is_capable(CapabilitiesFlags::CAP_SETUID); + + if !capable { + if ruid != usize::MAX + && new_ruid != creds.uid + && new_ruid != creds.euid + && new_ruid != creds.suid + { + return Err(KernelError::NotPermitted); + } + if euid != usize::MAX + && new_euid != creds.uid + && new_euid != creds.euid + && new_euid != creds.suid + { + return Err(KernelError::NotPermitted); + } + if suid != usize::MAX + && new_suid != creds.uid + && new_suid != creds.euid + && new_suid != creds.suid + { + return Err(KernelError::NotPermitted); + } + } + + creds.uid = new_ruid; + creds.euid = new_euid; + creds.suid = new_suid; + + Ok(0) +} + +pub fn sys_setresgid(ctx: &ProcessCtx, rgid: usize, egid: usize, sgid: usize) -> Result { + let mut creds = ctx.shared().creds.lock_save_irq(); + let new_rgid = if rgid == usize::MAX { + creds.gid + } else { + Gid::new(rgid as u32) + }; + let new_egid = if egid == usize::MAX { + creds.egid + } else { + Gid::new(egid as u32) + }; + let new_sgid = if sgid == usize::MAX { + creds.sgid + } else { + Gid::new(sgid as u32) + }; + + let capable = creds.caps.is_capable(CapabilitiesFlags::CAP_SETGID); + + if !capable { + if rgid != usize::MAX + && new_rgid != creds.gid + && new_rgid != creds.egid + && new_rgid != creds.sgid + { + return Err(KernelError::NotPermitted); + } + if egid != usize::MAX + && new_egid != creds.gid + && new_egid != creds.egid + && new_egid != creds.sgid + { + return Err(KernelError::NotPermitted); + } + if sgid != usize::MAX + && new_sgid != creds.gid + && new_sgid != creds.egid + && new_sgid != creds.sgid + { + return Err(KernelError::NotPermitted); + } + } + + creds.gid = new_rgid; + creds.egid = new_egid; + creds.sgid = new_sgid; + + Ok(0) +} + pub fn sys_setfsuid(ctx: &ProcessCtx, _new_id: usize) -> core::result::Result { // Return the uid. This syscall is deprecated. sys_getuid(ctx)