feat: implement kernel capability model
This commit is contained in:
1 parent
9051b8a16e
commit
e7646bbbdb
47 files changed
+1507
-264
No files matched your search
@@ -4,6 +4,7 @@
|
||||
* Copyright (c) 2025-2026 Daniel Hammer
|
||||
*/
|
||||
|
||||
#include <Memory/UserRange.hpp>
|
||||
#include "Scheduler.hpp"
|
||||
#include "ElfLoader.hpp"
|
||||
#include <Memory/PageFrameAllocator.hpp>
|
||||
@@ -298,6 +299,9 @@ namespace Sched {
|
||||
processTable[i].environment[0] = '\0';
|
||||
processTable[i].environmentLength = 1;
|
||||
processTable[i].user[0] = '\0';
|
||||
processTable[i].permittedCaps = 0;
|
||||
processTable[i].effectiveCaps = 0;
|
||||
processTable[i].delegableCaps = 0;
|
||||
processTable[i].sessionId = -1;
|
||||
processTable[i].cwd[0] = '\0';
|
||||
processTable[i].runningOnCpu = -1;
|
||||
@@ -342,7 +346,9 @@ namespace Sched {
|
||||
}
|
||||
|
||||
int Spawn(const char* vfsPath, const char* args, bool startReady,
|
||||
const char* environment, uint32_t environmentLength) {
|
||||
const char* environment, uint32_t environmentLength,
|
||||
const montauk::abi::SpawnCapabilities* capabilities,
|
||||
const char* userOverride) {
|
||||
schedLock.Acquire();
|
||||
|
||||
int slot = -1;
|
||||
@@ -547,9 +553,37 @@ namespace Sched {
|
||||
proc.environmentLength = 1;
|
||||
}
|
||||
|
||||
// Inherit user string from parent, or default to "system" if no parent
|
||||
// Capabilities are kernel-owned and never inferred from the user name.
|
||||
// A normal userspace spawn receives no privileged authority; callers
|
||||
// must use SYS_SPAWN_CAPS for an explicit, kernel-validated delegation.
|
||||
if (parentPrimarySlot >= 0) {
|
||||
if (capabilities != nullptr) {
|
||||
proc.permittedCaps = capabilities->permitted;
|
||||
proc.effectiveCaps = capabilities->effective;
|
||||
proc.delegableCaps = capabilities->delegable;
|
||||
} else {
|
||||
proc.permittedCaps = 0;
|
||||
proc.effectiveCaps = 0;
|
||||
proc.delegableCaps = 0;
|
||||
}
|
||||
} else {
|
||||
// The kernel-created init process is the root of the capability
|
||||
// delegation tree. No userspace pathname or PID receives this
|
||||
// treatment; it is reached only with no current parent process.
|
||||
proc.permittedCaps = montauk::abi::CAP_ALL;
|
||||
proc.effectiveCaps = montauk::abi::CAP_ALL;
|
||||
proc.delegableCaps = montauk::abi::CAP_ALL;
|
||||
}
|
||||
|
||||
// Inherit user string from parent, or default to "system" if no parent.
|
||||
// An explicit override is accepted only through the validated
|
||||
// SYS_SPAWN_CAPS path.
|
||||
{
|
||||
if (parentSlot >= 0) {
|
||||
if (userOverride != nullptr) {
|
||||
int i = 0;
|
||||
for (; i < 31 && userOverride[i]; i++) proc.user[i] = userOverride[i];
|
||||
proc.user[i] = '\0';
|
||||
} else if (parentSlot >= 0) {
|
||||
int i = 0;
|
||||
for (; i < 31 && processTable[parentSlot].user[i]; i++)
|
||||
proc.user[i] = processTable[parentSlot].user[i];
|
||||
@@ -684,7 +718,7 @@ namespace Sched {
|
||||
mappedPages++;
|
||||
}
|
||||
if (!ok) {
|
||||
Ipc::UnmapAndFreeUserRange(sharedPml4, base, mappedPages);
|
||||
Memory::UnmapAndFreeUserRange(sharedPml4, base, mappedPages);
|
||||
ReleaseUserHeapRange(primarySlot_, base, numPages * 0x1000ULL);
|
||||
Kt::KernelLogStream(Kt::ERROR, "Sched")
|
||||
<< "Thread TLS allocation failed";
|
||||
@@ -711,7 +745,7 @@ namespace Sched {
|
||||
void* stackMem = Memory::g_pfa->ReallocConsecutive(nullptr, StackPages);
|
||||
if (stackMem == nullptr) {
|
||||
if (threadTlsPages != 0) {
|
||||
Ipc::UnmapAndFreeUserRange(sharedPml4, threadTlsBase, threadTlsPages);
|
||||
Memory::UnmapAndFreeUserRange(sharedPml4, threadTlsBase, threadTlsPages);
|
||||
ReleaseUserHeapRange(primarySlot_, threadTlsBase,
|
||||
threadTlsPages * 0x1000ULL);
|
||||
}
|
||||
@@ -737,7 +771,7 @@ namespace Sched {
|
||||
schedLock.Release();
|
||||
Memory::g_pfa->Free(stackMem, StackPages);
|
||||
if (threadTlsPages != 0) {
|
||||
Ipc::UnmapAndFreeUserRange(sharedPml4, threadTlsBase, threadTlsPages);
|
||||
Memory::UnmapAndFreeUserRange(sharedPml4, threadTlsBase, threadTlsPages);
|
||||
ReleaseUserHeapRange(primarySlot_, threadTlsBase,
|
||||
threadTlsPages * 0x1000ULL);
|
||||
}
|
||||
@@ -885,7 +919,7 @@ namespace Sched {
|
||||
uint64_t base = thr.fsBase - blockSize;
|
||||
uint64_t pages = (blockSize + 16 + 0xFFF) / 0x1000;
|
||||
thr.fsBase = 0;
|
||||
Ipc::UnmapAndFreeUserRange(primary.pml4Phys, base, pages);
|
||||
Memory::UnmapAndFreeUserRange(primary.pml4Phys, base, pages);
|
||||
ReleaseUserHeapRange(primarySlot_, base, pages * 0x1000ULL);
|
||||
}
|
||||
|
||||
@@ -1418,6 +1452,11 @@ namespace Sched {
|
||||
return &processTable[primary];
|
||||
}
|
||||
|
||||
bool HasCapability(uint64_t capability) {
|
||||
Process* proc = GetCurrentProcessPtr();
|
||||
return proc != nullptr && (proc->effectiveCaps & capability) == capability;
|
||||
}
|
||||
|
||||
Process* GetCurrentThreadPtr() {
|
||||
auto* cpu = Smp::GetCurrentCpuData();
|
||||
int slot = cpu->currentSlot;
|
||||
|
||||
@@ -86,6 +86,9 @@ namespace Sched {
|
||||
char environment[EnvironmentBytes]; // NUL-separated NAME=VALUE entries
|
||||
uint32_t environmentLength;
|
||||
char user[32]; // Owner user name (inherited from parent on spawn)
|
||||
uint64_t permittedCaps; // Authority owned by this process
|
||||
uint64_t effectiveCaps; // Authority currently usable by syscalls
|
||||
uint64_t delegableCaps; // Authority this process may pass to children
|
||||
int sessionId; // Process-session leader PID (inherited on spawn)
|
||||
char cwd[256]; // Absolute current working directory
|
||||
|
||||
@@ -144,7 +147,9 @@ namespace Sched {
|
||||
|
||||
void Initialize();
|
||||
int Spawn(const char* vfsPath, const char* args = nullptr, bool startReady = true,
|
||||
const char* environment = nullptr, uint32_t environmentLength = 0);
|
||||
const char* environment = nullptr, uint32_t environmentLength = 0,
|
||||
const montauk::abi::SpawnCapabilities* capabilities = nullptr,
|
||||
const char* userOverride = nullptr);
|
||||
int StartProcess(int pid);
|
||||
void Schedule();
|
||||
|
||||
@@ -172,6 +177,10 @@ namespace Sched {
|
||||
// Always returns the slot that owns per-process state -- never a sibling thread.
|
||||
Process* GetCurrentProcessPtr();
|
||||
|
||||
// Capability checks always consult kernel-owned process metadata. User
|
||||
// names are deliberately excluded from authorization.
|
||||
bool HasCapability(uint64_t capability);
|
||||
|
||||
// Get a pointer to the currently running thread's slot (may be a sibling).
|
||||
Process* GetCurrentThreadPtr();
|
||||
|
||||
|
||||
Reference in new issue
Block a user