#include "memory/MemoryManager.h" #include "sys/Syscall.h" #include "thread/Scheduler.h" #include Result sys_getpid(Registers*, SyscallArgs) { return Scheduler::current()->id; } Result sys_getppid(Registers*, SyscallArgs) { auto* parent = Scheduler::current()->parent; return parent ? parent->id : 0; } Result sys_getuid(Registers*, SyscallArgs) { return Scheduler::current()->auth.uid; } Result sys_geteuid(Registers*, SyscallArgs) { return Scheduler::current()->auth.euid; } Result sys_getgid(Registers*, SyscallArgs) { return Scheduler::current()->auth.gid; } Result sys_getegid(Registers*, SyscallArgs) { return Scheduler::current()->auth.egid; } Result sys_setuid(Registers*, SyscallArgs args) { u32 uid = (u32)args[0]; Credentials& auth = Scheduler::current()->auth; if (auth.euid == 0) { auth.uid = auth.euid = auth.suid = uid; return 0; } if (uid != auth.uid && uid != auth.suid) return err(EPERM); auth.euid = uid; return 0; } Result sys_seteuid(Registers*, SyscallArgs args) { u32 uid = (u32)args[0]; Credentials& auth = Scheduler::current()->auth; if (auth.euid != 0 && uid != auth.uid && uid != auth.suid) return err(EPERM); auth.euid = uid; return 0; } Result sys_setgid(Registers*, SyscallArgs args) { u32 gid = (u32)args[0]; Credentials& auth = Scheduler::current()->auth; if (auth.euid == 0) { auth.gid = auth.egid = auth.sgid = gid; return 0; } if (gid != auth.gid && gid != auth.sgid) return err(EPERM); auth.egid = gid; return 0; } Result sys_setegid(Registers*, SyscallArgs args) { u32 gid = (u32)args[0]; Credentials& auth = Scheduler::current()->auth; if (auth.euid != 0 && gid != auth.gid && gid != auth.sgid) return err(EPERM); auth.egid = gid; return 0; } Result sys_setpgid(Registers*, SyscallArgs args) { pid_t pid = (pid_t)args[0]; pid_t pgid = (pid_t)args[1]; auto* current = Scheduler::current(); if (pid == 0) pid = current->id; if (pgid == 0) pgid = current->id; if (pgid < 0) return err(EINVAL); auto* thread = TRY(Result::from_option(Scheduler::find_by_pid(pid), ESRCH)); if (thread != current && thread->parent != current) return err(ESRCH); // FIXME: Weird session stuff, we don't have that currently. if (thread->has_called_exec) return err(EPERM); if (pgid != current->id) { bool pgid_exists = false; Scheduler::for_each_in_process_group(pgid, [&pgid_exists](Thread*) { pgid_exists = true; return false; }); if (!pgid_exists) return err(EPERM); } thread->pgid = (u64)pgid; return 0; } Result sys_getpgid(Registers*, SyscallArgs args) { pid_t pid = (pid_t)args[0]; auto* current = Scheduler::current(); if (pid == 0) pid = current->id; if (pid < 0) return err(EINVAL); auto* thread = TRY(Result::from_option(Scheduler::find_by_pid(pid), ESRCH)); return (u64)thread->pgid; } Result sys_fchmodat(Registers*, SyscallArgs args) { int dirfd = (int)args[0]; auto path = TRY(MemoryManager::strdup_from_user(args[1])); mode_t mode = (mode_t)args[2]; int flags = (int)args[3]; auto* current = Scheduler::current(); auto inode = TRY(current->resolve_atfile(dirfd, path, flags & AT_EMPTY_PATH, !(flags & AT_SYMLINK_NOFOLLOW))); if (current->auth.euid != 0 && current->auth.euid != inode->uid()) return err(EPERM); TRY(inode->chmod(mode)); return 0; } Result sys_fchownat(Registers*, SyscallArgs args) { int dirfd = (int)args[0]; auto path = TRY(MemoryManager::strdup_from_user(args[1])); u32 uid = (u32)args[2]; u32 gid = (u32)args[3]; int flags = (int)args[4]; auto* current = Scheduler::current(); auto inode = TRY(current->resolve_atfile(dirfd, path, flags & AT_EMPTY_PATH, !(flags & AT_SYMLINK_NOFOLLOW))); if (current->auth.euid != 0) return err(EPERM); TRY(inode->chown(uid == (u32)-1 ? inode->uid() : uid, gid == (u32)-1 ? inode->gid() : gid)); return 0; }