kernel+libc: Add pledge support
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
apio 2023-08-12 21:38:25 +02:00
parent 0ae409ae22
commit e2a77bb3da
Signed by: apio
GPG Key ID: B8A7D06E42258954
31 changed files with 282 additions and 19 deletions

View File

@ -6,6 +6,8 @@
int main()
{
pledge("stdio rpath wpath cpath proc", nullptr);
int fd = shm_open("/shared", O_CREAT | O_RDWR, 0666);
if (fd < 0)
{

View File

@ -6,6 +6,7 @@ set(SOURCES
${HEADERS}
src/main.cpp
src/Log.cpp
src/Pledge.cpp
src/cxxabi.cpp
src/video/Framebuffer.cpp
src/video/TextConsole.cpp
@ -45,6 +46,7 @@ set(SOURCES
src/sys/socket.cpp
src/sys/poll.cpp
src/sys/alarm.cpp
src/sys/pledge.cpp
src/fs/VFS.cpp
src/fs/Pipe.cpp
src/fs/Mount.cpp

View File

@ -27,8 +27,8 @@ static void log_serial(LogLevel level, const char* format, va_list origin)
va_list ap;
va_copy(ap, origin);
const SafeScopeLock lock { g_serial_lock };
if (!lock.did_succeed()) return;
/*const SafeScopeLock lock { g_serial_lock };
if (!lock.did_succeed()) return;*/
Serial::printf("\x1b[%sm"
"%c"
@ -61,7 +61,7 @@ static void log_text_console(LogLevel level, const char* format, va_list origin)
va_list ap;
va_copy(ap, origin);
const ScopeLock lock { g_console_lock };
/*const ScopeLock lock { g_console_lock };*/
const u32 original_foreground = TextConsole::foreground();
const u32 original_background = TextConsole::background();

66
kernel/src/Pledge.cpp Normal file
View File

@ -0,0 +1,66 @@
#include "Pledge.h"
#include "Log.h"
#include "memory/MemoryManager.h"
static const char* promise_names[] = {
#define __enumerate(promise) #promise,
enumerate_promises(__enumerate)
#undef __enumerate
};
Result<void> check_pledge(Thread* thread, Promise promise)
{
// Thread has not called pledge().
if (thread->promises < 0) return {};
int mask = (1 << (int)promise);
if ((thread->promises & mask) != mask)
{
kerrorln("Pledge violation in thread %d! Has not pledged %s", thread->id, promise_names[(int)promise]);
if (thread->promises & (1 << (int)Promise::p_error)) return err(ENOSYS);
// Kill this thread with an uncatchable SIGABRT. For this, we reset the disposition of SIGABRT to the default
// (dump core). We could just kill the thread here and be done, but that discards anything on the current stack,
// which means that some destructors might not be called. Instead, leave the job to the next call of
// Thread::process_pending_signals().
thread->signal_handlers[SIGABRT - 1].sa_handler = SIG_DFL;
// If there are any other pending signals, they might be processed before SIGABRT. Avoid that by resetting the
// thread's pending signals.
thread->pending_signals = 0;
thread->send_signal(SIGABRT);
// This should never arrive to userspace.
return err(ENOSYS);
}
return {};
}
Result<int> parse_promises(u64 pledge)
{
if (!pledge) return -1;
auto text = TRY(MemoryManager::strdup_from_user(pledge));
if (text.is_empty()) return 0;
auto promises = TRY(text.split(" "));
int result = 0;
for (const auto& promise : promises)
{
for (int i = 0; i < (int)Promise::num_promises; i++)
{
if (promise.view() == promise_names[i])
{
result |= (1 << i);
goto found;
}
}
return err(EINVAL);
found:
continue;
}
return result;
}

19
kernel/src/Pledge.h Normal file
View File

@ -0,0 +1,19 @@
#pragma once
#include "thread/Thread.h"
#include <luna/Result.h>
#define enumerate_promises(_p) \
_p(stdio) _p(rpath) _p(wpath) _p(cpath) _p(fattr) _p(chown) _p(unix) _p(tty) _p(proc) _p(exec) _p(prot_exec) \
_p(id) _p(mount) _p(signal) _p(host) _p(error)
enum class Promise
{
#define __enumerate(promise) p_##promise,
enumerate_promises(__enumerate)
#undef __enumerate
num_promises,
};
Result<void> check_pledge(Thread* thread, Promise promise);
Result<int> parse_promises(u64 pledge);

View File

@ -1,5 +1,6 @@
#include "fs/devices/ConsoleDevice.h"
#include "Log.h"
#include "Pledge.h"
#include "fs/devices/DeviceRegistry.h"
#include "fs/devices/KeyboardDevice.h"
#include "memory/MemoryManager.h"
@ -199,6 +200,9 @@ void ConsoleDevice::process_key_event(u8 scancode)
Result<u64> ConsoleDevice::ioctl(int request, void* arg)
{
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_tty));
switch (request)
{
case TCGETS: {

View File

@ -1,3 +1,4 @@
#include "Pledge.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.h"
@ -7,6 +8,8 @@ Result<u64> sys_alarm(Registers*, SyscallArgs args)
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
u64 time_left = current->alarm_ticks_left;
current->alarm_ticks_left = seconds * 1000;

View File

@ -1,3 +1,4 @@
#include "Pledge.h"
#include "memory/MemoryManager.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.h"
@ -9,6 +10,8 @@ Result<u64> sys_chdir(Registers*, SyscallArgs args)
Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_rpath));
if (PathParser::is_absolute(path.view()))
{
SharedPtr<VFS::Inode> inode = TRY(VFS::resolve_path(path.chars(), current->auth));

View File

@ -1,6 +1,8 @@
#include "Pledge.h"
#include "arch/Timer.h"
#include "memory/MemoryManager.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.h"
#include <bits/clockid.h>
#include <bits/timespec.h>
@ -9,6 +11,10 @@ Result<u64> sys_clock_gettime(Registers*, SyscallArgs args)
clockid_t id = (clockid_t)args[0];
struct timespec* ts = (struct timespec*)args[1];
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
switch (id)
{
case CLOCK_MONOTONIC: {

View File

@ -1,4 +1,5 @@
#include "Log.h"
#include "Pledge.h"
#include "binfmt/BinaryFormat.h"
#include "fs/VFS.h"
#include "memory/MemoryManager.h"
@ -63,6 +64,8 @@ Result<u64> sys_execve(Registers* regs, SyscallArgs args)
auto current = Scheduler::current();
TRY(check_pledge(current, Promise::p_exec));
auto inode = TRY(VFS::resolve_path(path.chars(), current->auth, current->current_directory));
if (!VFS::can_execute(inode, current->auth)) return err(EACCES);
@ -115,6 +118,9 @@ Result<u64> sys_execve(Registers* regs, SyscallArgs args)
current->set_arguments(user_argc, user_argv, user_envc, user_envp);
current->promises = current->execpromises;
current->execpromises = -1;
memcpy(regs, &current->regs, sizeof(*regs));
for (int i = 0; i < NSIG; i++)
@ -133,6 +139,8 @@ Result<u64> sys_fork(Registers* regs, SyscallArgs)
{
auto current = Scheduler::current();
TRY(check_pledge(current, Promise::p_proc));
auto guard = make_scope_guard([current] { MMU::switch_page_directory(current->self_directory()); });
memcpy(&current->regs, regs, sizeof(*regs));
@ -152,6 +160,10 @@ Result<u64> sys_fork(Registers* regs, SyscallArgs)
thread->current_directory_path = move(current_directory_path);
thread->umask = current->umask;
thread->parent = current;
// TODO: Should promises be inherited across fork()? We're assuming yes, as they're already reset on exec (unless
// execpromises has been set). Couldn't find any suitable documentation from OpenBSD about this.
thread->promises = current->promises;
thread->execpromises = current->execpromises;
for (int i = 0; i < FD_MAX; i++) { thread->fd_table[i] = current->fd_table[i]; }

View File

@ -1,4 +1,5 @@
#include "Log.h"
#include "Pledge.h"
#include "fs/Pipe.h"
#include "fs/VFS.h"
#include "memory/MemoryManager.h"
@ -24,6 +25,8 @@ Result<u64> sys_read(Registers* regs, SyscallArgs args)
Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
auto& descriptor = *TRY(current->resolve_fd(fd));
if (!descriptor.is_readable()) return err(EBADF);
@ -65,6 +68,8 @@ Result<u64> sys_write(Registers*, SyscallArgs args)
Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
auto& descriptor = *TRY(current->resolve_fd(fd));
if (!descriptor.is_writable()) return err(EBADF);
@ -87,6 +92,8 @@ Result<u64> sys_lseek(Registers*, SyscallArgs args)
Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
auto& descriptor = *TRY(current->resolve_fd(fd));
if (descriptor.inode()->type() == VFS::InodeType::FIFO) return err(ESPIPE);
@ -117,6 +124,8 @@ Result<u64> sys_fcntl(Registers*, SyscallArgs args)
Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
auto& descriptor = *TRY(current->resolve_fd(fd));
bool is_cloexec = true;
@ -176,6 +185,7 @@ Result<u64> sys_isatty(Registers*, SyscallArgs args)
int fd = (int)args[0];
Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
auto& descriptor = *TRY(current->resolve_fd(fd));
return descriptor.inode()->isatty();
@ -188,6 +198,8 @@ Result<u64> sys_dup2(Registers*, SyscallArgs args)
Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
if (newfd < 0 || newfd >= FD_MAX) return err(EBADF);
auto descriptor = *TRY(current->resolve_fd(oldfd));
@ -206,6 +218,8 @@ Result<u64> sys_pipe(Registers*, SyscallArgs args)
Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
int rfd = TRY(current->allocate_fd(0));
int wfd = TRY(current->allocate_fd(rfd + 1));
@ -229,6 +243,8 @@ Result<u64> sys_umask(Registers*, SyscallArgs args)
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
mode_t old_umask = current->umask;
current->umask = new_umask & 0777;
@ -242,6 +258,7 @@ Result<u64> sys_truncate(Registers*, SyscallArgs args)
size_t length = (size_t)args[1];
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_wpath));
auto inode = TRY(VFS::resolve_path(path.chars(), current->auth, current->current_directory));
if (!VFS::can_write(inode, current->auth)) return err(EACCES);
@ -257,6 +274,7 @@ Result<u64> sys_ftruncate(Registers*, SyscallArgs args)
size_t length = (size_t)args[1];
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
auto description = TRY(current->resolve_fd(fd))->description;
if (!(description->flags & O_WRONLY)) return err(EBADF);
@ -273,6 +291,7 @@ Result<u64> sys_utimensat(Registers*, SyscallArgs args)
int flags = (int)args[3];
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_fattr));
auto inode = TRY(current->resolve_atfile(dirfd, path, flags & AT_EMPTY_PATH, !(flags & AT_SYMLINK_NOFOLLOW)));
struct timespec ktimes[2];

View File

@ -1,3 +1,4 @@
#include "Pledge.h"
#include "fs/VFS.h"
#include "memory/MemoryManager.h"
#include "sys/Syscall.h"
@ -11,6 +12,7 @@ Result<u64> sys_getdents(Registers*, SyscallArgs args)
usize count = (usize)args[2];
Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
auto& descriptor = *TRY(current->resolve_fd(fd));

View File

@ -1,3 +1,4 @@
#include "Pledge.h"
#include "memory/MemoryManager.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.h"
@ -5,41 +6,54 @@
Result<u64> sys_getpid(Registers*, SyscallArgs)
{
return Scheduler::current()->id;
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
return current->id;
}
Result<u64> sys_getppid(Registers*, SyscallArgs)
{
auto* parent = Scheduler::current()->parent;
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)
{
return Scheduler::current()->auth.uid;
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
return current->auth.uid;
}
Result<u64> sys_geteuid(Registers*, SyscallArgs)
{
return Scheduler::current()->auth.euid;
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
return current->auth.euid;
}
Result<u64> sys_getgid(Registers*, SyscallArgs)
{
return Scheduler::current()->auth.gid;
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
return current->auth.gid;
}
Result<u64> sys_getegid(Registers*, SyscallArgs)
{
return Scheduler::current()->auth.egid;
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];
Credentials& auth = Scheduler::current()->auth;
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_id));
Credentials& auth = current->auth;
if (auth.euid == 0)
{
@ -57,7 +71,9 @@ Result<u64> sys_seteuid(Registers*, SyscallArgs args)
{
u32 uid = (u32)args[0];
Credentials& auth = Scheduler::current()->auth;
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;
@ -69,7 +85,9 @@ Result<u64> sys_setgid(Registers*, SyscallArgs args)
{
u32 gid = (u32)args[0];
Credentials& auth = Scheduler::current()->auth;
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_id));
Credentials& auth = current->auth;
if (auth.euid == 0)
{
@ -87,7 +105,9 @@ Result<u64> sys_setegid(Registers*, SyscallArgs args)
{
u32 gid = (u32)args[0];
Credentials& auth = Scheduler::current()->auth;
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;
@ -101,6 +121,7 @@ Result<u64> sys_setpgid(Registers*, SyscallArgs args)
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;
@ -133,6 +154,7 @@ 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);
@ -150,6 +172,7 @@ Result<u64> sys_fchmodat(Registers*, SyscallArgs args)
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)));
@ -171,6 +194,7 @@ Result<u64> sys_fchownat(Registers*, SyscallArgs args)
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)));

