Luna/kernel/src/sys/id.cpp
apio e2a77bb3da
Some checks failed
continuous-integration/drone/push Build is failing
kernel+libc: Add pledge support
2023-08-12 21:38:25 +02:00

210 lines
5.3 KiB
C++

#include "Pledge.h"
#include "memory/MemoryManager.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.h"
#include <bits/atfile.h>
Result<u64> sys_getpid(Registers*, SyscallArgs)
{
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
return current->id;
}
Result<u64> sys_getppid(Registers*, SyscallArgs)
{
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
auto* parent = current->parent;
return parent ? parent->id : 0;
}
Result<u64> sys_getuid(Registers*, SyscallArgs)
{
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
return current->auth.uid;
}
Result<u64> sys_geteuid(Registers*, SyscallArgs)
{
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
return current->auth.euid;
}
Result<u64> sys_getgid(Registers*, SyscallArgs)
{
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
return current->auth.gid;
}
Result<u64> sys_getegid(Registers*, SyscallArgs)
{
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
return current->auth.egid;
}
Result<u64> sys_setuid(Registers*, SyscallArgs args)
{
u32 uid = (u32)args[0];
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_id));
Credentials& auth = 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<u64> sys_seteuid(Registers*, SyscallArgs args)
{
u32 uid = (u32)args[0];
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_id));
Credentials& auth = current->auth;
if (auth.euid != 0 && uid != auth.uid && uid != auth.suid) return err(EPERM);
auth.euid = uid;
return 0;
}
Result<u64> sys_setgid(Registers*, SyscallArgs args)
{
u32 gid = (u32)args[0];
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_id));
Credentials& auth = 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<u64> sys_setegid(Registers*, SyscallArgs args)
{
u32 gid = (u32)args[0];
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_id));
Credentials& auth = current->auth;
if (auth.euid != 0 && gid != auth.gid && gid != auth.sgid) return err(EPERM);
auth.egid = gid;
return 0;
}
Result<u64> sys_setpgid(Registers*, SyscallArgs args)
{
pid_t pid = (pid_t)args[0];
pid_t pgid = (pid_t)args[1];
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_proc));
if (pid == 0) pid = current->id;
if (pgid == 0) pgid = current->id;
if (pgid < 0) return err(EINVAL);
auto* thread = TRY(Result<Thread*>::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<u64> sys_getpgid(Registers*, SyscallArgs args)
{
pid_t pid = (pid_t)args[0];
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
if (pid == 0) pid = current->id;
if (pid < 0) return err(EINVAL);
auto* thread = TRY(Result<Thread*>::from_option(Scheduler::find_by_pid(pid), ESRCH));
return (u64)thread->pgid;
}
Result<u64> 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();
TRY(check_pledge(current, Promise::p_wpath));
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->metadata().uid) return err(EPERM);
auto metadata = inode->metadata();
metadata.mode = mode;
TRY(inode->set_metadata(metadata));
return 0;
}
Result<u64> sys_fchownat(Registers*, SyscallArgs args)
{
int dirfd = (int)args[0];
auto path = TRY(MemoryManager::strdup_from_user(args[1]));
uid_t uid = (u32)args[2];
gid_t gid = (u32)args[3];
int flags = (int)args[4];
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_chown));
auto inode = TRY(current->resolve_atfile(dirfd, path, flags & AT_EMPTY_PATH, !(flags & AT_SYMLINK_NOFOLLOW)));
if (current->auth.euid != 0) return err(EPERM);
auto metadata = inode->metadata();
if (uid != (uid_t)-1) metadata.uid = uid;
if (gid != (gid_t)-1) metadata.gid = gid;
TRY(inode->set_metadata(metadata));
return 0;
}