feat: add Rust userspace support; fix TLS layout for p_align < 16; kill whole process on sibling-thread faults
This commit is contained in:
1 parent
a81298fb24
commit
f8b8f9610f
31 files changed
+1076
-38
No files matched your search
@@ -12,4 +12,4 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define MONTAUK_BUILD_NUMBER 302
|
||||
#define MONTAUK_BUILD_NUMBER 306
|
||||
@@ -221,6 +221,10 @@ namespace montauk::abi {
|
||||
}
|
||||
|
||||
static int Sys_Kill(int pid) {
|
||||
// A process may always kill itself: a sibling thread has no other
|
||||
// way to take the whole process down (SYS_EXIT from a sibling ends
|
||||
// only that thread), which abort()/panic=abort need.
|
||||
if (pid == Sched::GetCurrentPid()) return Sched::KillProcess(pid);
|
||||
if (!Sched::HasCapability(CAP_PROCESS_ADMIN)) {
|
||||
int ancestor = pid;
|
||||
bool descendant = false;
|
||||
|
||||
+11
-1
@@ -177,7 +177,17 @@ namespace Hal {
|
||||
if (i == 0x00) sig = 8; /* #DE -> SIGFPE */
|
||||
else if (i == 0x06) sig = 4; /* #UD -> SIGILL */
|
||||
else if (i == 0x10 || i == 0x13) sig = 8; /* x87/SIMD FP */
|
||||
Sched::SetProcessExitCode(proc->pid, 256 + sig);
|
||||
|
||||
// ExitProcess from a sibling thread ends only that thread,
|
||||
// which would leave the process running with the crash
|
||||
// swallowed. Flag the whole process (main thread and every
|
||||
// sibling) first, carrying the crash code rather than
|
||||
// KillProcess's default SIGKILL, so waiters see the fault.
|
||||
if (Sched::GetCurrentThreadPtr() != proc) {
|
||||
Sched::KillProcess(proc->pid, 256 + sig);
|
||||
} else {
|
||||
Sched::SetProcessExitCode(proc->pid, 256 + sig);
|
||||
}
|
||||
}
|
||||
|
||||
Sched::ExitProcess();
|
||||
|
||||
@@ -536,16 +536,13 @@ namespace Sched {
|
||||
}
|
||||
|
||||
// Build the main thread's TLS block (x86-64 variant II): the block
|
||||
// lives below the thread pointer, TP = base + S where
|
||||
// S = align_up(memsz, align), template data at [base, base+filesz),
|
||||
// .tbss zeroed, and [TP] holds the ABI-required self-pointer.
|
||||
// lives below the thread pointer (see ComputeTlsLayout), template
|
||||
// data first, .tbss zeroed, and [TP] holds the ABI self-pointer.
|
||||
if (tlsPhdr != nullptr && outTls != nullptr) {
|
||||
uint64_t align = tlsPhdr->p_align < 16 ? 16 : tlsPhdr->p_align;
|
||||
uint64_t S = (tlsPhdr->p_memsz + align - 1) & ~(align - 1);
|
||||
TlsLayout layout = ComputeTlsLayout(tlsPhdr->p_memsz, tlsPhdr->p_align);
|
||||
uint64_t base = (maxVaddrEnd + 0x1FFFULL) & ~0xFFFULL; // page-aligned, 1 guard page gap
|
||||
uint64_t total = S + 16; // + minimal TCB
|
||||
uint64_t numPages = (total + 0xFFF) / 0x1000;
|
||||
uint64_t tp = base + S;
|
||||
uint64_t numPages = (layout.totalSize + 0xFFF) / 0x1000;
|
||||
uint64_t tp = base + layout.tpOffset;
|
||||
|
||||
bool ok = true;
|
||||
for (uint64_t p = 0; p < numPages && ok; p++) {
|
||||
@@ -562,7 +559,7 @@ namespace Sched {
|
||||
}
|
||||
|
||||
// Copy the .tdata template bytes that land in this page.
|
||||
if (!copyPageFromFile(physAddr, virtAddr, base,
|
||||
if (!copyPageFromFile(physAddr, virtAddr, base + layout.templateOffset,
|
||||
tlsPhdr->p_offset, tlsPhdr->p_filesz)) {
|
||||
ok = false;
|
||||
break;
|
||||
@@ -579,7 +576,7 @@ namespace Sched {
|
||||
outTls->templateVaddr = tlsPhdr->p_vaddr;
|
||||
outTls->fileSize = tlsPhdr->p_filesz;
|
||||
outTls->memSize = tlsPhdr->p_memsz;
|
||||
outTls->align = align;
|
||||
outTls->align = tlsPhdr->p_align;
|
||||
} else {
|
||||
Kt::KernelLogStream(Kt::ERROR, "ELF")
|
||||
<< "PT_TLS setup failed (out of pages?), "
|
||||
|
||||
@@ -60,9 +60,30 @@ namespace Sched {
|
||||
uint64_t templateVaddr; // source of .tdata in the loaded image
|
||||
uint64_t fileSize; // initialized bytes
|
||||
uint64_t memSize; // total bytes (incl. .tbss)
|
||||
uint64_t align;
|
||||
uint64_t align; // PT_TLS p_align, NOT rounded up
|
||||
};
|
||||
|
||||
// Geometry of one variant II TLS block, as offsets from its
|
||||
// page-aligned base. The linker addresses TLS variables at
|
||||
// TP - align_up(memSize, p_align) + offset, so the template must start
|
||||
// exactly that far below TP; rounding p_align up first (as an older
|
||||
// version did) shifts every variable away from its initial value.
|
||||
// TP itself is kept at least 16-byte aligned, which the gap between
|
||||
// base and the template absorbs.
|
||||
struct TlsLayout {
|
||||
uint64_t templateOffset; // where .tdata/.tbss start
|
||||
uint64_t tpOffset; // thread pointer; [TP] holds the self-pointer
|
||||
uint64_t totalSize; // bytes to map, incl. the 16-byte TCB
|
||||
};
|
||||
|
||||
inline TlsLayout ComputeTlsLayout(uint64_t memSize, uint64_t pAlign) {
|
||||
uint64_t align = pAlign ? pAlign : 1;
|
||||
uint64_t block = (memSize + align - 1) & ~(align - 1);
|
||||
uint64_t tpAlign = align < 16 ? 16 : align;
|
||||
uint64_t tp = (block + tpAlign - 1) & ~(tpAlign - 1);
|
||||
return {tp - block, tp, tp + 16};
|
||||
}
|
||||
|
||||
uint64_t ElfLoad(const char* vfsPath, uint64_t pml4Phys, TlsInfo* outTls);
|
||||
|
||||
// Load a shared library into a fixed address range.
|
||||
|
||||
@@ -720,10 +720,8 @@ namespace Sched {
|
||||
uint64_t threadTlsPages = 0;
|
||||
Process& primary = processTable[primarySlot_];
|
||||
if (primary.tlsMemSize > 0) {
|
||||
uint64_t align = primary.tlsAlign < 16 ? 16 : primary.tlsAlign;
|
||||
uint64_t S = (primary.tlsMemSize + align - 1) & ~(align - 1);
|
||||
uint64_t total = S + 16;
|
||||
uint64_t numPages = (total + 0xFFF) / 0x1000;
|
||||
TlsLayout layout = ComputeTlsLayout(primary.tlsMemSize, primary.tlsAlign);
|
||||
uint64_t numPages = (layout.totalSize + 0xFFF) / 0x1000;
|
||||
|
||||
uint64_t base = 0;
|
||||
if (!ReserveUserHeapRange(primarySlot_, numPages * 0x1000, base)) {
|
||||
@@ -757,9 +755,9 @@ namespace Sched {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint64_t tp = base + S;
|
||||
memcpy((void*)base, (const void*)primary.tlsTemplateVaddr,
|
||||
primary.tlsFileSize);
|
||||
uint64_t tp = base + layout.tpOffset;
|
||||
memcpy((void*)(base + layout.templateOffset),
|
||||
(const void*)primary.tlsTemplateVaddr, primary.tlsFileSize);
|
||||
*(uint64_t*)tp = tp; /* ABI self-pointer */
|
||||
threadFsBase = tp;
|
||||
threadTlsBase = base;
|
||||
@@ -945,14 +943,13 @@ namespace Sched {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t align = primary.tlsAlign < 16 ? 16 : primary.tlsAlign;
|
||||
uint64_t blockSize = (primary.tlsMemSize + align - 1) & ~(align - 1);
|
||||
if (blockSize > thr.fsBase || blockSize > UINT64_MAX - 16) {
|
||||
TlsLayout layout = ComputeTlsLayout(primary.tlsMemSize, primary.tlsAlign);
|
||||
if (layout.tpOffset > thr.fsBase || layout.totalSize < layout.tpOffset) {
|
||||
Panic("Invalid sibling TLS metadata during thread teardown", nullptr);
|
||||
}
|
||||
|
||||
uint64_t base = thr.fsBase - blockSize;
|
||||
uint64_t pages = (blockSize + 16 + 0xFFF) / 0x1000;
|
||||
uint64_t base = thr.fsBase - layout.tpOffset;
|
||||
uint64_t pages = (layout.totalSize + 0xFFF) / 0x1000;
|
||||
thr.fsBase = 0;
|
||||
Memory::UnmapAndFreeUserRange(primary.pml4Phys, base, pages);
|
||||
ReleaseUserHeapRange(primarySlot_, base, pages * 0x1000ULL);
|
||||
@@ -1791,10 +1788,13 @@ namespace Sched {
|
||||
}
|
||||
}
|
||||
|
||||
int KillProcess(int pid) {
|
||||
// Refuse to kill PID 0 (init) or caller's own process
|
||||
int KillProcess(int pid, int exitCode) {
|
||||
// Refuse to kill PID 0 (init). Killing the caller's own process is
|
||||
// allowed: a faulting/aborting sibling thread shares the pid and has
|
||||
// no other way to take the process down. The caller's own slot gets
|
||||
// killPending below and exits at syscall return (ExitIfKilled) or
|
||||
// via the ExitProcess the fault handler calls next.
|
||||
if (pid == 0) return -1;
|
||||
if (pid == GetCurrentPid()) return -1;
|
||||
|
||||
schedLock.Acquire();
|
||||
|
||||
@@ -1817,7 +1817,7 @@ namespace Sched {
|
||||
return -1;
|
||||
}
|
||||
|
||||
processTable[primarySlot_].exitCode = 256 + 9; /* killed (SIGKILL) */
|
||||
processTable[primarySlot_].exitCode = exitCode;
|
||||
|
||||
// Flag the main thread so its next tick (or scheduler dispatch)
|
||||
// routes through ExitProcess, which sweeps every sibling thread
|
||||
|
||||
@@ -302,9 +302,10 @@ namespace Sched {
|
||||
int FutexWake(uint64_t uaddr, uint32_t count);
|
||||
|
||||
// Kill a process by PID. If the process is running on another CPU,
|
||||
// sets a kill-pending flag checked on the next timer tick.
|
||||
// sets a kill-pending flag checked on the next timer tick. exitCode is
|
||||
// what a waiter sees (256+sig; SIGKILL by default).
|
||||
// Returns 0 on success, -1 on failure.
|
||||
int KillProcess(int pid);
|
||||
int KillProcess(int pid, int exitCode = 256 + 9);
|
||||
|
||||
// Start a new process session for the caller, or terminate every process
|
||||
// belonging to a session. KillSession returns the number of live members
|
||||
|
||||
Reference in new issue
Block a user