View File

@ -1,4 +1,5 @@
#include "Log.h"
#include "Pledge.h"
#include "memory/MemoryManager.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.h"
@ -12,6 +13,7 @@ Result<u64> sys_unlinkat(Registers*, SyscallArgs args)
int flags = (int)args[2];
Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_cpath));
auto dirname = TRY(PathParser::dirname(path.view()));
auto basename = TRY(PathParser::basename(path.view()));
@ -44,6 +46,7 @@ Result<u64> sys_symlinkat(Registers*, SyscallArgs args)
if (target.is_empty()) return err(ENOENT);
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_cpath));
auto parent = TRY(PathParser::dirname(linkpath.view()));
@ -73,6 +76,7 @@ Result<u64> sys_readlinkat(Registers*, SyscallArgs args)
usize bufsiz = (usize)args[3];
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_rpath));
auto symlink = TRY(current->resolve_atfile(dirfd, path, true, false));
@ -98,6 +102,7 @@ Result<u64> sys_linkat(Registers*, SyscallArgs args)
int flags = (int)args[4];
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_cpath));
auto parent = TRY(PathParser::dirname(newpath.view()));

View File

@ -1,4 +1,5 @@
#include "Log.h"
#include "Pledge.h"
#include "fs/VFS.h"
#include "memory/MemoryManager.h"
#include "sys/Syscall.h"
@ -10,6 +11,7 @@ Result<u64> sys_mkdir(Registers*, SyscallArgs args)
mode_t mode = (mode_t)args[1];
Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_cpath));
auto inode =
TRY(VFS::create_directory(path.chars(), mode & ~current->umask, current->auth, current->current_directory));

