duct taped posix.dll (just like microsoft), new cursor, more info in the fault handlers, processes now have a parse-it-yourself cmdline, add SYS_WAIT_THREAD and SYS_GET_PROCESS_PID, writing still doesn't work

This commit is contained in:
maksw committed 2026-05-05 15:24:58 +02:00
1 parent a37f5b1581
commit b5c831f593
26 files changed
+1107 -56

No files matched your search

+88 -5
View File
@@ -683,14 +683,15 @@ static uint64_t SyscallDebugPrint(uint64_t a0, uint64_t a1, uint64_t a2,
}
// ---------------------------------------------------------------------------
// SYS_CREATE_PROCESS (40) a0=*path a1=*handleOut
// SYS_CREATE_PROCESS (40) a0=*path a1=*handleOut a2=*cmdline (optional)
// ---------------------------------------------------------------------------
static uint64_t SyscallCreateProcess(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
(void)a2; (void)a3; (void)a4; (void)a5;
(void)a3; (void)a4; (void)a5;
const char* path = (const char*)(uintptr_t)a0;
const char* path = (const char*)(uintptr_t)a0;
uint32_t* handleOut = (uint32_t*)(uintptr_t)a1;
const char* cmdline = (const char*)(uintptr_t)a2; // NULL = no args
if (!path || !handleOut) return STATUS_INVALID_PARAMETER;
// Read the executable from disk.
@@ -712,16 +713,33 @@ static uint64_t SyscallCreateProcess(uint64_t a0, uint64_t a1, uint64_t a2,
s = KeCreateProcess(path, &proc);
if (!KSUCCESS(s)) { MmFreeUserMemory(mem, size); return s; }
// Store the command line in the process so _start can pick it up.
// If no cmdline was supplied default to just the image path.
if (cmdline && cmdline[0])
strncpy(proc->Cmdline, cmdline, sizeof(proc->Cmdline) - 1);
else
strncpy(proc->Cmdline, path, sizeof(proc->Cmdline) - 1);
proc->Cmdline[sizeof(proc->Cmdline) - 1] = '\0';
// proc->Cmdline is kernel pool - CPL=3 code can't read it.
// Copy into user memory so the initial thread can access it directly.
size_t cmdlineLen = strlen(proc->Cmdline) + 1;
char* userCmdline = (char*)MmAllocateUserMemory(cmdlineLen);
if (!userCmdline) { ObDereferenceObject(&proc->Header); return STATUS_NO_MEMORY; }
memcpy(userCmdline, proc->Cmdline, cmdlineLen);
// Map the PE image into memory.
uintptr_t imageBase = 0;
s = LdrLoadImage(mem, size, &imageBase, true);
MmFreeUserMemory(mem, size);
if (!KSUCCESS(s)) { ObDereferenceObject(&proc->Header); return s; }
// Spin up the initial thread at the PE entry point.
// Spin up the initial thread. Pass userCmdline as UserArg so _start
// receives it directly in RCX without an extra syscall.
THREAD* thread;
uintptr_t entryPoint = LdrGetEntryPoint(imageBase);
s = KeCreateThread(proc, entryPoint, 0, PriorityNormal, &thread);
s = KeCreateThread(proc, entryPoint, (uintptr_t)userCmdline,
PriorityNormal, &thread);
if (!KSUCCESS(s)) { ObDereferenceObject(&proc->Header); return s; }
// Give the caller a handle to the new process so they can wait on it.
@@ -850,6 +868,69 @@ static uint64_t SyscallGetCwd(uint64_t a0, uint64_t a1, uint64_t a2,
return IoGetCwd(buf, size);
}
// ---------------------------------------------------------------------------
// SYS_WAIT_THREAD (53) a0=tid
// Blocks the caller until the thread with the given TID exits.
// Searches the current process's thread list; cross-process join is not
// supported in v1 (POSIX pthread_join is always intra-process).
// Returns STATUS_NOT_FOUND if the TID is unknown (already reaped or never
// existed) - treat the same as a successful join at the POSIX layer.
// ---------------------------------------------------------------------------
static uint64_t SyscallWaitThread(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
uint32_t targetTid = (uint32_t)a0;
PROCESS* proc = KeGetCurrentProcess();
if (!proc) return STATUS_FAILURE;
// Walk the thread list under the spinlock to find the target, then bump
// its ExitEvent refcount so the event survives even if the thread exits
// and is destroyed while we wait.
EVENT* exitEvent = (EVENT*)0;
uintptr_t flags = KeAcquireSpinlock(&proc->HandleLock);
LIST_ENTRY* entry = proc->ThreadList.Fwd;
while (entry != &proc->ThreadList) {
THREAD* t = CONTAINING_RECORD(entry, THREAD, ProcessLink);
if (t->ThreadId == targetTid && t->ExitEvent) {
exitEvent = t->ExitEvent;
ObReferenceObject(&exitEvent->Header); // keep event alive
break;
}
entry = entry->Fwd;
}
KeReleaseSpinlock(&proc->HandleLock, flags);
if (!exitEvent) {
// TID not found - either already exited and reaped, or invalid.
// Treat as success at the POSIX layer (join on an already-dead thread).
return STATUS_NOT_FOUND;
}
KSTATUS s = KeWaitForEvent(exitEvent);
ObDereferenceObject(&exitEvent->Header);
return s;
}
// ---------------------------------------------------------------------------
// SYS_GET_PROCESS_PID (54) a0=procHandle a1=*pidOut
// Returns the numeric PID of a process identified by handle.
// Used by posix_spawn to map the kernel handle back to a pid_t for waitpid.
// ---------------------------------------------------------------------------
static uint64_t SyscallGetProcessPid(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
(void)a2; (void)a3; (void)a4; (void)a5;
PROCESS* proc = (PROCESS*)HandleToObject((uint32_t)a0, ObjectTypeProcess);
uint32_t* pidOut = (uint32_t*)(uintptr_t)a1;
if (!proc) return STATUS_INVALID_HANDLE;
if (!pidOut) { ObDereferenceObject(&proc->Header); return STATUS_INVALID_PARAMETER; }
*pidOut = proc->ProcessId;
ObDereferenceObject(&proc->Header);
return STATUS_SUCCESS;
}
// ===========================================================================
// Dispatch table - index must match SYS_* in syscall_nr.h exactly.
// ===========================================================================
@@ -910,6 +991,8 @@ static const SYSCALL_HANDLER gSyscallTable[SYS_MAX] = {
/* 50 SYS_READ_DIR */ SyscallReadDir,
/* 51 SYS_SET_CWD */ SyscallSetCwd,
/* 52 SYS_GET_CWD */ SyscallGetCwd,
/* 53 SYS_WAIT_THREAD */ SyscallWaitThread,
/* 54 SYS_GET_PROCESS_PID */ SyscallGetProcessPid,
};
// ---------------------------------------------------------------------------