From ac1ee50d63d193ec4482e836d945638827ab7494 Mon Sep 17 00:00:00 2001 From: Omar Berrow Date: Thu, 4 Dec 2025 19:07:10 -0500 Subject: [PATCH 01/17] misc: implement syscall permission subsystem --- CMakeLists.txt | 2 + src/oboskrnl/CMakeLists.txt | 2 +- src/oboskrnl/perm.c | 218 ++++++++++++++++++++++++++++++++++++ src/oboskrnl/perm.h | 33 ++++++ 4 files changed, 254 insertions(+), 1 deletion(-) create mode 100644 src/oboskrnl/perm.c create mode 100644 src/oboskrnl/perm.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 478be4ea..93711fab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,7 @@ endif() set (OUTPUT_DIR ${CMAKE_SOURCE_DIR}/out CACHE STRING "The output directory.") set (OBOS_PAGE_REPLACEMENT_ALGORITHM "Aging" CACHE STRING "(Kernel developers only) The page replacement algorithm used by the MM.") set (OBOS_DEV_PREFIX "/dev" CACHE STRING "Directory where the kernel places devices.") +set (OBOS_PERM_PREFIX "/sys/perm" CACHE STRING "Directory where the kernel checks for capabilities") set (OBOS_CLANG_SUFFIX "" CACHE STRING "Some Linux distributions add a suffix to various clang and LLVM commands, such as the version used. Specify that suffix, if needed") file (TO_CMAKE_PATH "${OUTPUT_DIR}" OUTPUT_DIR) @@ -249,6 +250,7 @@ configure_file(${CMAKE_SOURCE_DIR}/src/inc/dev_prefix.h.in ${CMAKE_SOURCE_DIR}/s add_compile_definitions( OBOS_ARCHITECTURE_HAS_ACPI=${OBOS_ARCHITECTURE_HAS_ACPI} OBOS_ARCHITECTURE_HAS_PCI=${OBOS_ARCHITECTURE_HAS_PCI} + OBOS_PERM_PREFIX="${OBOS_PERM_PREFIX}" ) if (OBOS_USE_OBOS_GCC AND OBOS_COMPILE_USER_UTILS) diff --git a/src/oboskrnl/CMakeLists.txt b/src/oboskrnl/CMakeLists.txt index 8e11352e..b86b74c3 100644 --- a/src/oboskrnl/CMakeLists.txt +++ b/src/oboskrnl/CMakeLists.txt @@ -22,7 +22,7 @@ list (APPEND oboskrnl_sources "init_proc.c" "vfs/create.c" "net/route.c" "net/eth.c" "net/ip.c" "net/arp.c" "power/event.c" "net/udp.c" "net/icmp.c" "net/tcp.c" "vfs/socket.c" "net/lo.c" - "kinit.c" "vfs/local_socket.c" + "kinit.c" "vfs/local_socket.c" "perm.c" ) add_executable(oboskrnl) diff --git a/src/oboskrnl/perm.c b/src/oboskrnl/perm.c new file mode 100644 index 00000000..7a810e1e --- /dev/null +++ b/src/oboskrnl/perm.c @@ -0,0 +1,218 @@ +/* + * oboskrnl/perm.c + * + * Copyright (c) 2025 Omar Berrow + * + * Syscall permission checking utilities + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +dirent* Vfs_PermRoot; + +#define CHECK_ID(id) \ +do {\ + if (*id == '/' || *id == 0) return OBOS_STATUS_INVALID_ARGUMENT;\ +} while(0)\ + +void OBOS_CapabilityInitialize() +{ + Vfs_PermRoot = VfsH_DirentLookup(OBOS_PERM_PREFIX); + if (!Vfs_PermRoot) + OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "%s: Could not find directory at OBOS_PERM_PREFIX (%s) specified at build time.\n", __func__, OBOS_PERM_PREFIX); + // we chillin +} + +obos_status OBOS_CapabilityFetch(const char* id, capability* res, bool create) +{ + OBOS_ENSURE(Vfs_PermRoot); + OBOS_ENSURE(res); + OBOS_ENSURE(id); + CHECK_ID(id); + dirent* ent = VfsH_DirentLookupFrom(id, Vfs_PermRoot); + if (!ent) + { + if (!create) + return OBOS_STATUS_NOT_FOUND; + capability def = {}; + def.allow_user = true; + def.allow_group = true; + def.owner = ROOT_UID; + def.group = ROOT_GID; + return OBOS_CapabilitySet(id, &def, true); + } + + if (!ent->vnode) + return OBOS_STATUS_INTERNAL_ERROR; + + res->owner = ent->vnode->uid; + res->group = ent->vnode->gid; + res->allow_user = ent->vnode->perm.owner_exec; + res->allow_group = ent->vnode->perm.group_exec; + res->allow_other = ent->vnode->perm.other_exec; + + if (res->allow_other) + OBOS_Warning("Allowing 'other' permissions on capability \"%s\"\n", id); + if (!res->allow_other && !res->allow_group && !res->allow_user) + OBOS_Warning("Capability \"%s\" is disabled.\n", id); + if (res->owner != ROOT_UID) + OBOS_Warning("Capability \"%s\" has weird ownership. Owned by %d:%d\n", id, res->owner, res->group); + + return OBOS_STATUS_SUCCESS; +} + +// TODO: Should this be replaced with strchr? +static size_t str_search(const char* str, char ch) +{ + size_t ret = strchr(str, ch); + for (; str[ret] == ch && str[ret] != 0; ret++) + ; + return ret; +} + +static obos_status create_parents(const char* path, dirent* root, dirent** last_parent, const char** last_token) +{ + size_t path_len = strlen(path); + if (!path_len) + return OBOS_STATUS_INVALID_ARGUMENT; + + for (; *path == '/'; path++, path_len--) + ; + const char* tok = path; + size_t tok_len = strchr(tok, '/'); + if (tok_len != path_len) + tok_len--; + while (tok[tok_len - 1] == '/') + tok_len--; + if (!tok_len) + return OBOS_STATUS_INVALID_ARGUMENT; + + obos_status status = OBOS_STATUS_SUCCESS; + file_perm mode = {}; + mode.owner_read = true; + mode.owner_write = true; + mode.owner_exec = true; + mode.group_read = true; + mode.group_write = false; + mode.group_exec = true; + mode.other_read = true; + mode.other_write = false; + mode.other_exec = true; + + while (1) + { + char* tok_nul = Vfs_Malloc(tok_len+1); + memcpy(tok_nul, tok, tok_len); + + dirent* new = VfsH_DirentLookupFrom(tok_nul, root); + if (new) + goto cont; + + cont: + *last_token = tok; + tok = tok + str_search(tok, '/'); + size_t currentPathLen = strlen(tok)-1; + if (tok[currentPathLen] != '/') + currentPathLen++; + while (tok[currentPathLen] == '/') + currentPathLen--; + tok_len = strchr(tok, '/'); + if (tok_len != currentPathLen) + tok_len--; + while (tok[tok_len - 1] == '/') + tok_len--; + if (!tok_len) + { + // Last token, do not create anything + *last_parent = root; + Vfs_Free(tok_nul); + break; + } + else + { + if (obos_is_error(status = Vfs_CreateNode(root, tok_nul, VNODE_TYPE_DIR, mode))) + return status; + root = VfsH_DirentLookupFrom(tok_nul, root); + Vfs_Free(tok_nul); + continue; + } + } + + return OBOS_STATUS_SUCCESS; +} + +obos_status OBOS_CapabilitySet(const char* id, const capability* perm, bool overwrite) +{ + CHECK_ID(id); + OBOS_ENSURE(Vfs_PermRoot); + OBOS_ENSURE(id); + OBOS_ENSURE(perm); + capability tmp = {}; + obos_status status = OBOS_CapabilityFetch(id, &tmp, false); + switch (status) { + case OBOS_STATUS_SUCCESS: + if (!overwrite) return OBOS_STATUS_ALREADY_INITIALIZED; + break; + case OBOS_STATUS_NOT_FOUND: + break; + default: return status; + } + + // We need to create the file. + dirent* parent = nullptr; + const char* name = nullptr; + status = create_parents(id, Vfs_PermRoot, &parent, &name); + if (obos_is_error(status)) + return status; + OBOS_ENSURE(parent); + file_perm mode = {}; + mode.owner_exec = perm->allow_user; + mode.group_exec = perm->allow_group; + mode.other_exec = perm->allow_other; + return Vfs_CreateNodeOwner(parent, name, VNODE_TYPE_REG, mode, perm->owner, perm->group); +} + +obos_status OBOS_CapabilityCheck(const char* id) +{ + obos_status res = OBOS_CapabilityCheckAs(id, Core_GetCurrentThread()->proc->euid, Core_GetCurrentThread()->proc->egid); + if (res) + return OBOS_STATUS_SUCCESS; + for (size_t i = 0; i < Core_GetCurrentThread()->proc->groups.nEntries; i++) + { + res = OBOS_CapabilityCheckAs(id, Core_GetCurrentThread()->proc->euid, Core_GetCurrentThread()->proc->groups.list[i]); + if (res == OBOS_STATUS_SUCCESS) + return OBOS_STATUS_SUCCESS; + else if (res == OBOS_STATUS_ACCESS_DENIED) + continue; + else + return res; + } + return OBOS_STATUS_ACCESS_DENIED; +} + +obos_status OBOS_CapabilityCheckAs(const char* id, uid user, gid group) +{ + capability res = {}; + obos_status status = OBOS_CapabilityFetch(id, &res, false); + if (obos_is_error(status)) + return status; + if (res.allow_user && res.owner == user) + return true; + if (res.allow_group && res.group == group) + return true; + return res.allow_other; +} \ No newline at end of file diff --git a/src/oboskrnl/perm.h b/src/oboskrnl/perm.h new file mode 100644 index 00000000..00c0c915 --- /dev/null +++ b/src/oboskrnl/perm.h @@ -0,0 +1,33 @@ +/* + * oboskrnl/perm.h + * + * Copyright (c) 2025 Omar Berrow + * + * Syscall permission checking utilities + */ + +#pragma once + +#include +#include + +#ifndef OBOS_PERM_PREFIX +# define OBOS_PERM_PREFIX "/sys/perm/" +#endif + +extern struct dirent* Vfs_PermRoot; + +typedef struct capability { + uid owner; + gid group; + bool allow_user : 1; + bool allow_group : 1; + bool allow_other : 1; +} capability; + +void OBOS_CapabilityInitialize(); + +obos_status OBOS_CapabilityFetch(const char* id, capability* res, bool create); +obos_status OBOS_CapabilitySet(const char* id, const capability* perm, bool overwrite); +obos_status OBOS_CapabilityCheck(const char* id); +obos_status OBOS_CapabilityCheckAs(const char* id, uid user, gid group); \ No newline at end of file From 45bcbad1731c1e4c031c5015209d18890e3a903f Mon Sep 17 00:00:00 2001 From: Omar Berrow Date: Thu, 4 Dec 2025 19:10:02 -0500 Subject: [PATCH 02/17] vfs: call OBOS_CapabilityInitialize --- src/oboskrnl/vfs/init.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/oboskrnl/vfs/init.c b/src/oboskrnl/vfs/init.c index a8976960..54805318 100644 --- a/src/oboskrnl/vfs/init.c +++ b/src/oboskrnl/vfs/init.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -111,6 +112,7 @@ void Vfs_Initialize() Vfs_DevRoot = VfsH_DirentLookup(OBOS_DEV_PREFIX); if (!Vfs_DevRoot) OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "%s: Could not find directory at OBOS_DEV_PREFIX (%s) specified at build time.\n", __func__, OBOS_DEV_PREFIX); + OBOS_CapabilityInitialize(); if (root_partid) Free(OBOS_KernelAllocator, root_partid, strlen(root_partid)); if (root_uuid) From d98d640c5cfa9af87de4678e0a21db1083f92e1a Mon Sep 17 00:00:00 2001 From: Omar Berrow Date: Thu, 4 Dec 2025 19:19:12 -0500 Subject: [PATCH 03/17] misc: add reasonable default return value for OBOS_CapabilityCheckAs --- src/oboskrnl/perm.c | 16 ++++++++++++---- src/oboskrnl/perm.h | 13 +++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/oboskrnl/perm.c b/src/oboskrnl/perm.c index 7a810e1e..b6fd9454 100644 --- a/src/oboskrnl/perm.c +++ b/src/oboskrnl/perm.c @@ -39,7 +39,8 @@ void OBOS_CapabilityInitialize() obos_status OBOS_CapabilityFetch(const char* id, capability* res, bool create) { - OBOS_ENSURE(Vfs_PermRoot); + if (!Vfs_PermRoot) + return OBOS_STATUS_NOT_FOUND; OBOS_ENSURE(res); OBOS_ENSURE(id); CHECK_ID(id); @@ -209,10 +210,17 @@ obos_status OBOS_CapabilityCheckAs(const char* id, uid user, gid group) capability res = {}; obos_status status = OBOS_CapabilityFetch(id, &res, false); if (obos_is_error(status)) + { + if (status == OBOS_STATUS_NOT_FOUND) + { + if (user == ROOT_UID || group == ROOT_GID) return OBOS_STATUS_SUCCESS; + return OBOS_STATUS_ACCESS_DENIED; + } return status; + } if (res.allow_user && res.owner == user) - return true; + return OBOS_STATUS_SUCCESS; if (res.allow_group && res.group == group) - return true; - return res.allow_other; + return OBOS_STATUS_SUCCESS; + return res.allow_other ? OBOS_STATUS_SUCCESS : OBOS_STATUS_ACCESS_DENIED; } \ No newline at end of file diff --git a/src/oboskrnl/perm.h b/src/oboskrnl/perm.h index 00c0c915..bc319dd2 100644 --- a/src/oboskrnl/perm.h +++ b/src/oboskrnl/perm.h @@ -27,6 +27,19 @@ typedef struct capability { void OBOS_CapabilityInitialize(); +// NOTE: If a filesystem is unmounted, and remounted, any default values +// WILL be lost + +// NOTE: OBOS_CapabilityCheckAs treats a capability like the following, +// if it cannot be found +// capability cap = { +// .owner=ROOT_UID, +// .group=ROOT_GID, +// .allow_user=true, +// .allow_group=true, +// .allow_other=false +// }; + obos_status OBOS_CapabilityFetch(const char* id, capability* res, bool create); obos_status OBOS_CapabilitySet(const char* id, const capability* perm, bool overwrite); obos_status OBOS_CapabilityCheck(const char* id); From 8891f08f7f4a4306b757b5cc153c697928bf39fb Mon Sep 17 00:00:00 2001 From: Omar Berrow Date: Thu, 4 Dec 2025 19:19:53 -0500 Subject: [PATCH 04/17] sys: use capability subsystem for driver syscalls --- src/oboskrnl/driver_interface/drv_sys.c | 50 ++++++++++++------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/src/oboskrnl/driver_interface/drv_sys.c b/src/oboskrnl/driver_interface/drv_sys.c index 2d99ee15..b53f030c 100644 --- a/src/oboskrnl/driver_interface/drv_sys.c +++ b/src/oboskrnl/driver_interface/drv_sys.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -23,15 +24,11 @@ #include handle Sys_LoadDriver(const void* file, size_t szFile, obos_status* ustatus) -{ - if (Core_GetCurrentThread()->proc->euid != ROOT_UID) - { - obos_status status = OBOS_STATUS_ACCESS_DENIED; - if (ustatus) memcpy_k_to_usr(ustatus, &status, sizeof(obos_status)); - return HANDLE_INVALID; - } +{ + obos_status status = OBOS_CapabilityCheck("drv/load"); + if (obos_is_error(status)) + return status; - obos_status status = OBOS_STATUS_SUCCESS; if (!szFile) { status = OBOS_STATUS_INVALID_ARGUMENT; @@ -62,19 +59,13 @@ handle Sys_LoadDriver(const void* file, size_t szFile, obos_status* ustatus) return ret; } -#define perm_check_impl(ret) do {\ - if (Core_GetCurrentThread()->proc->euid != ROOT_UID)\ - return (ret);\ -} while(0) -#define perm_check() perm_check_impl(OBOS_STATUS_ACCESS_DENIED) -#define perm_check_hnd() perm_check_impl(HANDLE_INVALID) - obos_status Sys_StartDriver(handle driver, handle* mainThread) { - perm_check(); + obos_status status = OBOS_CapabilityCheck("drv/start"); + if (obos_is_error(status)) + return status; OBOS_LockHandleTable(OBOS_CurrentHandleTable()); - obos_status status = OBOS_STATUS_SUCCESS; handle_desc* drv = OBOS_HandleLookup(OBOS_CurrentHandleTable(), driver, HANDLE_TYPE_DRIVER_ID, false, &status); if (!drv) { @@ -105,10 +96,11 @@ obos_status Sys_StartDriver(handle driver, handle* mainThread) obos_status Sys_UnloadDriver(handle driver) { - perm_check(); + obos_status status = OBOS_CapabilityCheck("drv/unload"); + if (obos_is_error(status)) + return status; OBOS_LockHandleTable(OBOS_CurrentHandleTable()); - obos_status status = OBOS_STATUS_SUCCESS; handle_desc* drv = OBOS_HandleLookup(OBOS_CurrentHandleTable(), driver, HANDLE_TYPE_DRIVER_ID, false, &status); if (!drv) { @@ -127,10 +119,11 @@ obos_status Sys_UnloadDriver(handle driver) obos_status Sys_PnpLoadDriversAt(handle dent, bool wait) { - perm_check(); + obos_status status = OBOS_CapabilityCheck("drv/load-pnp"); + if (obos_is_error(status)) + return status; OBOS_LockHandleTable(OBOS_CurrentHandleTable()); - obos_status status = OBOS_STATUS_SUCCESS; handle_desc* dirent = OBOS_HandleLookup(OBOS_CurrentHandleTable(), dent, HANDLE_TYPE_DIRENT, false, &status); if (!dirent) { @@ -145,11 +138,13 @@ obos_status Sys_PnpLoadDriversAt(handle dent, bool wait) // Finds a loaded driver by its name, and returns a handle to it. handle Sys_FindDriverByName(const char* uname /* assumed to be 64-bytes at max */) { - perm_check_hnd(); + obos_status status = OBOS_CapabilityCheck("drv/open-name"); + if (obos_is_error(status)) + return HANDLE_INVALID; char* name = nullptr; size_t sz_name = 0; - obos_status status = OBOSH_ReadUserString(uname, nullptr, &sz_name); + status = OBOSH_ReadUserString(uname, nullptr, &sz_name); if (obos_is_error(status)) return HANDLE_INVALID; if (sz_name >= 64) @@ -187,7 +182,9 @@ handle Sys_FindDriverByName(const char* uname /* assumed to be 64-bytes at max * // If 'curr' is HANDLE_INVALID, the first item in the list is returned. handle Sys_EnumerateLoadedDrivers(handle curr) { - perm_check_hnd(); + obos_status status = OBOS_CapabilityCheck("drv/enumerate"); + if (obos_is_error(status)) + return HANDLE_INVALID; driver_id* id = nullptr; @@ -222,13 +219,14 @@ handle Sys_EnumerateLoadedDrivers(handle curr) // Queries the name of the driver in 'drv'. obos_status Sys_QueryDriverName(handle driver, char* namebuf, size_t *sznamebuf /* need not be over 64 */) { - perm_check(); + obos_status status = OBOS_CapabilityCheck("drv/query-name"); + if (obos_is_error(status)) + return status; if (!sznamebuf) return OBOS_STATUS_INVALID_ARGUMENT; OBOS_LockHandleTable(OBOS_CurrentHandleTable()); - obos_status status = OBOS_STATUS_SUCCESS; handle_desc* drv = OBOS_HandleLookup(OBOS_CurrentHandleTable(), driver, HANDLE_TYPE_DRIVER_ID, false, &status); if (!drv) { From 134ac522ec2f271631646738e40ed50bc9d6267e Mon Sep 17 00:00:00 2001 From: Omar Berrow Date: Thu, 4 Dec 2025 19:23:44 -0500 Subject: [PATCH 05/17] sys: use capability subsystem for power syscalls --- src/oboskrnl/syscall.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/src/oboskrnl/syscall.c b/src/oboskrnl/syscall.c index da8a315b..deb11d6f 100644 --- a/src/oboskrnl/syscall.c +++ b/src/oboskrnl/syscall.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -322,24 +323,45 @@ obos_status Sys_ThreadGetStack(handle thr, void** stack_base, size_t *stack_size obos_status Sys_Shutdown() { - if (Core_GetCurrentThread()->proc->euid != 0) - return OBOS_STATUS_ACCESS_DENIED; + obos_status status = OBOS_CapabilityCheck("power/shutdown"); + if (obos_is_error(status)) + { + if (status == OBOS_STATUS_ACCESS_DENIED) + return OBOS_STATUS_ACCESS_DENIED; + else + { + OBOS_Error("%s: OBOS_CapabilityCheck returned %d! It is safe to forcefully shutdown your PC\nThis could be a bug, report it\n", __func__, status); + return status; + } + } OBOS_Shutdown(); + OBOS_UNREACHABLE; } obos_status Sys_Reboot() { - if (Core_GetCurrentThread()->proc->euid != 0) - return OBOS_STATUS_ACCESS_DENIED; + obos_status status = OBOS_CapabilityCheck("power/reboot"); + if (obos_is_error(status)) + { + if (status == OBOS_STATUS_ACCESS_DENIED) + return OBOS_STATUS_ACCESS_DENIED; + else + { + OBOS_Error("%s: OBOS_CapabilityCheck returned %d! It is safe to forcefully reboot your PC\nThis could be a bug, report it\n", __func__, status); + return status; + } + } OBOS_Reboot(); + OBOS_UNREACHABLE; } obos_status Sys_Suspend() { - if (Core_GetCurrentThread()->proc->euid != 0) - return OBOS_STATUS_ACCESS_DENIED; - OBOS_Suspend(); - OBOS_UNREACHABLE; + obos_status status = OBOS_CapabilityCheck("power/suspend"); + if (obos_is_error(status)) + return status; + + return OBOS_Suspend(); } uintptr_t OBOS_SyscallTable[SYSCALL_END-SYSCALL_BEGIN] = { From 25ab25f0d0f375159655dd8d86a91a95e4e03004 Mon Sep 17 00:00:00 2001 From: Omar Berrow Date: Thu, 4 Dec 2025 19:25:14 -0500 Subject: [PATCH 06/17] sys: use capability subsystem for Sys_PartProbeDrive --- src/oboskrnl/syscall.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/oboskrnl/syscall.c b/src/oboskrnl/syscall.c index deb11d6f..79bd5782 100644 --- a/src/oboskrnl/syscall.c +++ b/src/oboskrnl/syscall.c @@ -50,10 +50,11 @@ #include -// TODO: Check permissions? obos_status Sys_PartProbeDrive(handle ent, bool check_checksum) { - obos_status status = OBOS_STATUS_SUCCESS; + obos_status status = OBOS_CapabilityCheck("fs/part-probe"); + if (obos_is_error(status)) + return status; handle_desc* dent = OBOS_HandleLookup(OBOS_CurrentHandleTable(), ent, HANDLE_TYPE_DIRENT, false, &status); if (!dent) @@ -335,7 +336,7 @@ obos_status Sys_Shutdown() } } OBOS_Shutdown(); - + OBOS_UNREACHABLE; } obos_status Sys_Reboot() From e3a394200961c493145d7596b71b122d58db1a4f Mon Sep 17 00:00:00 2001 From: Omar Berrow Date: Thu, 4 Dec 2025 19:40:23 -0500 Subject: [PATCH 07/17] misc: allow the user of OBOS_CapabilityCheck to set the default access for users falling into the 'other' category --- src/oboskrnl/perm.c | 10 +++++----- src/oboskrnl/perm.h | 4 ++-- src/oboskrnl/syscall.c | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/oboskrnl/perm.c b/src/oboskrnl/perm.c index b6fd9454..57603601 100644 --- a/src/oboskrnl/perm.c +++ b/src/oboskrnl/perm.c @@ -187,14 +187,14 @@ obos_status OBOS_CapabilitySet(const char* id, const capability* perm, bool over return Vfs_CreateNodeOwner(parent, name, VNODE_TYPE_REG, mode, perm->owner, perm->group); } -obos_status OBOS_CapabilityCheck(const char* id) +obos_status OBOS_CapabilityCheck(const char* id, bool def_other_allow) { - obos_status res = OBOS_CapabilityCheckAs(id, Core_GetCurrentThread()->proc->euid, Core_GetCurrentThread()->proc->egid); + obos_status res = OBOS_CapabilityCheckAs(id, Core_GetCurrentThread()->proc->euid, Core_GetCurrentThread()->proc->egid, def_other_allow); if (res) return OBOS_STATUS_SUCCESS; for (size_t i = 0; i < Core_GetCurrentThread()->proc->groups.nEntries; i++) { - res = OBOS_CapabilityCheckAs(id, Core_GetCurrentThread()->proc->euid, Core_GetCurrentThread()->proc->groups.list[i]); + res = OBOS_CapabilityCheckAs(id, Core_GetCurrentThread()->proc->euid, Core_GetCurrentThread()->proc->groups.list[i], def_other_allow); if (res == OBOS_STATUS_SUCCESS) return OBOS_STATUS_SUCCESS; else if (res == OBOS_STATUS_ACCESS_DENIED) @@ -205,7 +205,7 @@ obos_status OBOS_CapabilityCheck(const char* id) return OBOS_STATUS_ACCESS_DENIED; } -obos_status OBOS_CapabilityCheckAs(const char* id, uid user, gid group) +obos_status OBOS_CapabilityCheckAs(const char* id, uid user, gid group, bool def_other_allow) { capability res = {}; obos_status status = OBOS_CapabilityFetch(id, &res, false); @@ -214,7 +214,7 @@ obos_status OBOS_CapabilityCheckAs(const char* id, uid user, gid group) if (status == OBOS_STATUS_NOT_FOUND) { if (user == ROOT_UID || group == ROOT_GID) return OBOS_STATUS_SUCCESS; - return OBOS_STATUS_ACCESS_DENIED; + return def_other_allow ? OBOS_STATUS_SUCCESS : OBOS_STATUS_ACCESS_DENIED; } return status; } diff --git a/src/oboskrnl/perm.h b/src/oboskrnl/perm.h index bc319dd2..b6ff3981 100644 --- a/src/oboskrnl/perm.h +++ b/src/oboskrnl/perm.h @@ -42,5 +42,5 @@ void OBOS_CapabilityInitialize(); obos_status OBOS_CapabilityFetch(const char* id, capability* res, bool create); obos_status OBOS_CapabilitySet(const char* id, const capability* perm, bool overwrite); -obos_status OBOS_CapabilityCheck(const char* id); -obos_status OBOS_CapabilityCheckAs(const char* id, uid user, gid group); \ No newline at end of file +obos_status OBOS_CapabilityCheck(const char* id, bool def_other_allow); +obos_status OBOS_CapabilityCheckAs(const char* id, uid user, gid group, bool def_other_allow); \ No newline at end of file diff --git a/src/oboskrnl/syscall.c b/src/oboskrnl/syscall.c index 79bd5782..fd0cd6b9 100644 --- a/src/oboskrnl/syscall.c +++ b/src/oboskrnl/syscall.c @@ -52,7 +52,7 @@ obos_status Sys_PartProbeDrive(handle ent, bool check_checksum) { - obos_status status = OBOS_CapabilityCheck("fs/part-probe"); + obos_status status = OBOS_CapabilityCheck("fs/part-probe", false); if (obos_is_error(status)) return status; @@ -324,7 +324,7 @@ obos_status Sys_ThreadGetStack(handle thr, void** stack_base, size_t *stack_size obos_status Sys_Shutdown() { - obos_status status = OBOS_CapabilityCheck("power/shutdown"); + obos_status status = OBOS_CapabilityCheck("power/shutdown", false); if (obos_is_error(status)) { if (status == OBOS_STATUS_ACCESS_DENIED) @@ -341,7 +341,7 @@ obos_status Sys_Shutdown() } obos_status Sys_Reboot() { - obos_status status = OBOS_CapabilityCheck("power/reboot"); + obos_status status = OBOS_CapabilityCheck("power/reboot", false); if (obos_is_error(status)) { if (status == OBOS_STATUS_ACCESS_DENIED) @@ -358,7 +358,7 @@ obos_status Sys_Reboot() } obos_status Sys_Suspend() { - obos_status status = OBOS_CapabilityCheck("power/suspend"); + obos_status status = OBOS_CapabilityCheck("power/suspend", false); if (obos_is_error(status)) return status; From 9f98ae59a49b52da610accd81cb1510305e1d2d4 Mon Sep 17 00:00:00 2001 From: Omar Berrow Date: Thu, 4 Dec 2025 19:40:50 -0500 Subject: [PATCH 08/17] sys: use capability subsystem for scheduler syscalls --- src/oboskrnl/scheduler/sched_sys.c | 121 +++++++++++++++++++++++++++-- 1 file changed, 116 insertions(+), 5 deletions(-) diff --git a/src/oboskrnl/scheduler/sched_sys.c b/src/oboskrnl/scheduler/sched_sys.c index 45d5a7d4..13a82e9e 100644 --- a/src/oboskrnl/scheduler/sched_sys.c +++ b/src/oboskrnl/scheduler/sched_sys.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -103,6 +104,10 @@ handle Sys_ThreadOpen(handle proc_hnd, uintptr_t tid) if (tid <= (Core_CpuCount + 1)) return HANDLE_INVALID; // you cannot open any CPU's idle thread + obos_status status = OBOS_CapabilityCheck("core/thread-open", true); + if (obos_is_error(status)) + return status; + process* parent = HANDLE_TYPE(proc_hnd) == HANDLE_TYPE_CURRENT ? Core_GetCurrentThread()->proc : nullptr; if (!parent) @@ -116,6 +121,12 @@ handle Sys_ThreadOpen(handle proc_hnd, uintptr_t tid) } parent = proc->un.process; OBOS_UnlockHandleTable(OBOS_CurrentHandleTable()); + if (parent->euid != Core_GetCurrentThread()->proc->euid) + { + obos_status status = OBOS_CapabilityCheck("core/thread-arbitrary-open", false); + if (obos_is_error(status)) + return status; + } } thread* thr = nullptr; @@ -141,6 +152,7 @@ handle Sys_ThreadOpen(handle proc_hnd, uintptr_t tid) return hnd; } + handle Sys_ThreadCreate(thread_priority priority, thread_affinity affinity, handle thread_context) { if (priority < 0 || priority > THREAD_PRIORITY_MAX_VALUE) @@ -208,6 +220,7 @@ handle Sys_ThreadCreate(thread_priority priority, thread_affinity affinity, hand }\ result__;\ }) + obos_status Sys_ThreadReady(handle thread) { struct thread* thr = thread_object_from_handle(thread, true, false); @@ -218,12 +231,14 @@ obos_status Sys_ThreadReady(handle thread) thr->kernelStack = Mm_AllocateKernelStack(thr->proc->ctx, nullptr); return CoreH_ThreadReady(thr); } + obos_status Sys_ThreadBlock(handle thread) { struct thread* thr = thread_object_from_handle(thread, true, true); OBOS_ASSERT(thr); return CoreH_ThreadBlock(thr, true); } + obos_status Sys_ThreadBoostPriority(handle thread, int reserved /* ignored as of now */) { OBOS_UNUSED(reserved); @@ -231,6 +246,7 @@ obos_status Sys_ThreadBoostPriority(handle thread, int reserved /* ignored as of OBOS_ASSERT(thr); return CoreH_ThreadBoostPriority(thr); } + obos_status Sys_ThreadPriority(handle thread_hnd, const thread_priority *new, thread_priority* old) { struct thread* thr = thread_object_from_handle(thread_hnd, true, true); @@ -239,8 +255,59 @@ obos_status Sys_ThreadPriority(handle thread_hnd, const thread_priority *new, th memcpy_k_to_usr(old, &thr->priority, sizeof(thr->priority)); if (new) { + obos_status status = OBOS_CapabilityCheck("core/thread-set-priority", true); + if (obos_is_error(status)) + return status; + thread_priority new_priority = 0; thread_priority old_priority = thr->priority; - memcpy_usr_to_k(&thr->priority, new, sizeof(thr->priority)); + memcpy_usr_to_k(&new_priority, new, sizeof(thr->priority)); + switch (new_priority) { + case THREAD_PRIORITY_IDLE: + { + obos_status status = OBOS_CapabilityCheck("core/thread-idle-priority", true); + if (obos_is_error(status)) + return status; + break; + } + case THREAD_PRIORITY_LOW: + { + obos_status status = OBOS_CapabilityCheck("core/thread-low-priority", true); + if (obos_is_error(status)) + return status; + break; + } + case THREAD_PRIORITY_NORMAL: + { + obos_status status = OBOS_CapabilityCheck("core/thread-normal-priority", true); + if (obos_is_error(status)) + return status; + break; + } + case THREAD_PRIORITY_HIGH: + { + obos_status status = OBOS_CapabilityCheck("core/thread-high-priority", true); + if (obos_is_error(status)) + return status; + break; + } + case THREAD_PRIORITY_URGENT: + { + obos_status status = OBOS_CapabilityCheck("core/thread-urgent-priority", false); + if (obos_is_error(status)) + return status; + break; + } + case THREAD_PRIORITY_REAL_TIME: + { + obos_status status = OBOS_CapabilityCheck("core/thread-realtime-priority", false); + if (obos_is_error(status)) + return status; + break; + } + default: return OBOS_STATUS_INVALID_ARGUMENT; + } + + thr->priority = new_priority; if (thr->priority != old_priority && thr->masterCPU) { CoreH_ThreadListRemove(&thr->masterCPU->priorityLists[old_priority].list, &thr->snode); @@ -249,6 +316,7 @@ obos_status Sys_ThreadPriority(handle thread_hnd, const thread_priority *new, th } return OBOS_STATUS_SUCCESS; } + obos_status Sys_ThreadAffinity(handle thread_hnd, const thread_affinity *new, thread_affinity* old) { struct thread* thr = thread_object_from_handle(thread_hnd, true, true); @@ -256,9 +324,36 @@ obos_status Sys_ThreadAffinity(handle thread_hnd, const thread_affinity *new, th if (old) memcpy_k_to_usr(old, &thr->affinity, sizeof(thr->affinity)); if (new) + { + obos_status status = OBOS_CapabilityCheck("core/thread-set-affinity", false); + if (obos_is_error(status)) + return status; + thread_affinity old = thr->affinity; memcpy_usr_to_k(&thr->affinity, new, sizeof(thr->affinity)); + thr->affinity &= ~Core_DefaultThreadAffinity; + if (!thr->affinity) + { + thr->affinity = old; + return OBOS_STATUS_INVALID_ARGUMENT; + } + if (thr->status != THREAD_STATUS_BLOCKED) + { + if (~thr->affinity & CoreH_CPUIdToAffinity(thr->masterCPU->id)) + { + irql oldIrql = Core_RaiseIrqlNoThread(IRQL_DISPATCH); + bool yield_after = thr->masterCPU == CoreS_GetCPULocalPtr(); + CoreH_ThreadBlock(thr, false); + CoreH_ThreadReady(thr); + if (yield_after) + Core_Yield(); + else + Core_LowerIrqlNoThread(oldIrql); + } + } + } return OBOS_STATUS_SUCCESS; } + // Can only be called once per thread-object, and must be called before readying a thread. obos_status Sys_ThreadSetOwner(handle thr_hnd, handle proc_hnd) { @@ -285,6 +380,13 @@ obos_status Sys_ThreadSetOwner(handle thr_hnd, handle proc_hnd) OBOS_UnlockHandleTable(OBOS_CurrentHandleTable()); } + if (proc_hnd != HANDLE_CURRENT) + { + obos_status status = OBOS_CapabilityCheck("core/set-thread-owner-arbitrary", false); + if (obos_is_error(status)) + return status; + } + thr->stackFreeUserdata = proc->ctx; thr->stackFree = CoreH_VMAStackFree; @@ -366,9 +468,18 @@ handle Sys_ProcessOpen(uintptr_t pid) OBOS_UNUSED(pid); if (pid > Core_NextPID) return HANDLE_INVALID; + obos_status status = OBOS_CapabilityCheck("core/process-open", true); + if (obos_is_error(status)) + return HANDLE_INVALID; process* proc = Core_LookupProc(pid); if (!proc) return HANDLE_INVALID; + if (proc->euid != Core_GetCurrentThread()->proc->euid) + { + obos_status status = OBOS_CapabilityCheck("core/process-open-arbitrary", true); + if (obos_is_error(status)) + return HANDLE_INVALID; + } proc->refcount++; OBOS_LockHandleTable(OBOS_CurrentHandleTable()); handle_desc* desc = nullptr; @@ -684,7 +795,7 @@ static bool check_unpriv_gid(gid gid) obos_status Sys_SetRESUid(uid ruid, uid euid, uid suid) { - if (Core_GetCurrentThread()->proc->euid != 0) + if (OBOS_CapabilityCheck("core/set-uid", false) == OBOS_STATUS_SUCCESS) { if ((ruid != -1) && !check_unpriv_uid(ruid)) return OBOS_STATUS_ACCESS_DENIED; @@ -710,7 +821,7 @@ obos_status Sys_SetRESUid(uid ruid, uid euid, uid suid) obos_status Sys_SetRESGid(gid rgid, gid egid, gid sgid) { - if (Core_GetCurrentThread()->proc->euid != 0) + if (OBOS_CapabilityCheck("core/set-gid", false) == OBOS_STATUS_SUCCESS) { if ((rgid != -1) && !check_unpriv_gid(rgid)) return OBOS_STATUS_ACCESS_DENIED; @@ -758,7 +869,7 @@ obos_status Sys_GetRESGid(gid* rgid, gid* egid, gid* sgid) obos_status Sys_SetUid(uid uid) { - if (Core_GetCurrentThread()->proc->euid == 0) + if (OBOS_CapabilityCheck("core/set-uid", false) == OBOS_STATUS_SUCCESS) { Core_GetCurrentThread()->proc->ruid = uid; Core_GetCurrentThread()->proc->euid = uid; @@ -770,7 +881,7 @@ obos_status Sys_SetUid(uid uid) obos_status Sys_SetGid(gid gid) { - if (Core_GetCurrentThread()->proc->euid == 0) + if (OBOS_CapabilityCheck("core/set-uid", false) == OBOS_STATUS_SUCCESS) { Core_GetCurrentThread()->proc->rgid = gid; Core_GetCurrentThread()->proc->egid = gid; From c604d971acb423816656cd1a61e4358c4d0e3e92 Mon Sep 17 00:00:00 2001 From: Omar Berrow Date: Thu, 4 Dec 2025 19:50:53 -0500 Subject: [PATCH 09/17] misc: fix compiler error --- src/oboskrnl/driver_interface/drv_sys.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/oboskrnl/driver_interface/drv_sys.c b/src/oboskrnl/driver_interface/drv_sys.c index b53f030c..a14bf31c 100644 --- a/src/oboskrnl/driver_interface/drv_sys.c +++ b/src/oboskrnl/driver_interface/drv_sys.c @@ -25,7 +25,7 @@ handle Sys_LoadDriver(const void* file, size_t szFile, obos_status* ustatus) { - obos_status status = OBOS_CapabilityCheck("drv/load"); + obos_status status = OBOS_CapabilityCheck("drv/load", false); if (obos_is_error(status)) return status; @@ -61,7 +61,7 @@ handle Sys_LoadDriver(const void* file, size_t szFile, obos_status* ustatus) obos_status Sys_StartDriver(handle driver, handle* mainThread) { - obos_status status = OBOS_CapabilityCheck("drv/start"); + obos_status status = OBOS_CapabilityCheck("drv/start", false); if (obos_is_error(status)) return status; @@ -96,7 +96,7 @@ obos_status Sys_StartDriver(handle driver, handle* mainThread) obos_status Sys_UnloadDriver(handle driver) { - obos_status status = OBOS_CapabilityCheck("drv/unload"); + obos_status status = OBOS_CapabilityCheck("drv/unload", false); if (obos_is_error(status)) return status; @@ -119,7 +119,7 @@ obos_status Sys_UnloadDriver(handle driver) obos_status Sys_PnpLoadDriversAt(handle dent, bool wait) { - obos_status status = OBOS_CapabilityCheck("drv/load-pnp"); + obos_status status = OBOS_CapabilityCheck("drv/load-pnp", false); if (obos_is_error(status)) return status; @@ -138,7 +138,7 @@ obos_status Sys_PnpLoadDriversAt(handle dent, bool wait) // Finds a loaded driver by its name, and returns a handle to it. handle Sys_FindDriverByName(const char* uname /* assumed to be 64-bytes at max */) { - obos_status status = OBOS_CapabilityCheck("drv/open-name"); + obos_status status = OBOS_CapabilityCheck("drv/open-name", false); if (obos_is_error(status)) return HANDLE_INVALID; @@ -182,7 +182,7 @@ handle Sys_FindDriverByName(const char* uname /* assumed to be 64-bytes at max * // If 'curr' is HANDLE_INVALID, the first item in the list is returned. handle Sys_EnumerateLoadedDrivers(handle curr) { - obos_status status = OBOS_CapabilityCheck("drv/enumerate"); + obos_status status = OBOS_CapabilityCheck("drv/enumerate", false); if (obos_is_error(status)) return HANDLE_INVALID; @@ -219,7 +219,7 @@ handle Sys_EnumerateLoadedDrivers(handle curr) // Queries the name of the driver in 'drv'. obos_status Sys_QueryDriverName(handle driver, char* namebuf, size_t *sznamebuf /* need not be over 64 */) { - obos_status status = OBOS_CapabilityCheck("drv/query-name"); + obos_status status = OBOS_CapabilityCheck("drv/query-name", false); if (obos_is_error(status)) return status; From 5756ad318682890c77d9b42391c647745da631e0 Mon Sep 17 00:00:00 2001 From: Omar Berrow Date: Thu, 4 Dec 2025 19:53:59 -0500 Subject: [PATCH 10/17] vfs: use capability subsystem for sockets --- src/oboskrnl/vfs/socket.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/oboskrnl/vfs/socket.c b/src/oboskrnl/vfs/socket.c index 6d255377..763bba2e 100644 --- a/src/oboskrnl/vfs/socket.c +++ b/src/oboskrnl/vfs/socket.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -271,6 +272,19 @@ static obos_status inet_socket(int type, int protocol, fd* out) if (protocol == IPPROTO_UDP && type != SOCK_DGRAM) return OBOS_STATUS_INVALID_ARGUMENT; + if (protocol == IPPROTO_TCP) + { + obos_status status = OBOS_CapabilityCheck("net/tcp", true); + if (obos_is_error(status)) + return status; + } + if (protocol == IPPROTO_UDP) + { + obos_status status = OBOS_CapabilityCheck("net/udp", true); + if (obos_is_error(status)) + return status; + } + if (!get_sock_ops(AF_INET, type, protocol)) return OBOS_STATUS_INVALID_ARGUMENT; @@ -306,9 +320,15 @@ obos_status Net_Socket(int domain, int type, int protocol, fd* out) obos_status status = OBOS_STATUS_UNIMPLEMENTED; switch (domain) { case AF_INET: + status = OBOS_CapabilityCheck("net/ipv4", true); + if (obos_is_error(status)) + return status; status = inet_socket(type, protocol, out); break; case AF_UNIX: + status = OBOS_CapabilityCheck("unix-socket", true); + if (obos_is_error(status)) + return status; status = local_socket(type, protocol, out); break; default: break; From 12641a08a078d22c671f9097e4aaad2bae788e61 Mon Sep 17 00:00:00 2001 From: Omar Berrow Date: Thu, 4 Dec 2025 19:54:09 -0500 Subject: [PATCH 11/17] sys: use capability subsystem for vfs syscalls --- src/oboskrnl/vfs/fd_sys.c | 42 +++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/src/oboskrnl/vfs/fd_sys.c b/src/oboskrnl/vfs/fd_sys.c index 50ab5462..6e3d660c 100644 --- a/src/oboskrnl/vfs/fd_sys.c +++ b/src/oboskrnl/vfs/fd_sys.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -485,8 +486,11 @@ obos_status Sys_FdEOF(const handle desc) obos_status Sys_FdIoctl(handle desc, uintptr_t request, void* argp, size_t sz_argp) { + obos_status status = OBOS_CapabilityCheck("fs/ioctl", true); + if (obos_is_error(status)) + return status; + OBOS_LockHandleTable(OBOS_CurrentHandleTable()); - obos_status status = OBOS_STATUS_SUCCESS; handle_desc* fd = OBOS_HandleLookup(OBOS_CurrentHandleTable(), desc, HANDLE_TYPE_FD, false, &status); if (!fd) { @@ -1026,6 +1030,10 @@ void OBOS_OpenStandardFDs(handle_table* tbl) // makes new dirty pages. void Sys_Sync() { + obos_status status = OBOS_CapabilityCheck("fs/sync", true); + if (obos_is_error(status)) + return; + Mm_PageWriterOperation = PAGE_WRITER_SYNC_FILE; Mm_WakePageWriter(true); Mm_WakePageWriter(true); @@ -1044,9 +1052,13 @@ obos_status Sys_Mount(const char* uat, const char* uon) if (!uat || !uon) return OBOS_STATUS_INVALID_ARGUMENT; + obos_status status = OBOS_CapabilityCheck("fs/mount", false); + if (obos_is_error(status)) + return status; + char* at = nullptr; size_t sz_path = 0; - obos_status status = OBOSH_ReadUserString(uat, nullptr, &sz_path); + status = OBOSH_ReadUserString(uat, nullptr, &sz_path); if (obos_is_error(status)) return status; at = ZeroAllocate(OBOS_KernelAllocator, sz_path+1, sizeof(char), nullptr); @@ -1086,9 +1098,13 @@ obos_status Sys_Mount(const char* uat, const char* uon) obos_status Sys_Unmount(const char* uat) { + obos_status status = OBOS_CapabilityCheck("fs/unmount", false); + if (obos_is_error(status)) + return status; + char* at = nullptr; size_t sz_path = 0; - obos_status status = OBOSH_ReadUserString(uat, nullptr, &sz_path); + status = OBOSH_ReadUserString(uat, nullptr, &sz_path); if (obos_is_error(status)) return status; at = ZeroAllocate(OBOS_KernelAllocator, sz_path+1, sizeof(char), nullptr); @@ -1846,9 +1862,13 @@ obos_status Sys_SymLinkAt(const char* utarget, handle dirfd, const char* ulink) obos_status Sys_LinkAt(handle olddirfd, const char *utarget, handle newdirfd, const char *ulink, int flags) { + obos_status status = OBOS_CapabilityCheck("fs/hardlink", false); + if (obos_is_error(status)) + return status; + char* target = nullptr; size_t sz_path = 0; - obos_status status = OBOSH_ReadUserString(utarget, nullptr, &sz_path); + status = OBOSH_ReadUserString(utarget, nullptr, &sz_path); if (obos_is_error(status)) return status; target = ZeroAllocate(OBOS_KernelAllocator, sz_path+1, sizeof(char), nullptr); @@ -2837,6 +2857,10 @@ obos_status Sys_FChmodAt(handle dirfd, const char* upathname, int mode, int flag { obos_status status = 0; + status = OBOS_CapabilityCheck("fs/chmod", true); + if (obos_is_error(status)) + return status; + char* pathname = nullptr; size_t sz_path = 0; status = OBOSH_ReadUserString(upathname, nullptr, &sz_path); @@ -2958,7 +2982,9 @@ obos_status Sys_FChmodAt(handle dirfd, const char* upathname, int mode, int flag obos_status Sys_FChownAt(handle dirfd, const char *upathname, uid owner, gid group, int flags) { - obos_status status = 0; + obos_status status = OBOS_CapabilityCheck("fs/chown", false); + if (obos_is_error(status)) + return status; char* pathname = nullptr; size_t sz_path = 0; @@ -3049,12 +3075,6 @@ obos_status Sys_FChownAt(handle dirfd, const char *upathname, uid owner, gid gro have_target: OBOS_ENSURE(target); - if (Sys_GetUid() != ROOT_UID) - { - status = OBOS_STATUS_ACCESS_DENIED; - goto fail; - } - driver_header* header = Vfs_GetVnodeDriver(target); if (!header) { From bae47cfdb13743264b96d56b1d886d82a9359ca2 Mon Sep 17 00:00:00 2001 From: Omar Berrow Date: Thu, 4 Dec 2025 19:54:37 -0500 Subject: [PATCH 12/17] sys: fix bugs with scheduler syscalls --- src/oboskrnl/scheduler/sched_sys.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/oboskrnl/scheduler/sched_sys.c b/src/oboskrnl/scheduler/sched_sys.c index 13a82e9e..46f02b70 100644 --- a/src/oboskrnl/scheduler/sched_sys.c +++ b/src/oboskrnl/scheduler/sched_sys.c @@ -476,7 +476,7 @@ handle Sys_ProcessOpen(uintptr_t pid) return HANDLE_INVALID; if (proc->euid != Core_GetCurrentThread()->proc->euid) { - obos_status status = OBOS_CapabilityCheck("core/process-open-arbitrary", true); + obos_status status = OBOS_CapabilityCheck("core/process-open-arbitrary", false); if (obos_is_error(status)) return HANDLE_INVALID; } @@ -795,7 +795,7 @@ static bool check_unpriv_gid(gid gid) obos_status Sys_SetRESUid(uid ruid, uid euid, uid suid) { - if (OBOS_CapabilityCheck("core/set-uid", false) == OBOS_STATUS_SUCCESS) + if (OBOS_CapabilityCheck("core/set-uid", false) == OBOS_STATUS_ACCESS_DENIED) { if ((ruid != -1) && !check_unpriv_uid(ruid)) return OBOS_STATUS_ACCESS_DENIED; @@ -821,7 +821,7 @@ obos_status Sys_SetRESUid(uid ruid, uid euid, uid suid) obos_status Sys_SetRESGid(gid rgid, gid egid, gid sgid) { - if (OBOS_CapabilityCheck("core/set-gid", false) == OBOS_STATUS_SUCCESS) + if (OBOS_CapabilityCheck("core/set-gid", false) == OBOS_STATUS_ACCESS_DENIED) { if ((rgid != -1) && !check_unpriv_gid(rgid)) return OBOS_STATUS_ACCESS_DENIED; From 537649394a06d5b26a4178da5b18302f70748350 Mon Sep 17 00:00:00 2001 From: Omar Berrow Date: Thu, 4 Dec 2025 19:54:43 -0500 Subject: [PATCH 13/17] misc: fix compiler error --- src/oboskrnl/perm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/oboskrnl/perm.c b/src/oboskrnl/perm.c index 57603601..3f933691 100644 --- a/src/oboskrnl/perm.c +++ b/src/oboskrnl/perm.c @@ -6,8 +6,6 @@ * Syscall permission checking utilities */ -#pragma once - #include #include #include From 94bc3a980c310b184721fc350dead47c9b9bd5c4 Mon Sep 17 00:00:00 2001 From: Omar Berrow Date: Thu, 4 Dec 2025 19:59:18 -0500 Subject: [PATCH 14/17] sys: use capability subsystem for mm --- src/oboskrnl/mm/mm_sys.c | 45 ++++++++++++++++++++++++++++++++++++++-- src/oboskrnl/mm/mm_sys.h | 2 ++ src/oboskrnl/syscall.c | 18 ---------------- 3 files changed, 45 insertions(+), 20 deletions(-) diff --git a/src/oboskrnl/mm/mm_sys.c b/src/oboskrnl/mm/mm_sys.c index df4b6d0b..0c7ea672 100644 --- a/src/oboskrnl/mm/mm_sys.c +++ b/src/oboskrnl/mm/mm_sys.c @@ -4,10 +4,10 @@ * Copyright (c) 2024-2025 Omar Berrow */ -#include "mm/swap.h" #include #include #include +#include #include #include #include @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -81,6 +82,16 @@ void* Sys_VirtualMemoryAlloc(handle ctx, void* base, size_t size, struct vma_all prot &= ~OBOS_PROTECTION_CACHE_DISABLE; flags &= ~VMA_FLAGS_32BITPHYS; // userspace doesn't need this as much as kernel mode + if (flags & VMA_FLAGS_NON_PAGED) + { + obos_status status = OBOS_CapabilityCheck("mm/allocate-non-paged", false); + if (obos_is_error(status)) + { + if (pstatus) memcpy_k_to_usr(pstatus, &status, sizeof(status)); + return nullptr; + } + } + void* ret = Mm_VirtualMemoryAllocEx(vmm_ctx, base, size, prot, flags, file, args.offset, &status); if (pstatus) memcpy_k_to_usr(pstatus, &status, sizeof(status)); @@ -99,10 +110,12 @@ obos_status Sys_VirtualMemoryProtect(handle ctx, void* base, size_t size, prot_f } obos_status Sys_VirtualMemoryLock(handle ctx, void* base, size_t size) { + OBOS_UNUSED(ctx && base && size); return OBOS_STATUS_UNIMPLEMENTED; } obos_status Sys_VirtualMemoryUnlock(handle ctx, void* base, size_t size) { + OBOS_UNUSED(ctx && base && size); return OBOS_STATUS_UNIMPLEMENTED; } @@ -157,6 +170,10 @@ size_t Sys_GetUsedPhysicalMemoryCount() obos_status Sys_QueryPageInfo(handle ctx, void* base, page_info* info) { + obos_status status = OBOS_CapabilityCheck("mm/query-page-info", false); + if (obos_is_error(status)) + return status; + context* vmm_ctx = context_from_handle(ctx, false, 0, true); // Search the page in the RB-Tree. irql oldIrql = Core_SpinlockAcquire(&vmm_ctx->lock); @@ -198,9 +215,13 @@ obos_status Sys_MakeDiskSwap(const char* upath) obos_status Sys_SwitchSwap(const char* upath) { + obos_status status = OBOS_CapabilityCheck("mm/switch-swap", false); + if (obos_is_error(status)) + return status; + char* path = nullptr; size_t sz_path = 0; - obos_status status = OBOSH_ReadUserString(upath, nullptr, &sz_path); + status = OBOSH_ReadUserString(upath, nullptr, &sz_path); if (obos_is_error(status)) return status; path = ZeroAllocate(OBOS_KernelAllocator, sz_path+1, sizeof(char), nullptr); @@ -236,6 +257,26 @@ obos_status Sys_SwitchSwap(const char* upath) void Sys_SyncAnonPages() { + obos_status status = OBOS_CapabilityCheck("mm/sync-anon", true); + if (obos_is_error(status)) + return; Mm_PageWriterOperation = PAGE_WRITER_SYNC_ANON; Mm_WakePageWriter(true); } + +handle Sys_MmFork() +{ + // Zeroed in Mm_ConstructContext + context* ctx = Allocate(Mm_Allocator, sizeof(context), nullptr); + Mm_ConstructContext(ctx); + Mm_ForkContext(ctx, Core_GetCurrentThread()->proc->ctx); + ctx->workingSet.capacity = Core_GetCurrentThread()->proc->ctx->workingSet.capacity; + + OBOS_LockHandleTable(OBOS_CurrentHandleTable()); + handle_desc* desc = nullptr; + handle hnd = OBOS_HandleAllocate(OBOS_CurrentHandleTable(), HANDLE_TYPE_VMM_CONTEXT, &desc); + desc->un.vmm_context = ctx; + OBOS_UnlockHandleTable(OBOS_CurrentHandleTable()); + + return hnd; +} \ No newline at end of file diff --git a/src/oboskrnl/mm/mm_sys.h b/src/oboskrnl/mm/mm_sys.h index 0bc8ed95..80a9abec 100644 --- a/src/oboskrnl/mm/mm_sys.h +++ b/src/oboskrnl/mm/mm_sys.h @@ -38,3 +38,5 @@ obos_status Sys_QueryPageInfo(handle ctx, void* base, page_info* info); obos_status Sys_MakeDiskSwap(const char* path); obos_status Sys_SwitchSwap(const char* path); void Sys_SyncAnonPages(); + +handle Sys_MmFork(); \ No newline at end of file diff --git a/src/oboskrnl/syscall.c b/src/oboskrnl/syscall.c index fd0cd6b9..deea4f1a 100644 --- a/src/oboskrnl/syscall.c +++ b/src/oboskrnl/syscall.c @@ -88,24 +88,6 @@ void Sys_LibCLog(const char* ustr) Free(OBOS_KernelAllocator, buf, str_len+1); } -static handle Sys_MmFork() -{ - // Zeroed in Mm_ConstructContext - context* ctx = Allocate(Mm_Allocator, sizeof(context), nullptr); - Mm_ConstructContext(ctx); - Mm_ForkContext(ctx, Core_GetCurrentThread()->proc->ctx); - ctx->workingSet.capacity = Core_GetCurrentThread()->proc->ctx->workingSet.capacity; - - OBOS_LockHandleTable(OBOS_CurrentHandleTable()); - handle_desc* desc = nullptr; - handle hnd = OBOS_HandleAllocate(OBOS_CurrentHandleTable(), HANDLE_TYPE_VMM_CONTEXT, &desc); - desc->un.vmm_context = ctx; - OBOS_UnlockHandleTable(OBOS_CurrentHandleTable()); - - return hnd; - -} - void Sys_ExitCurrentProcess(uint32_t exitCode) { Core_ExitCurrentProcess((exitCode & 0xff) << 8); From 18b4c9995ceff5bb228af2ba52c8a1589cd707f6 Mon Sep 17 00:00:00 2001 From: Omar Berrow Date: Thu, 4 Dec 2025 20:01:25 -0500 Subject: [PATCH 15/17] misc: fix bug in OBOS_CapabilityCheck --- src/oboskrnl/perm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/oboskrnl/perm.c b/src/oboskrnl/perm.c index 3f933691..f1c3458e 100644 --- a/src/oboskrnl/perm.c +++ b/src/oboskrnl/perm.c @@ -188,12 +188,12 @@ obos_status OBOS_CapabilitySet(const char* id, const capability* perm, bool over obos_status OBOS_CapabilityCheck(const char* id, bool def_other_allow) { obos_status res = OBOS_CapabilityCheckAs(id, Core_GetCurrentThread()->proc->euid, Core_GetCurrentThread()->proc->egid, def_other_allow); - if (res) + if (obos_is_success(res)) return OBOS_STATUS_SUCCESS; for (size_t i = 0; i < Core_GetCurrentThread()->proc->groups.nEntries; i++) { res = OBOS_CapabilityCheckAs(id, Core_GetCurrentThread()->proc->euid, Core_GetCurrentThread()->proc->groups.list[i], def_other_allow); - if (res == OBOS_STATUS_SUCCESS) + if (obos_is_success(res)) return OBOS_STATUS_SUCCESS; else if (res == OBOS_STATUS_ACCESS_DENIED) continue; From 783389f3684b88f1ffdf5348d257e4d38f8ca032 Mon Sep 17 00:00:00 2001 From: Omar Berrow Date: Thu, 4 Dec 2025 20:12:19 -0500 Subject: [PATCH 16/17] core: inherit supplementary gids from parent --- src/oboskrnl/scheduler/process.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/oboskrnl/scheduler/process.c b/src/oboskrnl/scheduler/process.c index 36569a20..d238480b 100644 --- a/src/oboskrnl/scheduler/process.c +++ b/src/oboskrnl/scheduler/process.c @@ -92,6 +92,12 @@ OBOS_PAGEABLE_FUNCTION obos_status Core_ProcessStart(process* proc, thread* main proc->rgid = proc->parent->rgid; proc->egid = proc->parent->egid; proc->sgid = proc->parent->sgid; + proc->groups.nEntries = proc->parent->groups.nEntries; + proc->groups.list = memcpy( + Allocate(OBOS_KernelAllocator, proc->parent->groups.nEntries * sizeof(gid), nullptr), + proc->parent->groups.list, + proc->parent->groups.nEntries*sizeof(gid) + ); proc->refcount++; Core_SetProcessGroup(proc, proc->parent->pgrp->pgid); proc->waiting_threads = WAITABLE_HEADER_INITIALIZE(false, true); From ce4c65b50466880a66044f6d38067a94814c11c0 Mon Sep 17 00:00:00 2001 From: Omar Berrow Date: Thu, 4 Dec 2025 20:21:31 -0500 Subject: [PATCH 17/17] misc: use capability subsystem for OBOS_Kill --- src/oboskrnl/signal.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/oboskrnl/signal.c b/src/oboskrnl/signal.c index 3871a937..f1dbab84 100644 --- a/src/oboskrnl/signal.c +++ b/src/oboskrnl/signal.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -46,7 +47,11 @@ obos_status OBOS_Kill(struct thread* as, struct thread* thr, int sigval) if (thr->proc->pid == 0) return OBOS_STATUS_INVALID_OPERATION; if (thr->proc->euid != as->proc->euid && as->proc->euid != 0) - return OBOS_STATUS_ACCESS_DENIED; + { + obos_status status = OBOS_CapabilityCheck("kill-arbitrary", true); + if (obos_is_error(status)) + return status; + } if (sigval == 0) return OBOS_STATUS_SUCCESS; // see man fork.2, "If sig is 0, then no signal is sent, but existence and permission checks are still performed"