View File

@ -1,4 +1,5 @@
#include "Log.h"
#include "Pledge.h"
#include "arch/MMU.h"
#include "memory/MemoryManager.h"
#include "memory/SharedMemory.h"
@ -22,6 +23,8 @@ Result<u64> sys_mmap(Registers*, SyscallArgs args)
if (params.flags < 0) return err(EINVAL);
Thread* current = Scheduler::current();
if (params.prot & PROT_EXEC) TRY(check_pledge(current, Promise::p_prot_exec));
TRY(check_pledge(current, Promise::p_stdio));
SharedPtr<OpenFileDescription> description;
if ((params.flags & MAP_ANONYMOUS) != MAP_ANONYMOUS)
@ -94,6 +97,7 @@ Result<u64> sys_munmap(Registers*, SyscallArgs args)
if (!is_aligned<ARCH_PAGE_SIZE>(address)) return err(EINVAL);
Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
bool ok = TRY(current->address_space->free_region(address, ceil_div(size, ARCH_PAGE_SIZE)));
@ -118,6 +122,7 @@ Result<u64> sys_msync(Registers*, SyscallArgs args)
if (!is_aligned<ARCH_PAGE_SIZE>(address)) return err(EINVAL);
Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
TRY(current->address_space->sync_regions(address, ceil_div(size, ARCH_PAGE_SIZE)));

