diff --git a/libos/CMakeLists.txt b/libos/CMakeLists.txt index 0771eb28..52dd7525 100644 --- a/libos/CMakeLists.txt +++ b/libos/CMakeLists.txt @@ -13,6 +13,7 @@ set(SOURCES src/Path.cpp src/Mode.cpp src/Prompt.cpp + src/Security.cpp ) add_library(os ${SOURCES}) diff --git a/libos/include/os/Security.h b/libos/include/os/Security.h new file mode 100644 index 00000000..79ea81b7 --- /dev/null +++ b/libos/include/os/Security.h @@ -0,0 +1,48 @@ +/** + * @file Security.h + * @author apio (cloudapio.eu) + * @brief Functions to restrict process operations. + * + * @copyright Copyright (c) 2023, the Luna authors. + * + */ + +#pragma once +#include + +namespace os +{ + namespace Security + { + /** + * @brief Restrict system operations. + * + * The pledge() call, borrowed from OpenBSD, is a simple function to sandbox a process effectively. + * + * Syscalls are divided into a number of categories ("promises"), the following are the ones implemented on + * Luna: stdio rpath wpath cpath fattr chown unix tty proc exec prot_exec id mount signal host error + * + * The way pledge() works is: the process "tells" the kernel which subset of functions it will use, and if it + * suddenly uses something it has not promised (probably because the process was hacked, using ROP or something + * else) the kernel kills the process immediately with an uncatchable SIGABRT. Alternatively, if the process has + * pledged the "error" promise, the call will fail with ENOSYS. + * + * Pledges are not inherited across exec, although one may specify another set of promises to apply on the next + * execve() call. Thus, pledge() is not a way to restrict untrusted programs (unless the "exec" pledge is + * removed), but more of a way to protect trusted local programs from vulnerabilities. + * + * One may call pledge() several times, but only to remove promises, not to add them. + * + * A typical call to pledge would look like this: + * + * TRY(os::Security::pledge("stdio rpath wpath unix proc", nullptr)); + * + * @param promises The promises to apply immediately, separated by spaces. If empty, the process may only call + * _exit(2). If NULL, the promises are not changed. + * @param execpromises The promises to apply on the next call to execve(2), separated by spaces. If empty, the + * process may only call _exit(2). If NULL, the execpromises are not changed. + * @return Result Whether the operation succeded. + */ + Result pledge(const char* promises, const char* execpromises); + } +} diff --git a/libos/src/Security.cpp b/libos/src/Security.cpp new file mode 100644 index 00000000..6ad74d5a --- /dev/null +++ b/libos/src/Security.cpp @@ -0,0 +1,22 @@ +/** + * @file Security.cpp + * @author apio (cloudapio.eu) + * @brief Functions to restrict process operations. + * + * @copyright Copyright (c) 2023, the Luna authors. + * + */ + +#include +#include +#include + +namespace os::Security +{ + Result pledge(const char* promises, const char* execpromises) + { + int rc = ::pledge(promises, execpromises); + if (rc < 0) return err(errno); + return {}; + } +}