implement generic I/O async request object to replace file-specific async requests, refactor lwIP network stack to dispatch requests through IRPs with cancellation support, add cancellation polling to lwIP accept and receive operations using LwipSocketWaitRecvNetbuf and LwipSocketWaitAccept, introduce NetSubmitSocketIrp for routing socket operations via device IRPs, track network IRP statistics with SYS_NET_IRP_STATS, add process module lock spinlock and reference counting for process modules, implement dynamic module loading and unloading via user module handles, add POSIX dynamic loader APIs including dlopen, dlsym, dlerror, and dlclose, introduce PosixStart entry point for posix applications, add new native smoke tests for net IRPs.

This commit is contained in:
maksw committed 2026-06-27 10:37:53 +02:00
1 parent ed3d065abd
commit 1f5477cf66
32 files changed
+3713 -551

No files matched your search

+185 -19
View File
@@ -10,6 +10,7 @@
#include <kernel/mm_virt.h>
#include <kernel/ke_debug.h>
#include <kernel/ke_system_root.h>
#include <ntlite/syscall.h>
#ifndef LDR_DEBUG_VERBOSE
#define LDR_DEBUG_VERBOSE 0
@@ -326,6 +327,24 @@ void* LdrGetExportForProcess(PROCESS* process, const char* moduleName, const cha
return KiGetExportAtBase(base, functionName);
}
// Looks up an export in a specific process module mapping.
void* LdrGetModuleExportForProcess(PROCESS* process, uintptr_t imageBase, const char* functionName) {
if (!process || !imageBase || !functionName) return (void*)0;
uintptr_t flags = KeAcquireSpinlock(&process->ModuleLock);
int found = 0;
for (uint32_t i = 0; i < process->ModuleCount; i++) {
if (process->Modules[i].Base == imageBase) {
found = 1;
break;
}
}
KeReleaseSpinlock(&process->ModuleLock, flags);
if (!found) return (void*)0;
return KiGetExportAtBase(imageBase, functionName);
}
// Implements the ldr Get Image Size operation.
size_t LdrGetImageSize(uintptr_t base) {
if (!base) return 0;
@@ -559,7 +578,7 @@ static KSTATUS LdrResolveImportsCommon(
if (!modBase) {
KSTATUS s =
LdrLoadModuleForProcess(process, dllName, &modBase);
LdrLoadModuleForProcess(process, dllName, LDR_MODULE_LOAD_IMPORT, &modBase);
if (!KSUCCESS(s)) {
DbgPrint(
@@ -674,38 +693,101 @@ KSTATUS LdrLoadImageFileForProcess(PROCESS* process, FILE_OBJECT* file, uintptr_
return STATUS_SUCCESS;
}
// Implements the ldr Register Process Module operation.
static KSTATUS LdrRegisterProcessModule(PROCESS* process, const char* name, uintptr_t base) {
if (!process || !name || !base) return STATUS_INVALID_PARAMETER;
// Converts a process module entry into the public module ABI.
static void KiFillProcessModuleInfo(const PROCESS_MODULE* mod, SYS_MODULE_INFO* info) {
memset(info, 0, sizeof(*info));
info->Size = sizeof(*info);
info->Version = SYS_MODULE_INFO_VERSION;
info->Flags = mod->Flags;
if (mod->PublicRefCount)
info->Flags |= SYS_MODULE_FLAG_PUBLIC_REF;
if (mod->ImportRefCount)
info->Flags |= SYS_MODULE_FLAG_IMPORT_PINNED;
if (mod->PublicRefCount && mod->ImportRefCount == 0)
info->Flags |= SYS_MODULE_FLAG_UNLOADABLE;
info->Base = mod->Base;
info->ImageSize = mod->Size;
info->EntryPoint = mod->EntryPoint;
info->PublicRefCount = mod->PublicRefCount;
info->ImportRefCount = mod->ImportRefCount;
info->TotalRefCount = mod->PublicRefCount + mod->ImportRefCount;
strncpy(info->Name, mod->Name, sizeof(info->Name) - 1);
info->Name[sizeof(info->Name) - 1] = '\0';
}
// Adds one reference of the requested class to an existing process module.
static void KiReferenceProcessModule(PROCESS_MODULE* mod, uint32_t loadFlags) {
if (loadFlags & LDR_MODULE_LOAD_PUBLIC)
mod->PublicRefCount++;
if (loadFlags & LDR_MODULE_LOAD_IMPORT)
mod->ImportRefCount++;
}
// Finds a process module by canonical name while the caller owns ModuleLock.
static PROCESS_MODULE* KiFindProcessModuleByNameLocked(PROCESS* process, const char* name) {
for (uint32_t i = 0; i < process->ModuleCount; i++) {
if (_stricmp(process->Modules[i].Name, name) == 0) {
return STATUS_SUCCESS;
}
if (_stricmp(process->Modules[i].Name, name) == 0)
return &process->Modules[i];
}
return (PROCESS_MODULE*)0;
}
// Finds a process module by image base while the caller owns ModuleLock.
static PROCESS_MODULE* KiFindProcessModuleByBaseLocked(PROCESS* process, uintptr_t base) {
for (uint32_t i = 0; i < process->ModuleCount; i++) {
if (process->Modules[i].Base == base)
return &process->Modules[i];
}
return (PROCESS_MODULE*)0;
}
// Registers a mapped process module or records a reference to an existing one.
static KSTATUS LdrRegisterProcessModule(PROCESS* process, const char* name, uintptr_t base, uint32_t loadFlags, uintptr_t* registeredBaseOut) {
if (!process || !name || !base || !loadFlags) return STATUS_INVALID_PARAMETER;
if (registeredBaseOut) *registeredBaseOut = 0;
uintptr_t flags = KeAcquireSpinlock(&process->ModuleLock);
PROCESS_MODULE* existing = KiFindProcessModuleByNameLocked(process, name);
if (existing) {
KiReferenceProcessModule(existing, loadFlags);
if (registeredBaseOut) *registeredBaseOut = existing->Base;
KeReleaseSpinlock(&process->ModuleLock, flags);
return STATUS_ALREADY_EXISTS;
}
if (process->ModuleCount >= PROCESS_MODULE_MAX) return STATUS_NO_MEMORY;
if (process->ModuleCount >= PROCESS_MODULE_MAX) {
KeReleaseSpinlock(&process->ModuleLock, flags);
return STATUS_NO_MEMORY;
}
PROCESS_MODULE* mod = &process->Modules[process->ModuleCount++];
strncpy(mod->Name, name, 31);
mod->Name[31] = '\0';
memset(mod, 0, sizeof(*mod));
strncpy(mod->Name, name, sizeof(mod->Name) - 1);
mod->Name[sizeof(mod->Name) - 1] = '\0';
mod->Base = base;
mod->Size = LdrGetMappedImageSize(process, base);
mod->EntryPoint = LdrGetEntryPoint(base);
KiReferenceProcessModule(mod, loadFlags);
if (registeredBaseOut) *registeredBaseOut = mod->Base;
KeReleaseSpinlock(&process->ModuleLock, flags);
return STATUS_SUCCESS;
}
// Implements the ldr Load Module For Process operation.
KSTATUS LdrLoadModuleForProcess(PROCESS* process, const char* filename, uintptr_t* baseOut) {
if (!process || !filename) return STATUS_INVALID_PARAMETER;
// Loads a DLL-like user module into a process and records the requested reference.
KSTATUS LdrLoadModuleForProcess(PROCESS* process, const char* filename, uint32_t loadFlags, uintptr_t* baseOut) {
if (!process || !filename || !loadFlags) return STATUS_INVALID_PARAMETER;
filename = KiCanonicalModuleName(filename);
for (uint32_t i = 0; i < process->ModuleCount; i++) {
if (_stricmp(process->Modules[i].Name, filename) == 0) {
if (baseOut) *baseOut = process->Modules[i].Base;
return STATUS_SUCCESS;
}
uintptr_t flags = KeAcquireSpinlock(&process->ModuleLock);
PROCESS_MODULE* existing = KiFindProcessModuleByNameLocked(process, filename);
if (existing) {
KiReferenceProcessModule(existing, loadFlags);
if (baseOut) *baseOut = existing->Base;
KeReleaseSpinlock(&process->ModuleLock, flags);
return STATUS_SUCCESS;
}
KeReleaseSpinlock(&process->ModuleLock, flags);
FILE_OBJECT* f;
KSTATUS s = IoOpenFile(SysSvFromCstr(filename), &f);
@@ -750,7 +832,13 @@ KSTATUS LdrLoadModuleForProcess(PROCESS* process, const char* filename, uintptr_
return s;
}
s = LdrRegisterProcessModule(process, filename, imageBase);
uintptr_t registeredBase = 0;
s = LdrRegisterProcessModule(process, filename, imageBase, loadFlags, &registeredBase);
if (s == STATUS_ALREADY_EXISTS) {
KiFreeLoadedImageForProcess(process, imageBase, true);
imageBase = registeredBase;
s = STATUS_SUCCESS;
}
if (!KSUCCESS(s)) {
KiFreeLoadedImageForProcess(process, imageBase, true);
return s;
@@ -762,6 +850,84 @@ KSTATUS LdrLoadModuleForProcess(PROCESS* process, const char* filename, uintptr_
return STATUS_SUCCESS;
}
// Releases one public module load reference and unmaps the image when no references remain.
KSTATUS LdrUnloadModuleForProcess(PROCESS* process, uintptr_t imageBase) {
if (!process || !imageBase) return STATUS_INVALID_PARAMETER;
char name[PROCESS_MODULE_NAME_MAX];
uintptr_t base = 0;
int shouldUnmap = 0;
uintptr_t flags = KeAcquireSpinlock(&process->ModuleLock);
PROCESS_MODULE* mod = KiFindProcessModuleByBaseLocked(process, imageBase);
if (!mod) {
KeReleaseSpinlock(&process->ModuleLock, flags);
return STATUS_NOT_FOUND;
}
if (mod->PublicRefCount == 0) {
KeReleaseSpinlock(&process->ModuleLock, flags);
return STATUS_INVALID_PARAMETER;
}
mod->PublicRefCount--;
if (mod->PublicRefCount == 0 && mod->ImportRefCount == 0) {
base = mod->Base;
strncpy(name, mod->Name, sizeof(name) - 1);
name[sizeof(name) - 1] = '\0';
uint32_t index = (uint32_t)(mod - process->Modules);
if (index + 1 < process->ModuleCount) {
memmove(&process->Modules[index],
&process->Modules[index + 1],
(process->ModuleCount - index - 1) * sizeof(process->Modules[0]));
}
process->ModuleCount--;
shouldUnmap = 1;
}
KeReleaseSpinlock(&process->ModuleLock, flags);
if (shouldUnmap) {
LdrDbg("LDR: unload module pid=%u name=%s base=%016llx\n",
process->ProcessId, name, (unsigned long long)base);
KiFreeLoadedImageForProcess(process, base, true);
}
return STATUS_SUCCESS;
}
// Queries one loaded process module by image base.
KSTATUS LdrQueryModuleForProcess(PROCESS* process, uintptr_t imageBase, SYS_MODULE_INFO* infoOut) {
if (!process || !imageBase || !infoOut) return STATUS_INVALID_PARAMETER;
uintptr_t flags = KeAcquireSpinlock(&process->ModuleLock);
PROCESS_MODULE* mod = KiFindProcessModuleByBaseLocked(process, imageBase);
if (!mod) {
KeReleaseSpinlock(&process->ModuleLock, flags);
return STATUS_NOT_FOUND;
}
KiFillProcessModuleInfo(mod, infoOut);
KeReleaseSpinlock(&process->ModuleLock, flags);
return STATUS_SUCCESS;
}
// Copies a bounded snapshot of the process module table.
KSTATUS LdrCopyProcessModuleInfo(PROCESS* process, SYS_MODULE_INFO* infoOut, size_t maxCount, size_t* countOut) {
if (!process || !countOut) return STATUS_INVALID_PARAMETER;
uintptr_t flags = KeAcquireSpinlock(&process->ModuleLock);
size_t count = process->ModuleCount;
*countOut = count;
size_t toCopy = count;
if (toCopy > maxCount) toCopy = maxCount;
if (toCopy && !infoOut) {
KeReleaseSpinlock(&process->ModuleLock, flags);
return STATUS_INVALID_PARAMETER;
}
for (size_t i = 0; i < toCopy; i++)
KiFillProcessModuleInfo(&process->Modules[i], &infoOut[i]);
KeReleaseSpinlock(&process->ModuleLock, flags);
return (maxCount < count) ? STATUS_BUFFER_TOO_SMALL : STATUS_SUCCESS;
}
// Loads a boot/kernel PE image from a raw memory buffer into kernel space.
static KSTATUS KiLdrLoadKernelImageFromBuffer(const void* buffer, size_t size, uintptr_t* baseOut) {
if (!buffer || !size || !baseOut) return STATUS_INVALID_PARAMETER;