refactor syscall ABI and FAT32 driver to use request structs and string views natively, enforce handle access rights on object lookup, add scheduler statistics tracking, fix KiSchedule to prevent 50% idle throttling on CPU-bound threads, better document x64 initial user stack alignment, fix process teardown to properly signal exit events and manage thread counts, optimize doom file I/O with a custom handle struct to internally track position and size, add SubsystemData to TEB for generic thread-local state, apply PAGE_NX to non-executable PE sections in the loader, update native apps, tests, and shells to match new APIs, update kernel32 directory retrieval.
This commit is contained in:
1 parent
603fbdfab1
commit
e1248f4afe
43 files changed
+2892
-1857
No files matched your search
+161
-56
@@ -88,15 +88,17 @@ static void KiProcessDestroy(OBJECT* obj) {
|
||||
|
||||
// Release all remaining handles.
|
||||
for (int i = 1; i < HANDLE_TABLE_SIZE; i++) {
|
||||
if (proc->Handles[i]) {
|
||||
ObDereferenceObject(proc->Handles[i]);
|
||||
proc->Handles[i] = (OBJECT *)0;
|
||||
if (proc->Handles[i].Object) {
|
||||
ObDereferenceObject(proc->Handles[i].Object);
|
||||
proc->Handles[i].Object = (OBJECT*)0;
|
||||
proc->Handles[i].Rights = 0;
|
||||
proc->Handles[i].Flags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Release the main executable image.
|
||||
if (proc->ImageBase && proc->ImageSize) {
|
||||
MmFreeUserMemory((void *)proc->ImageBase);
|
||||
MmFreeUserImage((void *)proc->ImageBase, proc->ImageSize);
|
||||
proc->ImageBase = 0;
|
||||
proc->ImageSize = 0;
|
||||
}
|
||||
@@ -104,7 +106,7 @@ static void KiProcessDestroy(OBJECT* obj) {
|
||||
// Release per-process modules.
|
||||
for (uint32_t i = 0; i < proc->ModuleCount; i++) {
|
||||
if (proc->Modules[i].Base && proc->Modules[i].Size) {
|
||||
MmFreeUserMemory((void *)proc->Modules[i].Base);
|
||||
MmFreeUserImage((void *)proc->Modules[i].Base, proc->Modules[i].Size);
|
||||
}
|
||||
proc->Modules[i].Base = 0;
|
||||
proc->Modules[i].Size = 0;
|
||||
@@ -170,6 +172,8 @@ KSTATUS KeCreateProcess(const char* name, PROCESS **out) {
|
||||
proc->ThreadCount = 0;
|
||||
proc->HandleLock = (SPINLOCK)SPINLOCK_INIT;
|
||||
proc->ExitCode = 0;
|
||||
proc->Terminating = 0;
|
||||
proc->Exited = 0;
|
||||
proc->ImageBase = 0;
|
||||
proc->ImageSize = 0;
|
||||
proc->UserPebBase = 0;
|
||||
@@ -182,6 +186,7 @@ KSTATUS KeCreateProcess(const char* name, PROCESS **out) {
|
||||
proc->UserCwdSize = 0;
|
||||
proc->ModuleCount = 0;
|
||||
proc->CurrentDirectory[0] = '\0';
|
||||
proc->CurrentDirectoryLength = 0;
|
||||
proc->CurrentDrive = 0;
|
||||
proc->CwdLock = (SPINLOCK)SPINLOCK_INIT;
|
||||
|
||||
@@ -208,33 +213,47 @@ KSTATUS KeCreateProcess(const char* name, PROCESS **out) {
|
||||
// ---------------------------------------------------------------------------
|
||||
// KeSetupUserProcessEnvironment
|
||||
// ---------------------------------------------------------------------------
|
||||
static KSTATUS KiCopyEnvironmentString(const char* src, uintptr_t* baseOut, size_t* sizeOut) {
|
||||
static KSTATUS KiCopyEnvironmentStringView(SYS_STRING_VIEW src,
|
||||
uintptr_t* baseOut,
|
||||
size_t* sizeOut) {
|
||||
if (!baseOut || !sizeOut) return STATUS_INVALID_PARAMETER;
|
||||
if (!src) src = "";
|
||||
*baseOut = 0;
|
||||
*sizeOut = 0;
|
||||
|
||||
size_t len = strlen(src) + 1;
|
||||
if (!SysSvIsValid(src)) return STATUS_INVALID_PARAMETER;
|
||||
if (SysSvContainsByte(src, '\0')) return STATUS_INVALID_PARAMETER;
|
||||
if (src.Length == (size_t)-1) return STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
size_t len = src.Length + 1;
|
||||
char* dst = (char*)MmAllocateUserMemory(len);
|
||||
if (!dst) return STATUS_NO_MEMORY;
|
||||
|
||||
memcpy(dst, src, len);
|
||||
if (src.Length) memcpy(dst, src.Data, src.Length);
|
||||
dst[src.Length] = '\0';
|
||||
|
||||
*baseOut = (uintptr_t)dst;
|
||||
*sizeOut = len;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static KSTATUS KiCopyEnvironmentStringFixed(const char* src, size_t capacity,
|
||||
uintptr_t* baseOut, size_t* sizeOut) {
|
||||
static KSTATUS KiCopyEnvironmentStringViewFixed(SYS_STRING_VIEW src,
|
||||
size_t capacity,
|
||||
uintptr_t* baseOut,
|
||||
size_t* sizeOut) {
|
||||
if (!baseOut || !sizeOut || capacity == 0) return STATUS_INVALID_PARAMETER;
|
||||
if (!src) src = "";
|
||||
*baseOut = 0;
|
||||
*sizeOut = 0;
|
||||
|
||||
if (!SysSvIsValid(src)) return STATUS_INVALID_PARAMETER;
|
||||
if (SysSvContainsByte(src, '\0')) return STATUS_INVALID_PARAMETER;
|
||||
if (src.Length + 1 > capacity) return STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
char* dst = (char*)MmAllocateUserMemory(capacity);
|
||||
if (!dst) return STATUS_NO_MEMORY;
|
||||
memset(dst, 0, capacity);
|
||||
|
||||
size_t len = strlen(src);
|
||||
if (len >= capacity) len = capacity - 1;
|
||||
memcpy(dst, src, len);
|
||||
dst[len] = '\0';
|
||||
if (src.Length) memcpy(dst, src.Data, src.Length);
|
||||
dst[src.Length] = '\0';
|
||||
|
||||
*baseOut = (uintptr_t)dst;
|
||||
*sizeOut = capacity;
|
||||
@@ -266,43 +285,68 @@ static void KiFreePartialProcessEnvironment(PROCESS* proc) {
|
||||
}
|
||||
}
|
||||
|
||||
static void KiFormatNativeCwd(const PROCESS* proc, const char* currentDirectory,
|
||||
char* out, size_t outSize) {
|
||||
if (!out || outSize == 0) return;
|
||||
const char* rel = currentDirectory ? currentDirectory : "";
|
||||
static KSTATUS KiFormatNativeCwdV(const PROCESS* proc,
|
||||
SYS_STRING_VIEW currentDirectory,
|
||||
char* out,
|
||||
size_t outSize,
|
||||
size_t* lengthOut) {
|
||||
if (lengthOut) *lengthOut = 0;
|
||||
if (!out || outSize == 0) return STATUS_INVALID_PARAMETER;
|
||||
out[0] = '\0';
|
||||
|
||||
if (!SysSvIsValid(currentDirectory)) return STATUS_INVALID_PARAMETER;
|
||||
if (SysSvContainsByte(currentDirectory, '\0')) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
uint8_t drive = proc ? proc->CurrentDrive : 0;
|
||||
if (drive > 7) drive = 0;
|
||||
|
||||
if (outSize < 4) { out[0] = '\0'; return; }
|
||||
if (currentDirectory.Length + 4 > outSize) return STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
out[0] = (char)('0' + drive);
|
||||
out[1] = ':';
|
||||
out[2] = '/';
|
||||
size_t len = strlen(rel);
|
||||
if (len + 4 > outSize) len = outSize - 4;
|
||||
memcpy(out + 3, rel, len);
|
||||
out[3 + len] = '\0';
|
||||
if (currentDirectory.Length)
|
||||
memcpy(out + 3, currentDirectory.Data, currentDirectory.Length);
|
||||
out[3 + currentDirectory.Length] = '\0';
|
||||
|
||||
if (lengthOut) *lengthOut = 3 + currentDirectory.Length;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
KSTATUS KeSetupUserProcessEnvironment(PROCESS* proc,
|
||||
const char* imagePath,
|
||||
const char* commandLine,
|
||||
const char* currentDirectory) {
|
||||
if (!proc || !imagePath) return STATUS_INVALID_PARAMETER;
|
||||
SYS_STRING_VIEW imagePath,
|
||||
SYS_STRING_VIEW commandLine,
|
||||
SYS_STRING_VIEW currentDirectory) {
|
||||
if (!proc || imagePath.Length == 0) return STATUS_INVALID_PARAMETER;
|
||||
if (!SysSvIsValid(imagePath) || !SysSvIsValid(commandLine) || !SysSvIsValid(currentDirectory))
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
if (SysSvContainsByte(imagePath, '\0') ||
|
||||
SysSvContainsByte(commandLine, '\0') ||
|
||||
SysSvContainsByte(currentDirectory, '\0'))
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
SYS_STRING_VIEW finalCommandLine = commandLine.Length ? commandLine : imagePath;
|
||||
SYS_STRING_VIEW finalCwdRel = currentDirectory;
|
||||
if (finalCwdRel.Length == 0 && proc->CurrentDirectoryLength)
|
||||
finalCwdRel = SysSvFromParts(proc->CurrentDirectory, proc->CurrentDirectoryLength);
|
||||
|
||||
const char* finalCommandLine = (commandLine && commandLine[0]) ? commandLine : imagePath;
|
||||
const char* finalCwdRel = currentDirectory ? currentDirectory : proc->CurrentDirectory;
|
||||
char finalCwd[SYS_CWD_MAX];
|
||||
KiFormatNativeCwd(proc, finalCwdRel, finalCwd, sizeof(finalCwd));
|
||||
size_t finalCwdLength = 0;
|
||||
KSTATUS s = KiFormatNativeCwdV(proc, finalCwdRel, finalCwd, sizeof(finalCwd), &finalCwdLength);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
|
||||
KiFreePartialProcessEnvironment(proc);
|
||||
|
||||
KSTATUS s = KiCopyEnvironmentString(imagePath, &proc->UserImagePathBase, &proc->UserImagePathSize);
|
||||
s = KiCopyEnvironmentStringView(imagePath, &proc->UserImagePathBase, &proc->UserImagePathSize);
|
||||
if (!KSUCCESS(s)) goto fail;
|
||||
|
||||
s = KiCopyEnvironmentString(finalCommandLine, &proc->UserCmdlineBase, &proc->UserCmdlineSize);
|
||||
s = KiCopyEnvironmentStringView(finalCommandLine, &proc->UserCmdlineBase, &proc->UserCmdlineSize);
|
||||
if (!KSUCCESS(s)) goto fail;
|
||||
|
||||
s = KiCopyEnvironmentStringFixed(finalCwd, SYS_CWD_MAX, &proc->UserCwdBase, &proc->UserCwdSize);
|
||||
s = KiCopyEnvironmentStringViewFixed(SysSvFromParts(finalCwd, finalCwdLength),
|
||||
SYS_CWD_MAX,
|
||||
&proc->UserCwdBase,
|
||||
&proc->UserCwdSize);
|
||||
if (!KSUCCESS(s)) goto fail;
|
||||
|
||||
SYS_PEB* peb = (SYS_PEB*)MmAllocateUserMemory(sizeof(SYS_PEB));
|
||||
@@ -312,12 +356,9 @@ KSTATUS KeSetupUserProcessEnvironment(PROCESS* proc,
|
||||
peb->Magic = SYS_PEB_MAGIC;
|
||||
peb->Version = SYS_ENV_VERSION;
|
||||
peb->ProcessId = proc->ProcessId;
|
||||
peb->ImagePath = (const char*)proc->UserImagePathBase;
|
||||
peb->ImagePathLength = proc->UserImagePathSize ? proc->UserImagePathSize - 1 : 0;
|
||||
peb->CommandLine = (const char*)proc->UserCmdlineBase;
|
||||
peb->CommandLineLength = proc->UserCmdlineSize ? proc->UserCmdlineSize - 1 : 0;
|
||||
peb->CurrentDirectory = (const char*)proc->UserCwdBase;
|
||||
peb->CurrentDirectoryLength = strlen(finalCwd);
|
||||
peb->ImagePath = SysSvFromParts((const char*)proc->UserImagePathBase, imagePath.Length);
|
||||
peb->CommandLine = SysSvFromParts((const char*)proc->UserCmdlineBase, finalCommandLine.Length);
|
||||
peb->CurrentDirectory = SysSvFromParts((const char*)proc->UserCwdBase, finalCwdLength);
|
||||
|
||||
proc->UserPebBase = (uintptr_t)peb;
|
||||
proc->UserPebSize = sizeof(SYS_PEB);
|
||||
@@ -329,16 +370,56 @@ fail:
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// KeExitProcess
|
||||
// Process exit / termination
|
||||
// ---------------------------------------------------------------------------
|
||||
static void KiCompleteProcessExitIfLastThread(PROCESS* process) {
|
||||
if (!process) return;
|
||||
|
||||
uintptr_t flags = KeAcquireSpinlock(&process->HandleLock);
|
||||
uint32_t threadCount = process->ThreadCount;
|
||||
KeReleaseSpinlock(&process->HandleLock, flags);
|
||||
|
||||
if (threadCount == 0 && _InterlockedExchange(&process->Exited, 1) == 0) {
|
||||
if (process->ExitEvent) KeSignalEvent(process->ExitEvent);
|
||||
}
|
||||
}
|
||||
|
||||
void KeExitProcess(PROCESS* process, int exitCode) {
|
||||
if (!process) return;
|
||||
process->ExitCode = exitCode;
|
||||
// Wake any threads waiting for this process to finish.
|
||||
if (process->ExitEvent) KeSignalEvent(process->ExitEvent);
|
||||
// The last thread exiting via KeExitThread will drop the process refcount.
|
||||
// This function is a policy hook; actual cleanup is in KiProcessDestroy.
|
||||
ObDereferenceObject(&process->Header);
|
||||
_InterlockedExchange(&process->Terminating, 1);
|
||||
|
||||
// The calling thread exits immediately after this in SysExitProcess. Do
|
||||
// not drop the process object here: each thread owns one process reference,
|
||||
// and KiThreadDestroy releases that reference after unlinking the thread.
|
||||
KiCompleteProcessExitIfLastThread(process);
|
||||
}
|
||||
|
||||
KSTATUS KeTerminateProcess(PROCESS* process, int exitCode) {
|
||||
if (!process) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
process->ExitCode = exitCode;
|
||||
_InterlockedExchange(&process->Terminating, 1);
|
||||
|
||||
// Wake alertable waiters so they can notice Terminating at the syscall/
|
||||
// wait boundary. This is intentionally conservative: fully asynchronous
|
||||
// forced thread teardown needs object-specific wait-list locking and is a
|
||||
// larger process-lifecycle project.
|
||||
uintptr_t flags = KeAcquireSpinlock(&process->HandleLock);
|
||||
LIST_ENTRY* head = &process->ThreadList;
|
||||
for (LIST_ENTRY* node = head->Fwd; node != head; node = node->Fwd) {
|
||||
THREAD* t = CONTAINING_RECORD(node, THREAD, ProcessLink);
|
||||
if (t != KeGetCurrentThread())
|
||||
(void)KeAlertThread(t);
|
||||
}
|
||||
KeReleaseSpinlock(&process->HandleLock, flags);
|
||||
|
||||
KiCompleteProcessExitIfLastThread(process);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
int KeIsProcessTerminating(PROCESS* process) {
|
||||
return process && process->Terminating != 0;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -353,15 +434,17 @@ KSTATUS KeGetProcessExitCode(PROCESS* process, int* exitCodeOut) {
|
||||
// ---------------------------------------------------------------------------
|
||||
// Handle table
|
||||
// ---------------------------------------------------------------------------
|
||||
KSTATUS KeAllocateHandle(PROCESS* process, OBJECT* object, uint32_t* handleOut) {
|
||||
if (!process || !object || !handleOut) return STATUS_INVALID_PARAMETER;
|
||||
KSTATUS KeAllocateHandleWithRights(PROCESS* process, OBJECT* object, uint32_t rights, uint32_t* handleOut) {
|
||||
if (!process || !object || !handleOut || rights == 0) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
uintptr_t flags = KeAcquireSpinlock(&process->HandleLock);
|
||||
|
||||
for (int i = 1; i < HANDLE_TABLE_SIZE; i++) {
|
||||
if (!process->Handles[i]) {
|
||||
if (!process->Handles[i].Object) {
|
||||
ObReferenceObject(object);
|
||||
process->Handles[i] = object;
|
||||
process->Handles[i].Object = object;
|
||||
process->Handles[i].Rights = rights;
|
||||
process->Handles[i].Flags = 0;
|
||||
*handleOut = (uint32_t)i;
|
||||
KeReleaseSpinlock(&process->HandleLock, flags);
|
||||
return STATUS_SUCCESS;
|
||||
@@ -372,13 +455,19 @@ KSTATUS KeAllocateHandle(PROCESS* process, OBJECT* object, uint32_t* handleOut)
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
KSTATUS KeAllocateHandle(PROCESS* process, OBJECT* object, uint32_t* handleOut) {
|
||||
return KeAllocateHandleWithRights(process, object, HANDLE_RIGHT_ALL, handleOut);
|
||||
}
|
||||
|
||||
void KeCloseHandle(PROCESS* process, uint32_t handle) {
|
||||
if (!process || handle == 0 || handle >= HANDLE_TABLE_SIZE) return;
|
||||
|
||||
uintptr_t flags = KeAcquireSpinlock(&process->HandleLock);
|
||||
OBJECT* obj = process->Handles[handle];
|
||||
OBJECT* obj = process->Handles[handle].Object;
|
||||
if (obj) {
|
||||
process->Handles[handle] = (OBJECT *)0;
|
||||
process->Handles[handle].Object = (OBJECT*)0;
|
||||
process->Handles[handle].Rights = 0;
|
||||
process->Handles[handle].Flags = 0;
|
||||
KeReleaseSpinlock(&process->HandleLock, flags);
|
||||
ObDereferenceObject(obj);
|
||||
return;
|
||||
@@ -386,17 +475,33 @@ void KeCloseHandle(PROCESS* process, uint32_t handle) {
|
||||
KeReleaseSpinlock(&process->HandleLock, flags);
|
||||
}
|
||||
|
||||
OBJECT* KeLookupHandle(PROCESS* process, uint32_t handle) {
|
||||
OBJECT* KeLookupHandleWithRights(PROCESS* process, uint32_t handle, uint32_t requiredRights) {
|
||||
if (!process || handle == 0 || handle >= HANDLE_TABLE_SIZE)
|
||||
return (OBJECT *)0;
|
||||
return (OBJECT*)0;
|
||||
|
||||
uintptr_t flags = KeAcquireSpinlock(&process->HandleLock);
|
||||
OBJECT* obj = process->Handles[handle];
|
||||
HANDLE_ENTRY* entry = &process->Handles[handle];
|
||||
OBJECT* obj = entry->Object;
|
||||
if (obj && requiredRights && ((entry->Rights & requiredRights) != requiredRights))
|
||||
obj = (OBJECT*)0;
|
||||
if (obj) ObReferenceObject(obj);
|
||||
KeReleaseSpinlock(&process->HandleLock, flags);
|
||||
return obj;
|
||||
}
|
||||
|
||||
OBJECT* KeLookupHandle(PROCESS* process, uint32_t handle) {
|
||||
return KeLookupHandleWithRights(process, handle, 0);
|
||||
}
|
||||
|
||||
uint32_t KeGetHandleRights(PROCESS* process, uint32_t handle) {
|
||||
if (!process || handle == 0 || handle >= HANDLE_TABLE_SIZE) return 0;
|
||||
|
||||
uintptr_t flags = KeAcquireSpinlock(&process->HandleLock);
|
||||
uint32_t rights = process->Handles[handle].Object ? process->Handles[handle].Rights : 0;
|
||||
KeReleaseSpinlock(&process->HandleLock, flags);
|
||||
return rights;
|
||||
}
|
||||
|
||||
PROCESS* KeGetProcessById(uint32_t pid) {
|
||||
KiProcessInit();
|
||||
uintptr_t flags = KeAcquireSpinlock(&gProcessListLock);
|
||||
|
||||
Reference in new issue
Block a user