View File

@ -1,3 +1,4 @@
#include "Pledge.h"
#include "fs/VFS.h"
#include "fs/ext2/FileSystem.h"
#include "fs/tmpfs/FileSystem.h"
@ -12,6 +13,7 @@ Result<u64> sys_mount(Registers*, SyscallArgs args)
auto source = TRY(MemoryManager::strdup_from_user(args[2]));
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_mount));
if (current->auth.euid != 0) return err(EPERM);
auto get_source = [current, &source]() -> Result<SharedPtr<Device>> {
@ -44,6 +46,7 @@ Result<u64> sys_umount(Registers*, SyscallArgs args)
auto target = TRY(MemoryManager::strdup_from_user(args[0]));
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_mount));
if (current->auth.euid != 0) return err(EPERM);
TRY(VFS::umount(target.chars(), current->auth, current->current_directory));
@ -57,6 +60,7 @@ Result<u64> sys_pivot_root(Registers*, SyscallArgs args)
auto put_old = TRY(MemoryManager::strdup_from_user(args[1]));
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_mount));
if (current->auth.euid != 0) return err(EPERM);
TRY(VFS::pivot_root(new_root.chars(), put_old.chars(), current->current_directory));

View File

@ -1,4 +1,5 @@
#include "Log.h"
#include "Pledge.h"
#include "fs/VFS.h"
#include "memory/MemoryManager.h"
#include "sys/Syscall.h"
@ -23,6 +24,12 @@ Result<u64> sys_openat(Registers*, SyscallArgs args)
// Caller did not pass either O_RDONLY, O_WRONLY or O_RDWR
if ((flags & O_RDWR) == 0) { return err(EINVAL); }
if (flags & O_RDONLY) TRY(check_pledge(current, Promise::p_rpath));
else if (flags & O_WRONLY)
TRY(check_pledge(current, Promise::p_wpath));
if (flags & O_CREAT) TRY(check_pledge(current, Promise::p_cpath));
if (flags & O_TMPFILE)
{
if (!(flags & O_WRONLY)) return err(EINVAL);
@ -99,6 +106,7 @@ Result<u64> sys_close(Registers*, SyscallArgs args)
if (fd < 0 || fd >= FD_MAX) return err(EBADF);
Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
Option<FileDescriptor>& descriptor = current->fd_table[fd];

40
kernel/src/sys/pledge.cpp Normal file
View File

@ -0,0 +1,40 @@
#include "Pledge.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.h"
Result<u64> sys_pledge(Registers*, SyscallArgs args)
{
int promises = TRY(parse_promises(args[0]));
int execpromises = TRY(parse_promises(args[1]));
auto* current = Scheduler::current();
if (promises >= 0)
{
int actual_promises = promises & ~(1 << (int)Promise::p_error);
int old_promises = current->promises & ~(1 << (int)Promise::p_error);
if (actual_promises & ~old_promises)
{
if (current->promises & ~(1 << (int)Promise::p_error)) return 0;
return err(EPERM);
}
}
if (execpromises >= 0)
{
int actual_execpromises = execpromises & ~(1 << (int)Promise::p_error);
int old_execpromises = current->execpromises & ~(1 << (int)Promise::p_error);
if (actual_execpromises & ~old_execpromises)
{
if (current->execpromises & ~(1 << (int)Promise::p_error)) return 0;
return err(EPERM);
}
}
if (promises >= 0) current->promises = promises;
if (execpromises >= 0) current->execpromises = execpromises;
return 0;
}

View File

@ -1,4 +1,5 @@
#include "Log.h"
#include "Pledge.h"
#include "fs/VFS.h"
#include "memory/MemoryManager.h"
#include "sys/Syscall.h"
@ -18,6 +19,7 @@ Result<u64> sys_poll(Registers*, SyscallArgs args)
Vector<SharedPtr<VFS::Inode>> inodes;
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
for (nfds_t i = 0; i < nfds; i++)
{

View File

@ -1,3 +1,4 @@
#include "Pledge.h"
#include "memory/MemoryManager.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.h"
@ -14,6 +15,9 @@ Result<u64> sys_pstat(Registers*, SyscallArgs args)
pid_t pid = (pid_t)args[0];
struct process* ps = (struct process*)args[1];
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_proc));
// If pid == -1, return the PID of the last spawned thread.
if (pid == -1) return g_threads.expect_last()->id;

View File

@ -1,4 +1,5 @@
#include "Log.h"
#include "Pledge.h"
#include "memory/MemoryManager.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.h"
@ -18,6 +19,7 @@ Result<u64> sys_sigreturn(Registers* regs, SyscallArgs)
Result<u64> sys_sigaction(Registers*, SyscallArgs args)
{
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_signal));
int signo = (int)args[0];
const struct sigaction* act = (const struct sigaction*)args[1];
@ -47,6 +49,7 @@ Result<u64> sys_sigaction(Registers*, SyscallArgs args)
Result<u64> sys_kill(Registers*, SyscallArgs args)
{
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_proc));
pid_t pid = (pid_t)args[0];
int signo = (int)args[1];
@ -68,6 +71,7 @@ Result<u64> sys_kill(Registers*, SyscallArgs args)
Result<u64> sys_sigprocmask(Registers*, SyscallArgs args)
{
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_signal));
int how = (int)args[0];
const sigset_t* set = (const sigset_t*)args[1];

View File

@ -1,4 +1,5 @@
#include "net/Socket.h"
#include "Pledge.h"
#include "memory/MemoryManager.h"
#include "net/UnixSocket.h"
#include "sys/Syscall.h"
@ -14,9 +15,10 @@ Result<u64> sys_socket(Registers*, SyscallArgs args)
if (type != SOCK_STREAM) return err(EPROTOTYPE);
if (domain != AF_UNIX) return err(EAFNOSUPPORT);
auto socket = TRY(make_shared<UnixSocket>());
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_unix));
auto socket = TRY(make_shared<UnixSocket>());
int fd = TRY(current->allocate_fd(0));
@ -36,6 +38,7 @@ Result<u64> sys_bind(Registers*, SyscallArgs args)
if (!MemoryManager::copy_from_user(addr, &storage, addrlen)) return err(EFAULT);
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_unix));
auto inode = TRY(current->resolve_fd(sockfd))->inode();
@ -59,6 +62,7 @@ Result<u64> sys_connect(Registers* regs, SyscallArgs args)
if (!MemoryManager::copy_from_user(addr, &storage, addrlen)) return err(EFAULT);
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_unix));
auto description = TRY(current->resolve_fd(sockfd))->description;
@ -77,6 +81,7 @@ Result<u64> sys_listen(Registers*, SyscallArgs args)
int backlog = (int)args[1];
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_unix));
auto inode = TRY(current->resolve_fd(sockfd))->inode();
@ -104,6 +109,7 @@ Result<u64> sys_accept(Registers* regs, SyscallArgs args)
}
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_unix));
auto description = TRY(current->resolve_fd(sockfd))->description;

View File

@ -1,3 +1,4 @@
#include "Pledge.h"
#include "memory/MemoryManager.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.h"
@ -33,6 +34,7 @@ Result<u64> sys_fstatat(Registers*, SyscallArgs args)
int flags = (int)args[3];
Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_rpath));
auto inode = TRY(current->resolve_atfile(dirfd, path, flags & AT_EMPTY_PATH, !(flags & AT_SYMLINK_NOFOLLOW)));
@ -67,6 +69,7 @@ Result<u64> sys_faccessat(Registers*, SyscallArgs args)
Credentials creds;
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_rpath));
if (flags & AT_EACCESS) creds = current->auth;
else

View File

@ -1,4 +1,5 @@
#include "Log.h"
#include "Pledge.h"
#include "arch/CPU.h"
#include "config.h"
#include "memory/MemoryManager.h"
@ -40,6 +41,7 @@ Result<u64> sys_sethostname(Registers*, SyscallArgs args)
usize length = (usize)args[1];
Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_host));
if (current->auth.euid != 0) return err(EPERM);
if (length >= _UTSNAME_LENGTH) return err(EINVAL);

View File

@ -1,3 +1,4 @@
#include "Pledge.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.h"
#include <sys/types.h>
@ -6,12 +7,13 @@ Result<u64> sys_usleep(Registers*, SyscallArgs args)
{
useconds_t us = (useconds_t)args[0];
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
// FIXME: Allow usleep() to use a more precise resolution.
if (us < 1000) return 0;
kernel_sleep(us / 1000);
auto* current = Scheduler::current();
return current->sleep_ticks_left;
}

View File

@ -1,4 +1,5 @@
#include "Log.h"
#include "Pledge.h"
#include "memory/MemoryManager.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.h"
@ -11,6 +12,7 @@ Result<u64> sys_waitpid(Registers* regs, SyscallArgs args)
int options = (int)args[2];
Thread* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
Thread* thread;

View File

@ -89,6 +89,9 @@ struct Thread : public LinkedListNode<Thread>
u64 sleep_ticks_left;
u64 alarm_ticks_left { 0 };
int promises { -1 };
int execpromises { -1 };
Stack stack;
Stack kernel_stack;

View File

@ -196,6 +196,9 @@ extern "C"
/* Schedule an alarm signal. */
unsigned int alarm(unsigned int seconds);
/* Restrict system operations. */
int pledge(const char* promises, const char* execpromises);
#ifdef __cplusplus
}
#endif

View File

@ -521,4 +521,10 @@ extern "C"
{
return (unsigned int)syscall(SYS_alarm, seconds);
}
int pledge(const char* promises, const char* execpromises)
{
long rc = syscall(SYS_pledge, promises, execpromises);
__errno_return(rc, int);
}
}

View File

@ -8,7 +8,7 @@
_e(umount) _e(pstat) _e(getrusage) _e(symlinkat) _e(readlinkat) _e(umask) _e(linkat) _e(faccessat) \
_e(pivot_root) _e(sigreturn) _e(sigaction) _e(kill) _e(sigprocmask) _e(setpgid) _e(isatty) \
_e(getpgid) _e(socket) _e(bind) _e(connect) _e(listen) _e(accept) _e(poll) _e(msync) \
_e(truncate) _e(ftruncate) _e(utimensat) _e(alarm)
_e(truncate) _e(ftruncate) _e(utimensat) _e(alarm) _e(pledge)
enum Syscalls
{