move POSIX spawn, exec and child tracking into posixsrv, keep process transactions alive across reconnects and preserve stable PIDs across image replacement, flesh out spawn with ordered file actions, process-group selection and signal inheritance, implement execve with bootstrap validation and rollback before retiring the old process, add vfork children that share the native process while keeping separate POSIX descriptor and signal state, replace local spawn bookkeeping with child reaping, nonblocking and process-group waits and orphan cleanup, add signal dispositions, per-thread masks, pending delivery, process/group signalling and alarms, translate native exceptions into POSIX signals and inherit masks when creating threads, make pipe waits interruptible and raise SIGPIPE for broken pipes, pass arguments and environment into main and add getenv/environ, add direct user APC notifications that can run without an alertable wait, add current-thread capabilities and resume-and-wait, let accepted IPC endpoints open restricted peer process capabilities and preserve caller security during spawn and exec, make process preparation reusable and improve DLL lookup across current, executable and fallback directories, move keyboard repeat into RSSRV so PS/2 and USB share one repeat policy, fix video presentation, report launch failure stages and status codes, mooaaar tests.
This commit is contained in:
1 parent
73abd6f90d
commit
899225f551
57 files changed
+8817
-1216
No files matched your search
@@ -13,7 +13,7 @@
|
||||
#define NTL_MODULE_CONTEXT_MAGIC 0x4D4F444Cu
|
||||
#define NTL_MODULE_PAGE_SIZE 4096u
|
||||
#define NTL_LOADER_DATA_MAGIC 0x30444C4Eu
|
||||
#define NTL_LOADER_DATA_VERSION 3u
|
||||
#define NTL_LOADER_DATA_VERSION 4u
|
||||
|
||||
typedef struct NTL_LOADER_IMAGE_RECORD {
|
||||
uintptr_t Base;
|
||||
@@ -22,6 +22,11 @@ typedef struct NTL_LOADER_IMAGE_RECORD {
|
||||
char Name[NTL_MODULE_NAME_MAX];
|
||||
} NTL_LOADER_IMAGE_RECORD;
|
||||
|
||||
typedef struct NTL_LOADER_STRING_RECORD {
|
||||
uint32_t Offset;
|
||||
uint32_t Length;
|
||||
} NTL_LOADER_STRING_RECORD;
|
||||
|
||||
typedef struct NTL_LOADER_DATA {
|
||||
uint32_t Magic;
|
||||
uint32_t Version;
|
||||
@@ -31,6 +36,10 @@ typedef struct NTL_LOADER_DATA {
|
||||
uint32_t CurrentDirectoryLength;
|
||||
uint32_t StartupDataOffset;
|
||||
uint32_t StartupDataLength;
|
||||
uint32_t ArgumentVectorOffset;
|
||||
uint32_t ArgumentCount;
|
||||
uint32_t EnvironmentVectorOffset;
|
||||
uint32_t EnvironmentCount;
|
||||
NTL_LOADER_IMAGE_RECORD Images[];
|
||||
} NTL_LOADER_DATA;
|
||||
|
||||
@@ -48,8 +57,12 @@ typedef struct NTL_MODULE_ENTRY {
|
||||
struct NTL_MODULE_CONTEXT {
|
||||
uint32_t Magic;
|
||||
SYS_HANDLE ProcessHandle;
|
||||
SYS_HANDLE ModuleRootHandle;
|
||||
SYS_STRING_VIEW ModuleDirectory;
|
||||
SYS_HANDLE PrimaryModuleRootHandle;
|
||||
SYS_STRING_VIEW PrimaryModuleDirectory;
|
||||
SYS_HANDLE SecondaryModuleRootHandle;
|
||||
SYS_STRING_VIEW SecondaryModuleDirectory;
|
||||
SYS_HANDLE FallbackModuleRootHandle;
|
||||
SYS_STRING_VIEW FallbackModuleDirectory;
|
||||
NTL_MODULE_NAME_RESOLVER Resolver;
|
||||
void* ResolverContext;
|
||||
NTL_MODULE_ENTRY* Head;
|
||||
@@ -202,27 +215,6 @@ static KSTATUS NtlpCanonicalName(NTL_MODULE_CONTEXT* context,
|
||||
return NtlpCopyName(*canonicalOut, scratch);
|
||||
}
|
||||
|
||||
// Builds the capability-relative dependency path beneath the configured module directory.
|
||||
static KSTATUS NtlpBuildModulePath(NTL_MODULE_CONTEXT* context,
|
||||
SYS_STRING_VIEW canonical,
|
||||
char out[SYS_PATH_MAX]) {
|
||||
if (!context || !out) return NTLSTATUS_INVALID_PARAMETER;
|
||||
char name[NTL_MODULE_NAME_MAX];
|
||||
KSTATUS status = NtlpCopyName(canonical, name);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
size_t dirLength = context->ModuleDirectory.Length;
|
||||
if (!SysSvIsValid(context->ModuleDirectory) || SysSvContainsByte(context->ModuleDirectory, '\0'))
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
size_t total = dirLength + (dirLength ? 1u : 0u) + canonical.Length;
|
||||
if (total + 1u > SYS_PATH_MAX) return NTLSTATUS_BUFFER_TOO_SMALL;
|
||||
if (dirLength) memcpy(out, context->ModuleDirectory.Data, dirLength);
|
||||
size_t pos = dirLength;
|
||||
if (dirLength) out[pos++] = '/';
|
||||
memcpy(out + pos, canonical.Data, canonical.Length);
|
||||
out[total] = '\0';
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Replaces the final component of an explicit module path with its canonical policy name.
|
||||
static KSTATUS NtlpBuildCanonicalPath(SYS_STRING_VIEW path,
|
||||
SYS_STRING_VIEW canonical,
|
||||
@@ -246,23 +238,54 @@ static KSTATUS NtlpBuildCanonicalPath(SYS_STRING_VIEW path,
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Opens one canonical dependency through the caller-supplied module-root capability.
|
||||
// Opens one canonical dependency from a single capability-relative search location.
|
||||
static KSTATUS NtlpOpenDependencyAt(SYS_HANDLE rootHandle,
|
||||
SYS_STRING_VIEW directory,
|
||||
SYS_STRING_VIEW canonical,
|
||||
SYS_HANDLE* fileOut) {
|
||||
if (rootHandle == SYS_HANDLE_INVALID || !fileOut || !SysSvIsValid(directory) ||
|
||||
SysSvContainsByte(directory, '\0'))
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
*fileOut = SYS_HANDLE_INVALID;
|
||||
|
||||
char path[SYS_PATH_MAX];
|
||||
char name[NTL_MODULE_NAME_MAX];
|
||||
KSTATUS status = NtlpCopyName(canonical, name);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
size_t dirLength = directory.Length;
|
||||
size_t total = dirLength + (dirLength ? 1u : 0u) + canonical.Length;
|
||||
if (total + 1u > sizeof(path)) return NTLSTATUS_BUFFER_TOO_SMALL;
|
||||
if (dirLength) memcpy(path, directory.Data, dirLength);
|
||||
size_t pos = dirLength;
|
||||
if (dirLength) path[pos++] = '/';
|
||||
memcpy(path + pos, canonical.Data, canonical.Length);
|
||||
path[total] = '\0';
|
||||
|
||||
SYS_OPEN_FILE_AT_REQUEST open = SysMakeOpenFileAtRequest(rootHandle, SysSvFromCstr(path),
|
||||
SYS_FILE_ACCESS_READ | SYS_FILE_ACCESS_QUERY,
|
||||
SYS_FILE_OPEN_EXISTING,
|
||||
SYS_FILE_FLAG_NONE, fileOut);
|
||||
return SysOpenFileAt(&open);
|
||||
}
|
||||
|
||||
// Searches the available current-directory root, then image-private and configured fallback roots.
|
||||
static KSTATUS NtlpOpenDependency(NTL_MODULE_CONTEXT* context,
|
||||
SYS_STRING_VIEW canonical,
|
||||
SYS_HANDLE* fileOut) {
|
||||
if (!context || context->ModuleRootHandle == SYS_HANDLE_INVALID || !fileOut)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
*fileOut = SYS_HANDLE_INVALID;
|
||||
char path[SYS_PATH_MAX];
|
||||
KSTATUS status = NtlpBuildModulePath(context, canonical, path);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
SYS_OPEN_FILE_AT_REQUEST open = SysMakeOpenFileAtRequest(context->ModuleRootHandle,
|
||||
SysSvFromCstr(path),
|
||||
SYS_FILE_ACCESS_READ | SYS_FILE_ACCESS_QUERY,
|
||||
SYS_FILE_OPEN_EXISTING,
|
||||
SYS_FILE_FLAG_NONE,
|
||||
fileOut);
|
||||
return SysOpenFileAt(&open);
|
||||
if (!context || !fileOut) return NTLSTATUS_INVALID_PARAMETER;
|
||||
KSTATUS status = NtlpOpenDependencyAt(context->PrimaryModuleRootHandle,
|
||||
context->PrimaryModuleDirectory, canonical, fileOut);
|
||||
if (status != NTLSTATUS_NOT_FOUND) return status;
|
||||
|
||||
if (context->SecondaryModuleRootHandle != SYS_HANDLE_INVALID) {
|
||||
status = NtlpOpenDependencyAt(context->SecondaryModuleRootHandle,
|
||||
context->SecondaryModuleDirectory, canonical, fileOut);
|
||||
if (status != NTLSTATUS_NOT_FOUND) return status;
|
||||
}
|
||||
|
||||
if (context->FallbackModuleRootHandle == SYS_HANDLE_INVALID) return NTLSTATUS_NOT_FOUND;
|
||||
return NtlpOpenDependencyAt(context->FallbackModuleRootHandle,
|
||||
context->FallbackModuleDirectory, canonical, fileOut);
|
||||
}
|
||||
|
||||
// Publishes a mapped image before import binding so cyclic dependencies can resolve it.
|
||||
@@ -356,14 +379,22 @@ static KSTATUS NtlpResolveImport(void* opaque,
|
||||
|
||||
// Creates loader state for a child process or seeds the current process from PEB loader data.
|
||||
KSTATUS NtlpCreateModuleContext(SYS_HANDLE processHandle,
|
||||
SYS_HANDLE moduleRootHandle,
|
||||
SYS_STRING_VIEW moduleDirectory,
|
||||
SYS_HANDLE primaryModuleRootHandle,
|
||||
SYS_STRING_VIEW primaryModuleDirectory,
|
||||
SYS_HANDLE secondaryModuleRootHandle,
|
||||
SYS_STRING_VIEW secondaryModuleDirectory,
|
||||
SYS_HANDLE fallbackModuleRootHandle,
|
||||
SYS_STRING_VIEW fallbackModuleDirectory,
|
||||
NTL_MODULE_NAME_RESOLVER resolver,
|
||||
void* resolverContext,
|
||||
int seedCurrentProcess,
|
||||
NTL_MODULE_CONTEXT** contextOut) {
|
||||
if (!contextOut || moduleRootHandle == SYS_HANDLE_INVALID || !SysSvIsValid(moduleDirectory) ||
|
||||
SysSvContainsByte(moduleDirectory, '\0'))
|
||||
if (!contextOut || primaryModuleRootHandle == SYS_HANDLE_INVALID ||
|
||||
!SysSvIsValid(primaryModuleDirectory) || SysSvContainsByte(primaryModuleDirectory, '\0') ||
|
||||
(secondaryModuleRootHandle != SYS_HANDLE_INVALID &&
|
||||
(!SysSvIsValid(secondaryModuleDirectory) || SysSvContainsByte(secondaryModuleDirectory, '\0'))) ||
|
||||
(fallbackModuleRootHandle != SYS_HANDLE_INVALID &&
|
||||
(!SysSvIsValid(fallbackModuleDirectory) || SysSvContainsByte(fallbackModuleDirectory, '\0'))))
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
*contextOut = 0;
|
||||
|
||||
@@ -372,8 +403,12 @@ KSTATUS NtlpCreateModuleContext(SYS_HANDLE processHandle,
|
||||
if (!KSUCCESS(status)) return status;
|
||||
context->Magic = NTL_MODULE_CONTEXT_MAGIC;
|
||||
context->ProcessHandle = processHandle;
|
||||
context->ModuleRootHandle = moduleRootHandle;
|
||||
context->ModuleDirectory = moduleDirectory;
|
||||
context->PrimaryModuleRootHandle = primaryModuleRootHandle;
|
||||
context->PrimaryModuleDirectory = primaryModuleDirectory;
|
||||
context->SecondaryModuleRootHandle = secondaryModuleRootHandle;
|
||||
context->SecondaryModuleDirectory = secondaryModuleDirectory;
|
||||
context->FallbackModuleRootHandle = fallbackModuleRootHandle;
|
||||
context->FallbackModuleDirectory = fallbackModuleDirectory;
|
||||
context->Resolver = resolver;
|
||||
context->ResolverContext = resolverContext;
|
||||
context->OwnsStorage = 1u;
|
||||
@@ -495,9 +530,26 @@ KSTATUS NtlpLoadMainImage(NTL_MODULE_CONTEXT* context,
|
||||
return NtlLoadPeImage(&load);
|
||||
}
|
||||
|
||||
// Validates one caller-owned process string vector and returns its serialized string bytes.
|
||||
static KSTATUS NtlpMeasureProcessVector(NTL_PROCESS_STRING_VECTOR vector, size_t* bytesOut) {
|
||||
if (!bytesOut || (vector.Count && !vector.Entries)) return NTLSTATUS_INVALID_PARAMETER;
|
||||
size_t bytes = 0;
|
||||
for (uint32_t i = 0; i < vector.Count; ++i) {
|
||||
SYS_STRING_VIEW entry = vector.Entries[i];
|
||||
if (!SysSvIsValid(entry) || SysSvContainsByte(entry, '\0') || entry.Length > UINT32_MAX)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
if (entry.Length > SIZE_MAX - bytes - 1u) return NTLSTATUS_NO_MEMORY;
|
||||
bytes += entry.Length + 1u;
|
||||
}
|
||||
*bytesOut = bytes;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Serializes startup dependency metadata into a read-only child-owned VAD.
|
||||
KSTATUS NtlpBuildLoaderData(NTL_MODULE_CONTEXT* context,
|
||||
SYS_STRING_VIEW currentDirectory,
|
||||
NTL_PROCESS_STRING_VECTOR arguments,
|
||||
NTL_PROCESS_STRING_VECTOR environment,
|
||||
const void* startupData,
|
||||
size_t startupDataSize,
|
||||
void** loaderDataOut) {
|
||||
@@ -510,10 +562,28 @@ KSTATUS NtlpBuildLoaderData(NTL_MODULE_CONTEXT* context,
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
*loaderDataOut = 0;
|
||||
|
||||
size_t argumentStringBytes = 0;
|
||||
size_t environmentStringBytes = 0;
|
||||
KSTATUS status = NtlpMeasureProcessVector(arguments, &argumentStringBytes);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
status = NtlpMeasureProcessVector(environment, &environmentStringBytes);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
|
||||
size_t recordsBytes = (size_t)context->Count * sizeof(NTL_LOADER_IMAGE_RECORD);
|
||||
if (context->Count && recordsBytes / sizeof(NTL_LOADER_IMAGE_RECORD) != context->Count)
|
||||
return NTLSTATUS_NO_MEMORY;
|
||||
size_t bytes = sizeof(NTL_LOADER_DATA) + recordsBytes;
|
||||
size_t argumentRecordsBytes = (size_t)arguments.Count * sizeof(NTL_LOADER_STRING_RECORD);
|
||||
size_t environmentRecordsBytes = (size_t)environment.Count * sizeof(NTL_LOADER_STRING_RECORD);
|
||||
if ((arguments.Count && argumentRecordsBytes / sizeof(NTL_LOADER_STRING_RECORD) != arguments.Count) ||
|
||||
(environment.Count && environmentRecordsBytes / sizeof(NTL_LOADER_STRING_RECORD) != environment.Count) ||
|
||||
argumentRecordsBytes > SIZE_MAX - bytes)
|
||||
return NTLSTATUS_NO_MEMORY;
|
||||
size_t argumentVectorOffset = arguments.Count ? bytes : 0u;
|
||||
bytes += argumentRecordsBytes;
|
||||
if (environmentRecordsBytes > SIZE_MAX - bytes) return NTLSTATUS_NO_MEMORY;
|
||||
size_t environmentVectorOffset = environment.Count ? bytes : 0u;
|
||||
bytes += environmentRecordsBytes;
|
||||
if (bytes < sizeof(NTL_LOADER_DATA) || currentDirectory.Length > SIZE_MAX - bytes - 1u)
|
||||
return NTLSTATUS_NO_MEMORY;
|
||||
size_t currentDirectoryOffset = bytes;
|
||||
@@ -524,6 +594,12 @@ KSTATUS NtlpBuildLoaderData(NTL_MODULE_CONTEXT* context,
|
||||
startupDataOffset = bytes;
|
||||
bytes += startupDataSize;
|
||||
}
|
||||
if (argumentStringBytes > SIZE_MAX - bytes) return NTLSTATUS_NO_MEMORY;
|
||||
size_t argumentStringsOffset = bytes;
|
||||
bytes += argumentStringBytes;
|
||||
if (environmentStringBytes > SIZE_MAX - bytes) return NTLSTATUS_NO_MEMORY;
|
||||
size_t environmentStringsOffset = bytes;
|
||||
bytes += environmentStringBytes;
|
||||
if (bytes > UINT32_MAX) return NTLSTATUS_NO_MEMORY;
|
||||
if (bytes > SIZE_MAX - (NTL_MODULE_PAGE_SIZE - 1u)) return NTLSTATUS_NO_MEMORY;
|
||||
size_t pages = (bytes + NTL_MODULE_PAGE_SIZE - 1u) / NTL_MODULE_PAGE_SIZE;
|
||||
@@ -537,7 +613,7 @@ KSTATUS NtlpBuildLoaderData(NTL_MODULE_CONTEXT* context,
|
||||
alloc.Flags = SYS_VM_FLAG_NONE;
|
||||
alloc.PageCount = pages;
|
||||
alloc.BaseOut = &base;
|
||||
KSTATUS status = SysAllocProcessVm(&alloc);
|
||||
status = SysAllocProcessVm(&alloc);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
|
||||
NTL_LOADER_DATA* data = (NTL_LOADER_DATA*)base;
|
||||
@@ -550,6 +626,10 @@ KSTATUS NtlpBuildLoaderData(NTL_MODULE_CONTEXT* context,
|
||||
data->CurrentDirectoryLength = (uint32_t)currentDirectory.Length;
|
||||
data->StartupDataOffset = startupDataSize ? (uint32_t)startupDataOffset : 0u;
|
||||
data->StartupDataLength = (uint32_t)startupDataSize;
|
||||
data->ArgumentVectorOffset = arguments.Count ? (uint32_t)argumentVectorOffset : 0u;
|
||||
data->ArgumentCount = arguments.Count;
|
||||
data->EnvironmentVectorOffset = environment.Count ? (uint32_t)environmentVectorOffset : 0u;
|
||||
data->EnvironmentCount = environment.Count;
|
||||
uint32_t i = 0;
|
||||
for (NTL_MODULE_ENTRY* entry = context->Head; entry; entry = entry->Next) {
|
||||
NTL_LOADER_IMAGE_RECORD* image = &data->Images[i++];
|
||||
@@ -564,16 +644,40 @@ KSTATUS NtlpBuildLoaderData(NTL_MODULE_CONTEXT* context,
|
||||
if (startupDataSize)
|
||||
memcpy((char*)data + startupDataOffset, startupData, startupDataSize);
|
||||
|
||||
NTL_LOADER_STRING_RECORD* argumentRecords = arguments.Count
|
||||
? (NTL_LOADER_STRING_RECORD*)((char*)data + argumentVectorOffset) : 0;
|
||||
size_t stringOffset = argumentStringsOffset;
|
||||
for (uint32_t argumentIndex = 0; argumentIndex < arguments.Count; ++argumentIndex) {
|
||||
SYS_STRING_VIEW entry = arguments.Entries[argumentIndex];
|
||||
argumentRecords[argumentIndex].Offset = (uint32_t)stringOffset;
|
||||
argumentRecords[argumentIndex].Length = (uint32_t)entry.Length;
|
||||
if (entry.Length) memcpy((char*)data + stringOffset, entry.Data, entry.Length);
|
||||
((char*)data)[stringOffset + entry.Length] = '\0';
|
||||
stringOffset += entry.Length + 1u;
|
||||
}
|
||||
|
||||
NTL_LOADER_STRING_RECORD* environmentRecords = environment.Count
|
||||
? (NTL_LOADER_STRING_RECORD*)((char*)data + environmentVectorOffset) : 0;
|
||||
stringOffset = environmentStringsOffset;
|
||||
for (uint32_t environmentIndex = 0; environmentIndex < environment.Count; ++environmentIndex) {
|
||||
SYS_STRING_VIEW entry = environment.Entries[environmentIndex];
|
||||
environmentRecords[environmentIndex].Offset = (uint32_t)stringOffset;
|
||||
environmentRecords[environmentIndex].Length = (uint32_t)entry.Length;
|
||||
if (entry.Length) memcpy((char*)data + stringOffset, entry.Data, entry.Length);
|
||||
((char*)data)[stringOffset + entry.Length] = '\0';
|
||||
stringOffset += entry.Length + 1u;
|
||||
}
|
||||
|
||||
status = SysProtectProcessVm(context->ProcessHandle, base, pages, SYS_VM_READ);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
*loaderDataOut = base;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Copies the opaque userspace bootstrap payload from the current process loader block.
|
||||
KSTATUS NtlGetProcessStartupData(void* buffer, size_t bufferSize, size_t* sizeOut) {
|
||||
if (!sizeOut || (bufferSize && !buffer)) return NTLSTATUS_INVALID_PARAMETER;
|
||||
*sizeOut = 0;
|
||||
// Validates and returns the immutable loader block for the current process.
|
||||
static KSTATUS NtlpGetCurrentLoaderData(const NTL_LOADER_DATA** dataOut) {
|
||||
if (!dataOut) return NTLSTATUS_INVALID_PARAMETER;
|
||||
*dataOut = 0;
|
||||
|
||||
SYS_PEB* peb = SysGetPeb();
|
||||
if (!peb || peb->Magic != SYS_PEB_MAGIC || peb->Version != SYS_ENV_VERSION || !peb->LoaderData)
|
||||
@@ -595,8 +699,21 @@ KSTATUS NtlGetProcessStartupData(void* buffer, size_t bufferSize, size_t* sizeOu
|
||||
|
||||
const NTL_LOADER_DATA* data = (const NTL_LOADER_DATA*)peb->LoaderData;
|
||||
if (data->Magic != NTL_LOADER_DATA_MAGIC || data->Version != NTL_LOADER_DATA_VERSION ||
|
||||
data->Size < sizeof(*data) || data->Size > regionBytes - (dataBase - regionBase) ||
|
||||
data->StartupDataLength > NTL_PROCESS_STARTUP_DATA_MAX ||
|
||||
data->Size < sizeof(*data) || data->Size > regionBytes - (dataBase - regionBase))
|
||||
return NTLSTATUS_FAILURE;
|
||||
*dataOut = data;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Copies the opaque userspace bootstrap payload from the current process loader block.
|
||||
KSTATUS NtlGetProcessStartupData(void* buffer, size_t bufferSize, size_t* sizeOut) {
|
||||
if (!sizeOut || (bufferSize && !buffer)) return NTLSTATUS_INVALID_PARAMETER;
|
||||
*sizeOut = 0;
|
||||
|
||||
const NTL_LOADER_DATA* data = 0;
|
||||
KSTATUS status = NtlpGetCurrentLoaderData(&data);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
if (data->StartupDataLength > NTL_PROCESS_STARTUP_DATA_MAX ||
|
||||
(data->StartupDataLength == 0 && data->StartupDataOffset != 0) ||
|
||||
(data->StartupDataLength != 0 &&
|
||||
(data->StartupDataOffset < sizeof(*data) || data->StartupDataOffset > data->Size ||
|
||||
@@ -612,33 +729,85 @@ KSTATUS NtlGetProcessStartupData(void* buffer, size_t bufferSize, size_t* sizeOu
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Returns one loader string vector count after validating its descriptor table.
|
||||
static KSTATUS NtlpGetProcessVectorCount(int environment, uint32_t* countOut) {
|
||||
if (!countOut) return NTLSTATUS_INVALID_PARAMETER;
|
||||
*countOut = 0;
|
||||
const NTL_LOADER_DATA* data = 0;
|
||||
KSTATUS status = NtlpGetCurrentLoaderData(&data);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
|
||||
uint32_t count = environment ? data->EnvironmentCount : data->ArgumentCount;
|
||||
uint32_t offset = environment ? data->EnvironmentVectorOffset : data->ArgumentVectorOffset;
|
||||
if ((count == 0 && offset != 0) || (count != 0 && offset == 0)) return NTLSTATUS_FAILURE;
|
||||
size_t recordsBytes = (size_t)count * sizeof(NTL_LOADER_STRING_RECORD);
|
||||
if (count && recordsBytes / sizeof(NTL_LOADER_STRING_RECORD) != count)
|
||||
return NTLSTATUS_FAILURE;
|
||||
if (offset > data->Size || recordsBytes > data->Size - offset)
|
||||
return NTLSTATUS_FAILURE;
|
||||
*countOut = count;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Returns one immutable loader string vector entry.
|
||||
static KSTATUS NtlpGetProcessVectorEntry(int environment, uint32_t index, SYS_STRING_VIEW* entryOut) {
|
||||
if (!entryOut) return NTLSTATUS_INVALID_PARAMETER;
|
||||
*entryOut = SYS_SV_NULL;
|
||||
const NTL_LOADER_DATA* data = 0;
|
||||
KSTATUS status = NtlpGetCurrentLoaderData(&data);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
|
||||
uint32_t count = environment ? data->EnvironmentCount : data->ArgumentCount;
|
||||
uint32_t offset = environment ? data->EnvironmentVectorOffset : data->ArgumentVectorOffset;
|
||||
if (index >= count || !count || !offset) return NTLSTATUS_NOT_FOUND;
|
||||
size_t recordsBytes = (size_t)count * sizeof(NTL_LOADER_STRING_RECORD);
|
||||
if (recordsBytes / sizeof(NTL_LOADER_STRING_RECORD) != count ||
|
||||
offset > data->Size || recordsBytes > data->Size - offset)
|
||||
return NTLSTATUS_FAILURE;
|
||||
|
||||
const NTL_LOADER_STRING_RECORD* records =
|
||||
(const NTL_LOADER_STRING_RECORD*)((const char*)data + offset);
|
||||
NTL_LOADER_STRING_RECORD record = records[index];
|
||||
if (record.Offset >= data->Size || record.Length > data->Size - record.Offset ||
|
||||
record.Length == data->Size - record.Offset)
|
||||
return NTLSTATUS_FAILURE;
|
||||
const char* string = (const char*)data + record.Offset;
|
||||
SYS_STRING_VIEW view = SysSvFromParts(string, record.Length);
|
||||
if (string[record.Length] != '\0' || SysSvContainsByte(view, '\0'))
|
||||
return NTLSTATUS_FAILURE;
|
||||
*entryOut = view;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Returns the number of serialized process arguments.
|
||||
KSTATUS NtlGetProcessArgumentCount(uint32_t* countOut) {
|
||||
return NtlpGetProcessVectorCount(0, countOut);
|
||||
}
|
||||
|
||||
// Returns one serialized process argument.
|
||||
KSTATUS NtlGetProcessArgument(uint32_t index, SYS_STRING_VIEW* argumentOut) {
|
||||
return NtlpGetProcessVectorEntry(0, index, argumentOut);
|
||||
}
|
||||
|
||||
// Returns the number of serialized environment entries.
|
||||
KSTATUS NtlGetProcessEnvironmentCount(uint32_t* countOut) {
|
||||
return NtlpGetProcessVectorCount(1, countOut);
|
||||
}
|
||||
|
||||
// Returns one serialized environment entry.
|
||||
KSTATUS NtlGetProcessEnvironment(uint32_t index, SYS_STRING_VIEW* entryOut) {
|
||||
return NtlpGetProcessVectorEntry(1, index, entryOut);
|
||||
}
|
||||
|
||||
// Returns the canonical inherited resource CWD stored in this process's loader data.
|
||||
KSTATUS NtlpGetLoaderCurrentDirectory(SYS_STRING_VIEW* currentDirectoryOut) {
|
||||
if (!currentDirectoryOut) return NTLSTATUS_INVALID_PARAMETER;
|
||||
*currentDirectoryOut = SysSvFromParts((const char*)0, 0);
|
||||
*currentDirectoryOut = SYS_SV_NULL;
|
||||
|
||||
SYS_PEB* peb = SysGetPeb();
|
||||
if (!peb || peb->Magic != SYS_PEB_MAGIC || peb->Version != SYS_ENV_VERSION || !peb->LoaderData)
|
||||
return NTLSTATUS_NOT_FOUND;
|
||||
|
||||
SYS_VM_REGION_INFO region;
|
||||
memset(®ion, 0, sizeof(region));
|
||||
KSTATUS status = SysQueryVm((void*)peb->LoaderData, ®ion);
|
||||
if (!KSUCCESS(status) || !region.Base || !region.PageCount ||
|
||||
region.PageCount > SIZE_MAX / NTL_MODULE_PAGE_SIZE)
|
||||
return NTLSTATUS_FAILURE;
|
||||
|
||||
size_t regionBytes = region.PageCount * NTL_MODULE_PAGE_SIZE;
|
||||
uintptr_t regionBase = (uintptr_t)region.Base;
|
||||
uintptr_t dataBase = (uintptr_t)peb->LoaderData;
|
||||
if (dataBase < regionBase || dataBase - regionBase > regionBytes ||
|
||||
regionBytes - (dataBase - regionBase) < sizeof(NTL_LOADER_DATA))
|
||||
return NTLSTATUS_FAILURE;
|
||||
|
||||
const NTL_LOADER_DATA* data = (const NTL_LOADER_DATA*)peb->LoaderData;
|
||||
if (data->Magic != NTL_LOADER_DATA_MAGIC || data->Version != NTL_LOADER_DATA_VERSION ||
|
||||
data->Size < sizeof(*data) || data->Size > regionBytes - (dataBase - regionBase) ||
|
||||
data->CurrentDirectoryOffset < sizeof(*data) ||
|
||||
const NTL_LOADER_DATA* data = 0;
|
||||
KSTATUS status = NtlpGetCurrentLoaderData(&data);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
if (data->CurrentDirectoryOffset < sizeof(*data) ||
|
||||
data->CurrentDirectoryLength == 0 ||
|
||||
data->CurrentDirectoryOffset > data->Size ||
|
||||
data->CurrentDirectoryLength > data->Size - data->CurrentDirectoryOffset ||
|
||||
@@ -664,6 +833,8 @@ static KSTATUS NtlpEnsureCurrentContext(SYS_HANDLE moduleRoot,
|
||||
if (_InterlockedCompareExchange(&gCurrentContextState, 1, 0) == 0) {
|
||||
NTL_MODULE_CONTEXT* temporary = 0;
|
||||
KSTATUS status = NtlpCreateModuleContext(SYS_HANDLE_INVALID, moduleRoot, moduleDirectory,
|
||||
SYS_HANDLE_INVALID, SysSvFromParts((const char*)0, 0),
|
||||
SYS_HANDLE_INVALID, SysSvFromParts((const char*)0, 0),
|
||||
resolver, resolverContext, 1, &temporary);
|
||||
if (!KSUCCESS(status)) {
|
||||
_InterlockedExchange(&gCurrentContextState, 0);
|
||||
@@ -679,8 +850,12 @@ static KSTATUS NtlpEnsureCurrentContext(SYS_HANDLE moduleRoot,
|
||||
while (_InterlockedCompareExchange(&gCurrentContextState, 2, 2) == 1) SysYield();
|
||||
if (_InterlockedCompareExchange(&gCurrentContextState, 2, 2) != 2)
|
||||
return NTLSTATUS_FAILURE;
|
||||
gCurrentContext.ModuleRootHandle = moduleRoot;
|
||||
gCurrentContext.ModuleDirectory = moduleDirectory;
|
||||
gCurrentContext.PrimaryModuleRootHandle = moduleRoot;
|
||||
gCurrentContext.PrimaryModuleDirectory = moduleDirectory;
|
||||
gCurrentContext.SecondaryModuleRootHandle = SYS_HANDLE_INVALID;
|
||||
gCurrentContext.SecondaryModuleDirectory = SysSvFromParts((const char*)0, 0);
|
||||
gCurrentContext.FallbackModuleRootHandle = SYS_HANDLE_INVALID;
|
||||
gCurrentContext.FallbackModuleDirectory = SysSvFromParts((const char*)0, 0);
|
||||
gCurrentContext.Resolver = resolver;
|
||||
gCurrentContext.ResolverContext = resolverContext;
|
||||
}
|
||||
|
||||
@@ -4,14 +4,19 @@
|
||||
|
||||
#include <ntlite/module_loader.h>
|
||||
#include <ntlite/pe_loader.h>
|
||||
#include <ntlite/process_loader.h>
|
||||
#include <ntlite/syscall.h>
|
||||
|
||||
typedef struct NTL_MODULE_CONTEXT NTL_MODULE_CONTEXT;
|
||||
|
||||
// Creates dependency-loader state for one constructing child or the current process.
|
||||
KSTATUS NtlpCreateModuleContext(SYS_HANDLE processHandle,
|
||||
SYS_HANDLE moduleRootHandle,
|
||||
SYS_STRING_VIEW moduleDirectory,
|
||||
SYS_HANDLE primaryModuleRootHandle,
|
||||
SYS_STRING_VIEW primaryModuleDirectory,
|
||||
SYS_HANDLE secondaryModuleRootHandle,
|
||||
SYS_STRING_VIEW secondaryModuleDirectory,
|
||||
SYS_HANDLE fallbackModuleRootHandle,
|
||||
SYS_STRING_VIEW fallbackModuleDirectory,
|
||||
NTL_MODULE_NAME_RESOLVER resolver,
|
||||
void* resolverContext,
|
||||
int seedCurrentProcess,
|
||||
@@ -25,6 +30,8 @@ KSTATUS NtlpLoadMainImage(NTL_MODULE_CONTEXT* context,
|
||||
// Builds the opaque read-only loader-data block consumed later by userspace base services.
|
||||
KSTATUS NtlpBuildLoaderData(NTL_MODULE_CONTEXT* context,
|
||||
SYS_STRING_VIEW currentDirectory,
|
||||
NTL_PROCESS_STRING_VECTOR arguments,
|
||||
NTL_PROCESS_STRING_VECTOR environment,
|
||||
const void* startupData,
|
||||
size_t startupDataSize,
|
||||
void** loaderDataOut);
|
||||
|
||||
@@ -15,12 +15,116 @@ static void NtlDiscardChild(SYS_HANDLE processHandle) {
|
||||
(void)SysCloseHandle(processHandle);
|
||||
}
|
||||
|
||||
// Creates and starts one child from an already-open PE file capability.
|
||||
static KSTATUS NtlCreateProcessFile(const NTL_CREATE_PROCESS_AT_REQUEST* request, SYS_HANDLE fileHandle) {
|
||||
if (!request || fileHandle == SYS_HANDLE_INVALID)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
#define NTL_PROCESS_BUILDER_MAGIC 0x3142504Eu
|
||||
|
||||
typedef struct NTL_PROCESS_BUILDER_INTERNAL {
|
||||
uint32_t Magic;
|
||||
uint32_t StartupCapabilityCount;
|
||||
SYS_HANDLE ProcessHandle;
|
||||
NTL_MODULE_CONTEXT* Modules;
|
||||
NTL_PE_IMAGE Image;
|
||||
void* LoaderData;
|
||||
SYS_STARTUP_CAPABILITY ChildCapabilities[SYS_STARTUP_CAPABILITY_MAX];
|
||||
} NTL_PROCESS_BUILDER_INTERNAL;
|
||||
|
||||
typedef char NTL_PROCESS_BUILDER_SIZE_CHECK[
|
||||
sizeof(NTL_PROCESS_BUILDER_INTERNAL) <= sizeof(NTL_PROCESS_BUILDER) ? 1 : -1];
|
||||
|
||||
static NTL_PROCESS_BUILDER_INTERNAL* NtlBuilderInternal(NTL_PROCESS_BUILDER* builder) {
|
||||
return (NTL_PROCESS_BUILDER_INTERNAL*)(void*)builder;
|
||||
}
|
||||
|
||||
static int NtlBuilderRequestValid(const NTL_PROCESS_BUILDER_REQUEST* request) {
|
||||
return request && request->Size == sizeof(*request) &&
|
||||
request->Flags == NTL_PROCESS_LOAD_FLAG_NONE &&
|
||||
request->RootHandle != SYS_HANDLE_INVALID &&
|
||||
request->ModuleRootHandle != SYS_HANDLE_INVALID &&
|
||||
request->Path.Data && request->Path.Length != 0 &&
|
||||
SysSvIsValid(request->ModuleDirectory) &&
|
||||
request->StartupCapabilityCount <= SYS_STARTUP_CAPABILITY_MAX &&
|
||||
(!request->StartupCapabilityCount || request->StartupCapabilities) &&
|
||||
(!request->Arguments.Count || request->Arguments.Entries) &&
|
||||
(!request->Environment.Count || request->Environment.Entries) &&
|
||||
request->StartupDataSize <= NTL_PROCESS_STARTUP_DATA_MAX &&
|
||||
(!request->StartupDataSize || request->StartupData);
|
||||
}
|
||||
|
||||
static void NtlBuilderReset(NTL_PROCESS_BUILDER* builder) {
|
||||
if (builder) memset(builder, 0, sizeof(*builder));
|
||||
}
|
||||
|
||||
// Aborts one prepared inert child. This is deliberately safe on an empty builder.
|
||||
void NtlProcessBuilderAbort(NTL_PROCESS_BUILDER* builder) {
|
||||
if (!builder) return;
|
||||
NTL_PROCESS_BUILDER_INTERNAL* state = NtlBuilderInternal(builder);
|
||||
if (state->Magic != NTL_PROCESS_BUILDER_MAGIC) {
|
||||
NtlBuilderReset(builder);
|
||||
return;
|
||||
}
|
||||
if (state->Modules) NtlpDestroyModuleContext(state->Modules);
|
||||
if (state->ProcessHandle != SYS_HANDLE_INVALID) NtlDiscardChild(state->ProcessHandle);
|
||||
NtlBuilderReset(builder);
|
||||
}
|
||||
|
||||
// Opens the executable's containing directory as the private dependency-search root.
|
||||
static KSTATUS NtlOpenImageDirectory(const NTL_PROCESS_BUILDER_REQUEST* request,
|
||||
SYS_HANDLE* directoryOut, int* borrowedRootOut) {
|
||||
if (!request || !directoryOut || !borrowedRootOut || !SysSvIsValid(request->Path) ||
|
||||
request->Path.Length == 0 || SysSvContainsByte(request->Path, '\0'))
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
*directoryOut = SYS_HANDLE_INVALID;
|
||||
*borrowedRootOut = 0;
|
||||
|
||||
size_t slash = SIZE_MAX;
|
||||
for (size_t i = 0; i < request->Path.Length; ++i) {
|
||||
if (request->Path.Data[i] == '/') slash = i;
|
||||
else if (request->Path.Data[i] == '\\') return NTLSTATUS_INVALID_PARAMETER;
|
||||
}
|
||||
if (slash == SIZE_MAX) {
|
||||
*directoryOut = request->RootHandle;
|
||||
*borrowedRootOut = 1;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SYS_STRING_VIEW directoryPath;
|
||||
if (slash == 0) directoryPath = SYS_SV_LITERAL("/");
|
||||
else directoryPath = SysSvFromParts(request->Path.Data, slash);
|
||||
|
||||
if (request->Path.Data[0] == '/')
|
||||
return NtlOpenDir(directoryPath, SYS_DIR_ACCESS_OPEN, SYS_DIR_FLAG_NONE, directoryOut);
|
||||
|
||||
SYS_OPEN_DIR_AT_REQUEST open = SysMakeOpenDirAtRequest(request->RootHandle, directoryPath,
|
||||
SYS_DIR_ACCESS_OPEN, SYS_DIR_FLAG_NONE,
|
||||
directoryOut);
|
||||
return SysOpenDirAt(&open);
|
||||
}
|
||||
|
||||
// Prepares an inert child: process object, image/dependencies, inherited startup
|
||||
// capabilities, CWD, and loader/bootstrap block are all complete before return.
|
||||
KSTATUS NtlProcessBuilderPrepare(NTL_PROCESS_BUILDER* builder,
|
||||
const NTL_PROCESS_BUILDER_REQUEST* request,
|
||||
SYS_HANDLE imageFile) {
|
||||
if (!builder || !NtlBuilderRequestValid(request)) return NTLSTATUS_INVALID_PARAMETER;
|
||||
NtlBuilderReset(builder);
|
||||
NTL_PROCESS_BUILDER_INTERNAL* state = NtlBuilderInternal(builder);
|
||||
state->ProcessHandle = SYS_HANDLE_INVALID;
|
||||
|
||||
SYS_HANDLE openedImage = SYS_HANDLE_INVALID;
|
||||
if (imageFile == SYS_HANDLE_INVALID) {
|
||||
SYS_OPEN_FILE_AT_REQUEST open;
|
||||
memset(&open, 0, sizeof(open));
|
||||
open.Size = sizeof(open);
|
||||
open.RootHandle = request->RootHandle;
|
||||
open.Path = request->Path;
|
||||
open.Access = SYS_FILE_ACCESS_READ | SYS_FILE_ACCESS_QUERY;
|
||||
open.Disposition = SYS_FILE_OPEN_EXISTING;
|
||||
open.Flags = SYS_FILE_FLAG_NONE;
|
||||
open.HandleOut = &openedImage;
|
||||
KSTATUS openStatus = SysOpenFileAt(&open);
|
||||
if (!KSUCCESS(openStatus)) return openStatus;
|
||||
imageFile = openedImage;
|
||||
}
|
||||
|
||||
SYS_HANDLE processHandle = SYS_HANDLE_INVALID;
|
||||
SYS_CREATE_PROCESS_OBJECT_REQUEST create;
|
||||
memset(&create, 0, sizeof(create));
|
||||
create.Size = sizeof(create);
|
||||
@@ -28,133 +132,200 @@ static KSTATUS NtlCreateProcessFile(const NTL_CREATE_PROCESS_AT_REQUEST* request
|
||||
create.ImagePath = request->Path;
|
||||
create.CommandLine = request->CommandLine;
|
||||
create.SecurityContext = request->SecurityContext;
|
||||
create.ProcessHandleOut = &processHandle;
|
||||
create.ProcessHandleOut = &state->ProcessHandle;
|
||||
KSTATUS status = SysCreateProcessObject(&create);
|
||||
if (!KSUCCESS(status))
|
||||
return status;
|
||||
if (!KSUCCESS(status)) goto done;
|
||||
|
||||
NTL_MODULE_CONTEXT* modules = 0;
|
||||
status = NtlpCreateModuleContext(processHandle,
|
||||
request->ModuleRootHandle,
|
||||
request->ModuleDirectory,
|
||||
request->ResolveModuleName,
|
||||
request->ResolveContext,
|
||||
0,
|
||||
&modules);
|
||||
char currentDirectoryBuffer[SYS_PATH_MAX + 1u];
|
||||
SYS_STRING_VIEW currentDirectory;
|
||||
size_t currentDirectorySize = 0;
|
||||
if (request->CurrentDirectory.Length != 0) {
|
||||
status = NtlRealPath(request->CurrentDirectory, currentDirectoryBuffer,
|
||||
sizeof(currentDirectoryBuffer), ¤tDirectorySize);
|
||||
} else {
|
||||
status = NtlGetCurrentDirectory(currentDirectoryBuffer, sizeof(currentDirectoryBuffer),
|
||||
¤tDirectorySize);
|
||||
}
|
||||
if (!KSUCCESS(status)) goto fail;
|
||||
currentDirectory = SysSvFromParts(currentDirectoryBuffer, currentDirectorySize - 1u);
|
||||
|
||||
SYS_HANDLE currentDirectoryHandle = SYS_HANDLE_INVALID;
|
||||
KSTATUS currentDirectoryStatus = NtlOpenDir(currentDirectory, SYS_DIR_ACCESS_OPEN,
|
||||
SYS_DIR_FLAG_NONE, ¤tDirectoryHandle);
|
||||
|
||||
SYS_HANDLE imageDirectory = SYS_HANDLE_INVALID;
|
||||
int imageDirectoryBorrowed = 0;
|
||||
status = NtlOpenImageDirectory(request, &imageDirectory, &imageDirectoryBorrowed);
|
||||
if (!KSUCCESS(status)) {
|
||||
NtlDiscardChild(processHandle);
|
||||
return status;
|
||||
if (currentDirectoryHandle != SYS_HANDLE_INVALID)
|
||||
(void)SysCloseHandle(currentDirectoryHandle);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
NTL_PE_IMAGE image;
|
||||
memset(&image, 0, sizeof(image));
|
||||
status = NtlpLoadMainImage(modules, fileHandle, &image);
|
||||
if (!KSUCCESS(status)) {
|
||||
NtlpDestroyModuleContext(modules);
|
||||
NtlDiscardChild(processHandle);
|
||||
return status;
|
||||
SYS_HANDLE primaryModuleRoot = imageDirectory;
|
||||
SYS_STRING_VIEW primaryModuleDirectory = SysSvFromParts((const char*)0, 0);
|
||||
SYS_HANDLE secondaryModuleRoot = request->ModuleRootHandle;
|
||||
SYS_STRING_VIEW secondaryModuleDirectory = request->ModuleDirectory;
|
||||
SYS_HANDLE fallbackModuleRoot = SYS_HANDLE_INVALID;
|
||||
SYS_STRING_VIEW fallbackModuleDirectory = SysSvFromParts((const char*)0, 0);
|
||||
|
||||
// Current-directory lookup is a search-path optimization, not a bootstrap dependency.
|
||||
if (KSUCCESS(currentDirectoryStatus)) {
|
||||
primaryModuleRoot = currentDirectoryHandle;
|
||||
secondaryModuleRoot = imageDirectory;
|
||||
secondaryModuleDirectory = SysSvFromParts((const char*)0, 0);
|
||||
fallbackModuleRoot = request->ModuleRootHandle;
|
||||
fallbackModuleDirectory = request->ModuleDirectory;
|
||||
}
|
||||
|
||||
SYS_STARTUP_CAPABILITY childCapabilities[SYS_STARTUP_CAPABILITY_MAX];
|
||||
memset(childCapabilities, 0, sizeof(childCapabilities));
|
||||
status = NtlpCreateModuleContext(state->ProcessHandle, primaryModuleRoot,
|
||||
primaryModuleDirectory, secondaryModuleRoot,
|
||||
secondaryModuleDirectory, fallbackModuleRoot,
|
||||
fallbackModuleDirectory, request->ResolveModuleName,
|
||||
request->ResolveContext, 0, &state->Modules);
|
||||
if (!KSUCCESS(status)) {
|
||||
if (!imageDirectoryBorrowed) (void)SysCloseHandle(imageDirectory);
|
||||
if (currentDirectoryHandle != SYS_HANDLE_INVALID)
|
||||
(void)SysCloseHandle(currentDirectoryHandle);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
memset(&state->Image, 0, sizeof(state->Image));
|
||||
status = NtlpLoadMainImage(state->Modules, imageFile, &state->Image);
|
||||
if (!imageDirectoryBorrowed) (void)SysCloseHandle(imageDirectory);
|
||||
if (currentDirectoryHandle != SYS_HANDLE_INVALID)
|
||||
(void)SysCloseHandle(currentDirectoryHandle);
|
||||
if (!KSUCCESS(status)) goto fail;
|
||||
|
||||
memset(state->ChildCapabilities, 0, sizeof(state->ChildCapabilities));
|
||||
for (uint32_t i = 0; i < request->StartupCapabilityCount; ++i) {
|
||||
const NTL_PROCESS_STARTUP_CAPABILITY* source = &request->StartupCapabilities[i];
|
||||
if (!source->Tag || source->SourceHandle == SYS_HANDLE_INVALID) {
|
||||
NtlpDestroyModuleContext(modules);
|
||||
NtlDiscardChild(processHandle);
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
status = NTLSTATUS_INVALID_PARAMETER;
|
||||
goto fail;
|
||||
}
|
||||
for (uint32_t j = 0; j < i; ++j) {
|
||||
if (childCapabilities[j].Tag == source->Tag) {
|
||||
NtlpDestroyModuleContext(modules);
|
||||
NtlDiscardChild(processHandle);
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
if (state->ChildCapabilities[j].Tag == source->Tag) {
|
||||
status = NTLSTATUS_INVALID_PARAMETER;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
SYS_HANDLE childHandle = SYS_HANDLE_INVALID;
|
||||
SYS_DUPLICATE_HANDLE_REQUEST duplicate;
|
||||
memset(&duplicate, 0, sizeof(duplicate));
|
||||
duplicate.Size = sizeof(duplicate);
|
||||
duplicate.SourceHandle = source->SourceHandle;
|
||||
duplicate.TargetProcessHandle = processHandle;
|
||||
duplicate.TargetProcessHandle = state->ProcessHandle;
|
||||
duplicate.DesiredRights = source->DesiredRights;
|
||||
duplicate.Flags = source->DuplicateFlags;
|
||||
duplicate.TargetHandleOut = &childHandle;
|
||||
status = SysDuplicateHandle(&duplicate);
|
||||
if (!KSUCCESS(status)) {
|
||||
NtlpDestroyModuleContext(modules);
|
||||
NtlDiscardChild(processHandle);
|
||||
return status;
|
||||
}
|
||||
childCapabilities[i].Tag = source->Tag;
|
||||
childCapabilities[i].Handle = childHandle;
|
||||
if (!KSUCCESS(status)) goto fail;
|
||||
state->ChildCapabilities[i].Tag = source->Tag;
|
||||
state->ChildCapabilities[i].Handle = childHandle;
|
||||
}
|
||||
state->StartupCapabilityCount = request->StartupCapabilityCount;
|
||||
|
||||
char currentDirectoryBuffer[SYS_PATH_MAX + 1u];
|
||||
SYS_STRING_VIEW currentDirectory;
|
||||
if (request->CurrentDirectory.Length != 0) {
|
||||
size_t required = 0;
|
||||
status = NtlRealPath(request->CurrentDirectory, currentDirectoryBuffer,
|
||||
sizeof(currentDirectoryBuffer), &required);
|
||||
if (!KSUCCESS(status)) {
|
||||
NtlpDestroyModuleContext(modules);
|
||||
NtlDiscardChild(processHandle);
|
||||
return status;
|
||||
}
|
||||
currentDirectory = SysSvFromParts(currentDirectoryBuffer, required - 1u);
|
||||
status = NtlpBuildLoaderData(state->Modules, currentDirectory, request->Arguments,
|
||||
request->Environment, request->StartupData,
|
||||
request->StartupDataSize, &state->LoaderData);
|
||||
if (!KSUCCESS(status)) goto fail;
|
||||
|
||||
SYS_HANDLE cwdHandle = SYS_HANDLE_INVALID;
|
||||
status = NtlOpenDir(currentDirectory, SYS_DIR_ACCESS_ENUMERATE | SYS_DIR_ACCESS_OPEN,
|
||||
SYS_DIR_FLAG_NONE, &cwdHandle);
|
||||
if (!KSUCCESS(status)) {
|
||||
NtlpDestroyModuleContext(modules);
|
||||
NtlDiscardChild(processHandle);
|
||||
return status;
|
||||
}
|
||||
(void)SysCloseHandle(cwdHandle);
|
||||
} else {
|
||||
size_t required = 0;
|
||||
status = NtlGetCurrentDirectory(currentDirectoryBuffer, sizeof(currentDirectoryBuffer), &required);
|
||||
if (!KSUCCESS(status)) {
|
||||
NtlpDestroyModuleContext(modules);
|
||||
NtlDiscardChild(processHandle);
|
||||
return status;
|
||||
}
|
||||
currentDirectory = SysSvFromParts(currentDirectoryBuffer, required - 1u);
|
||||
}
|
||||
state->Magic = NTL_PROCESS_BUILDER_MAGIC;
|
||||
status = NTLSTATUS_SUCCESS;
|
||||
goto done;
|
||||
|
||||
void* loaderData = 0;
|
||||
status = NtlpBuildLoaderData(modules, currentDirectory, request->StartupData,
|
||||
request->StartupDataSize, &loaderData);
|
||||
if (!KSUCCESS(status)) {
|
||||
NtlpDestroyModuleContext(modules);
|
||||
NtlDiscardChild(processHandle);
|
||||
return status;
|
||||
}
|
||||
fail:
|
||||
if (state->Modules) NtlpDestroyModuleContext(state->Modules);
|
||||
if (state->ProcessHandle != SYS_HANDLE_INVALID) NtlDiscardChild(state->ProcessHandle);
|
||||
NtlBuilderReset(builder);
|
||||
done:
|
||||
if (openedImage != SYS_HANDLE_INVALID) (void)SysCloseHandle(openedImage);
|
||||
return status;
|
||||
}
|
||||
|
||||
// Returns the process capability owned by one prepared builder without transferring it.
|
||||
KSTATUS NtlProcessBuilderGetProcessHandle(NTL_PROCESS_BUILDER* builder,
|
||||
SYS_HANDLE* processHandleOut) {
|
||||
if (!builder || !processHandleOut) return NTLSTATUS_INVALID_PARAMETER;
|
||||
*processHandleOut = SYS_HANDLE_INVALID;
|
||||
NTL_PROCESS_BUILDER_INTERNAL* state = NtlBuilderInternal(builder);
|
||||
if (state->Magic != NTL_PROCESS_BUILDER_MAGIC ||
|
||||
state->ProcessHandle == SYS_HANDLE_INVALID || !state->Modules || !state->LoaderData)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
*processHandleOut = state->ProcessHandle;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Starts one prepared child. On success ownership of the retained native process
|
||||
// capability moves to the caller; on failure the child is destroyed.
|
||||
KSTATUS NtlProcessBuilderStart(NTL_PROCESS_BUILDER* builder, SYS_HANDLE* processHandleOut) {
|
||||
if (!builder || !processHandleOut) return NTLSTATUS_INVALID_PARAMETER;
|
||||
*processHandleOut = SYS_HANDLE_INVALID;
|
||||
NTL_PROCESS_BUILDER_INTERNAL* state = NtlBuilderInternal(builder);
|
||||
if (state->Magic != NTL_PROCESS_BUILDER_MAGIC ||
|
||||
state->ProcessHandle == SYS_HANDLE_INVALID || !state->Modules || !state->LoaderData)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
SYS_START_PROCESS_REQUEST startRequest;
|
||||
memset(&startRequest, 0, sizeof(startRequest));
|
||||
startRequest.Size = sizeof(startRequest);
|
||||
startRequest.ProcessHandle = processHandle;
|
||||
startRequest.ProcessHandle = state->ProcessHandle;
|
||||
startRequest.Flags = SYS_START_PROCESS_FLAG_NONE;
|
||||
startRequest.MainImageBase = image.Base;
|
||||
startRequest.MainImageSize = image.Size;
|
||||
startRequest.EntryPoint = image.EntryPoint;
|
||||
startRequest.StartupCapabilities = childCapabilities;
|
||||
startRequest.StartupCapabilityCount = request->StartupCapabilityCount;
|
||||
startRequest.LoaderData = loaderData;
|
||||
status = SysStartProcess(&startRequest);
|
||||
NtlpDestroyModuleContext(modules);
|
||||
startRequest.MainImageBase = state->Image.Base;
|
||||
startRequest.MainImageSize = state->Image.Size;
|
||||
startRequest.EntryPoint = state->Image.EntryPoint;
|
||||
startRequest.StartupCapabilities = state->ChildCapabilities;
|
||||
startRequest.StartupCapabilityCount = state->StartupCapabilityCount;
|
||||
startRequest.LoaderData = state->LoaderData;
|
||||
KSTATUS status = SysStartProcess(&startRequest);
|
||||
NtlpDestroyModuleContext(state->Modules);
|
||||
state->Modules = 0;
|
||||
if (!KSUCCESS(status)) {
|
||||
NtlDiscardChild(processHandle);
|
||||
NtlDiscardChild(state->ProcessHandle);
|
||||
NtlBuilderReset(builder);
|
||||
return status;
|
||||
}
|
||||
|
||||
*request->ProcessHandleOut = processHandle;
|
||||
*processHandleOut = state->ProcessHandle;
|
||||
NtlBuilderReset(builder);
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void NtlBuilderRequestFromCreate(const NTL_CREATE_PROCESS_AT_REQUEST* create,
|
||||
NTL_PROCESS_BUILDER_REQUEST* builder) {
|
||||
memset(builder, 0, sizeof(*builder));
|
||||
builder->Size = sizeof(*builder);
|
||||
builder->Flags = create->Flags;
|
||||
builder->RootHandle = create->RootHandle;
|
||||
builder->Path = create->Path;
|
||||
builder->CommandLine = create->CommandLine;
|
||||
builder->CurrentDirectory = create->CurrentDirectory;
|
||||
builder->SecurityContext = create->SecurityContext;
|
||||
builder->ModuleRootHandle = create->ModuleRootHandle;
|
||||
builder->ModuleDirectory = create->ModuleDirectory;
|
||||
builder->ResolveModuleName = create->ResolveModuleName;
|
||||
builder->ResolveContext = create->ResolveContext;
|
||||
builder->StartupCapabilities = create->StartupCapabilities;
|
||||
builder->StartupCapabilityCount = create->StartupCapabilityCount;
|
||||
builder->Arguments = create->Arguments;
|
||||
builder->Environment = create->Environment;
|
||||
builder->StartupData = create->StartupData;
|
||||
builder->StartupDataSize = create->StartupDataSize;
|
||||
}
|
||||
|
||||
static KSTATUS NtlCreateProcessFile(const NTL_CREATE_PROCESS_AT_REQUEST* request, SYS_HANDLE fileHandle) {
|
||||
NTL_PROCESS_BUILDER_REQUEST builderRequest;
|
||||
NtlBuilderRequestFromCreate(request, &builderRequest);
|
||||
NTL_PROCESS_BUILDER builder;
|
||||
memset(&builder, 0, sizeof(builder));
|
||||
KSTATUS status = NtlProcessBuilderPrepare(&builder, &builderRequest, fileHandle);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
status = NtlProcessBuilderStart(&builder, request->ProcessHandleOut);
|
||||
if (!KSUCCESS(status)) NtlProcessBuilderAbort(&builder);
|
||||
return status;
|
||||
}
|
||||
|
||||
// Creates and starts one child from a PE file beneath a capability-relative root.
|
||||
KSTATUS NtlCreateProcessAt(const NTL_CREATE_PROCESS_AT_REQUEST* request) {
|
||||
if (!request || request->Size != sizeof(*request) ||
|
||||
@@ -165,6 +336,8 @@ KSTATUS NtlCreateProcessAt(const NTL_CREATE_PROCESS_AT_REQUEST* request) {
|
||||
!SysSvIsValid(request->ModuleDirectory) ||
|
||||
request->StartupCapabilityCount > SYS_STARTUP_CAPABILITY_MAX ||
|
||||
(request->StartupCapabilityCount && !request->StartupCapabilities) ||
|
||||
(request->Arguments.Count && !request->Arguments.Entries) ||
|
||||
(request->Environment.Count && !request->Environment.Entries) ||
|
||||
request->StartupDataSize > NTL_PROCESS_STARTUP_DATA_MAX ||
|
||||
(request->StartupDataSize && !request->StartupData) ||
|
||||
!request->ProcessHandleOut)
|
||||
@@ -195,11 +368,23 @@ KSTATUS NtlCreateSystemProcess(const NTL_CREATE_SYSTEM_PROCESS_REQUEST* request)
|
||||
if (!request || request->Size != sizeof(*request) ||
|
||||
request->Flags != NTL_PROCESS_LOAD_FLAG_NONE || !request->Path.Data ||
|
||||
request->Path.Length == 0 || request->StartupDataSize > NTL_PROCESS_STARTUP_DATA_MAX ||
|
||||
(request->Arguments.Count && !request->Arguments.Entries) ||
|
||||
(request->Environment.Count && !request->Environment.Entries) ||
|
||||
(request->StartupDataSize && !request->StartupData) || !request->ProcessHandleOut)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
*request->ProcessHandleOut = SYS_HANDLE_INVALID;
|
||||
|
||||
char canonicalPath[SYS_PATH_MAX + 1u];
|
||||
size_t canonicalSize = 0;
|
||||
KSTATUS canonicalStatus = NtlRealPath(request->Path, canonicalPath, sizeof(canonicalPath),
|
||||
&canonicalSize);
|
||||
SYS_STRING_VIEW imagePath = request->Path;
|
||||
if (KSUCCESS(canonicalStatus))
|
||||
imagePath = SysSvFromParts(canonicalPath, canonicalSize - 1u);
|
||||
else if (request->ImageFile == SYS_HANDLE_INVALID)
|
||||
return canonicalStatus;
|
||||
|
||||
SYS_HANDLE systemRoot = SYS_HANDLE_INVALID;
|
||||
KSTATUS status = NtlResourceOpenSystemRoot(SYS_RIGHT_QUERY | SYS_VOLUME_RIGHT_OPEN, &systemRoot);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
@@ -209,7 +394,7 @@ KSTATUS NtlCreateSystemProcess(const NTL_CREATE_SYSTEM_PROCESS_REQUEST* request)
|
||||
create.Size = sizeof(create);
|
||||
create.Flags = request->Flags;
|
||||
create.RootHandle = systemRoot;
|
||||
create.Path = request->Path;
|
||||
create.Path = imagePath;
|
||||
create.CommandLine = request->CommandLine;
|
||||
create.CurrentDirectory = request->CurrentDirectory;
|
||||
create.SecurityContext = request->SecurityContext;
|
||||
@@ -219,6 +404,8 @@ KSTATUS NtlCreateSystemProcess(const NTL_CREATE_SYSTEM_PROCESS_REQUEST* request)
|
||||
create.ResolveContext = request->ResolveContext;
|
||||
create.StartupCapabilities = request->StartupCapabilities;
|
||||
create.StartupCapabilityCount = request->StartupCapabilityCount;
|
||||
create.Arguments = request->Arguments;
|
||||
create.Environment = request->Environment;
|
||||
create.StartupData = request->StartupData;
|
||||
create.StartupDataSize = request->StartupDataSize;
|
||||
create.ProcessHandleOut = request->ProcessHandleOut;
|
||||
@@ -226,7 +413,7 @@ KSTATUS NtlCreateSystemProcess(const NTL_CREATE_SYSTEM_PROCESS_REQUEST* request)
|
||||
status = NtlCreateProcessFile(&create, request->ImageFile);
|
||||
} else {
|
||||
SYS_HANDLE imageFile = SYS_HANDLE_INVALID;
|
||||
status = NtlOpenFile(request->Path, SYS_FILE_ACCESS_READ | SYS_FILE_ACCESS_QUERY,
|
||||
status = NtlOpenFile(create.Path, SYS_FILE_ACCESS_READ | SYS_FILE_ACCESS_QUERY,
|
||||
SYS_FILE_OPEN_EXISTING, SYS_FILE_FLAG_NONE, &imageFile);
|
||||
if (KSUCCESS(status)) {
|
||||
status = NtlCreateProcessFile(&create, imageFile);
|
||||
|
||||
+167
-161
@@ -13,187 +13,193 @@ SYS_KILL_PROCESS EQU 8
|
||||
SYS_GET_PROCESS_LIST EQU 9
|
||||
SYS_GET_PROCESS_PID EQU 10
|
||||
SYS_CREATE_THREAD EQU 11
|
||||
SYS_RESUME_THREAD EQU 12
|
||||
SYS_GET_THREAD_LIST EQU 13
|
||||
SYS_GET_CURRENT_TID EQU 14
|
||||
SYS_GET_CURRENT_PID EQU 15
|
||||
SYS_SET_THREAD_PRIORITY EQU 16
|
||||
SYS_SET_THREAD_NAME EQU 17
|
||||
SYS_QUERY_THREAD_NAME EQU 18
|
||||
SYS_YIELD EQU 19
|
||||
SYS_SLEEP EQU 20
|
||||
SYS_WAIT_SINGLE EQU 21
|
||||
SYS_WAIT_MANY EQU 22
|
||||
SYS_SET_USER_APC_DISPATCHER EQU 23
|
||||
SYS_APC_RETURN EQU 24
|
||||
SYS_SET_EXCEPTION_DISPATCHER EQU 25
|
||||
SYS_GET_EXCEPTION_DISPATCHER EQU 26
|
||||
SYS_CONTINUE_EXCEPTION EQU 27
|
||||
SYS_RAISE_EXCEPTION EQU 28
|
||||
SYS_OPEN_CURRENT_THREAD EQU 12
|
||||
SYS_RESUME_THREAD EQU 13
|
||||
SYS_RESUME_THREAD_AND_WAIT EQU 14
|
||||
SYS_GET_THREAD_LIST EQU 15
|
||||
SYS_GET_THREAD_TID EQU 16
|
||||
SYS_GET_CURRENT_TID EQU 17
|
||||
SYS_GET_CURRENT_PID EQU 18
|
||||
SYS_SET_THREAD_PRIORITY EQU 19
|
||||
SYS_SET_THREAD_NAME EQU 20
|
||||
SYS_QUERY_THREAD_NAME EQU 21
|
||||
SYS_YIELD EQU 22
|
||||
SYS_SLEEP EQU 23
|
||||
SYS_WAIT_SINGLE EQU 24
|
||||
SYS_WAIT_MANY EQU 25
|
||||
SYS_SET_USER_APC_DISPATCHER EQU 26
|
||||
SYS_QUEUE_USER_APC EQU 27
|
||||
SYS_APC_RETURN EQU 28
|
||||
SYS_SET_EXCEPTION_DISPATCHER EQU 29
|
||||
SYS_GET_EXCEPTION_DISPATCHER EQU 30
|
||||
SYS_CONTINUE_EXCEPTION EQU 31
|
||||
SYS_RAISE_EXCEPTION EQU 32
|
||||
|
||||
; Virtual memory, mappings, and handles.
|
||||
SYS_ALLOC_VM EQU 29
|
||||
SYS_FREE_VM EQU 30
|
||||
SYS_PROTECT_VM EQU 31
|
||||
SYS_QUERY_VM EQU 32
|
||||
SYS_CLOSE_HANDLE EQU 33
|
||||
SYS_DUPLICATE_HANDLE EQU 34
|
||||
SYS_DERIVE_HANDLE EQU 35
|
||||
SYS_REVOKE_HANDLE EQU 36
|
||||
SYS_DERIVE_SECURITY_CONTEXT EQU 37
|
||||
SYS_QUERY_SECURITY_CONTEXT EQU 38
|
||||
SYS_CREATE_FILE_MAPPING EQU 39
|
||||
SYS_MAP_FILE EQU 40
|
||||
SYS_ALLOC_VM EQU 33
|
||||
SYS_FREE_VM EQU 34
|
||||
SYS_PROTECT_VM EQU 35
|
||||
SYS_QUERY_VM EQU 36
|
||||
SYS_CLOSE_HANDLE EQU 37
|
||||
SYS_DUPLICATE_HANDLE EQU 38
|
||||
SYS_DERIVE_HANDLE EQU 39
|
||||
SYS_REVOKE_HANDLE EQU 40
|
||||
SYS_DERIVE_SECURITY_CONTEXT EQU 41
|
||||
SYS_QUERY_SECURITY_CONTEXT EQU 42
|
||||
SYS_OPEN_PROCESS_SECURITY_CONTEXT EQU 43
|
||||
SYS_CREATE_FILE_MAPPING EQU 44
|
||||
SYS_MAP_FILE EQU 45
|
||||
|
||||
; Synchronization objects.
|
||||
SYS_CREATE_MUTEX EQU 41
|
||||
SYS_TRY_ACQUIRE_MUTEX EQU 42
|
||||
SYS_RELEASE_MUTEX EQU 43
|
||||
SYS_CREATE_SEM EQU 44
|
||||
SYS_TRY_WAIT_SEM EQU 45
|
||||
SYS_SIGNAL_SEM EQU 46
|
||||
SYS_CREATE_EVENT EQU 47
|
||||
SYS_SIGNAL_EVENT EQU 48
|
||||
SYS_CLEAR_EVENT EQU 49
|
||||
SYS_CREATE_MUTEX EQU 46
|
||||
SYS_TRY_ACQUIRE_MUTEX EQU 47
|
||||
SYS_RELEASE_MUTEX EQU 48
|
||||
SYS_CREATE_SEM EQU 49
|
||||
SYS_TRY_WAIT_SEM EQU 50
|
||||
SYS_SIGNAL_SEM EQU 51
|
||||
SYS_CREATE_EVENT EQU 52
|
||||
SYS_SIGNAL_EVENT EQU 53
|
||||
SYS_CLEAR_EVENT EQU 54
|
||||
|
||||
; Queues and named queues.
|
||||
SYS_CREATE_QUEUE EQU 50
|
||||
SYS_SEND_QUEUE EQU 51
|
||||
SYS_RECV_QUEUE EQU 52
|
||||
SYS_PUBLISH_QUEUE EQU 53
|
||||
SYS_OPEN_NAMED_QUEUE EQU 54
|
||||
SYS_OPEN_NAMED_QUEUE_OWNER_PROCESS EQU 55
|
||||
SYS_UNPUBLISH_QUEUE EQU 56
|
||||
SYS_CREATE_QUEUE EQU 55
|
||||
SYS_SEND_QUEUE EQU 56
|
||||
SYS_RECV_QUEUE EQU 57
|
||||
SYS_PUBLISH_QUEUE EQU 58
|
||||
SYS_OPEN_NAMED_QUEUE EQU 59
|
||||
SYS_OPEN_NAMED_QUEUE_OWNER_PROCESS EQU 60
|
||||
SYS_UNPUBLISH_QUEUE EQU 61
|
||||
|
||||
; LPC-like Ports and well-known system services.
|
||||
SYS_CREATE_PORT EQU 57
|
||||
SYS_CONNECT_PORT EQU 58
|
||||
SYS_ACCEPT_PORT EQU 59
|
||||
SYS_SEND_PORT EQU 60
|
||||
SYS_RECEIVE_PORT EQU 61
|
||||
SYS_CALL_PORT EQU 62
|
||||
SYS_REPLY_PORT EQU 63
|
||||
SYS_DISCONNECT_PORT EQU 64
|
||||
SYS_REGISTER_SYSTEM_SERVICE EQU 65
|
||||
SYS_UNREGISTER_SYSTEM_SERVICE EQU 66
|
||||
SYS_CONNECT_SYSTEM_SERVICE EQU 67
|
||||
SYS_CREATE_PORT EQU 62
|
||||
SYS_CONNECT_PORT EQU 63
|
||||
SYS_ACCEPT_PORT EQU 64
|
||||
SYS_SEND_PORT EQU 65
|
||||
SYS_RECEIVE_PORT EQU 66
|
||||
SYS_CALL_PORT EQU 67
|
||||
SYS_REPLY_PORT EQU 68
|
||||
SYS_DISCONNECT_PORT EQU 69
|
||||
SYS_OPEN_PORT_PEER_PROCESS EQU 70
|
||||
SYS_REGISTER_SYSTEM_SERVICE EQU 71
|
||||
SYS_UNREGISTER_SYSTEM_SERVICE EQU 72
|
||||
SYS_CONNECT_SYSTEM_SERVICE EQU 73
|
||||
|
||||
; Mounted-volume manager control plane.
|
||||
SYS_QUERY_VOLUMES EQU 68
|
||||
SYS_OPEN_VOLUME EQU 69
|
||||
SYS_WAIT_VOLUME_CHANGE EQU 70
|
||||
SYS_QUERY_VOLUMES EQU 74
|
||||
SYS_OPEN_VOLUME EQU 75
|
||||
SYS_WAIT_VOLUME_CHANGE EQU 76
|
||||
|
||||
; Files and directories.
|
||||
SYS_OPEN_FILE_AT EQU 71
|
||||
SYS_OPEN_DIR_AT EQU 72
|
||||
SYS_STAT_AT EQU 73
|
||||
SYS_DELETE_AT EQU 74
|
||||
SYS_RENAME_AT EQU 75
|
||||
SYS_CREATE_DIR_AT EQU 76
|
||||
SYS_REMOVE_DIR_AT EQU 77
|
||||
SYS_READ_FILE EQU 78
|
||||
SYS_WRITE_FILE EQU 79
|
||||
SYS_READ_FILE_ASYNC EQU 80
|
||||
SYS_WRITE_FILE_ASYNC EQU 81
|
||||
SYS_CANCEL_IO EQU 82
|
||||
SYS_SEEK_FILE EQU 83
|
||||
SYS_GET_FILE_POS EQU 84
|
||||
SYS_GET_FILE_SIZE EQU 85
|
||||
SYS_GET_FILE_STAT EQU 86
|
||||
SYS_TRUNCATE_FILE EQU 87
|
||||
SYS_FLUSH_FILE EQU 88
|
||||
SYS_LOCK_FILE EQU 89
|
||||
SYS_UNLOCK_FILE EQU 90
|
||||
SYS_QUERY_FILE_LOCK EQU 91
|
||||
SYS_SET_FILE_STATUS EQU 92
|
||||
SYS_CREATE_PIPE EQU 93
|
||||
SYS_NOTIFY_PIPE EQU 94
|
||||
SYS_READ_DIR EQU 95
|
||||
SYS_OPEN_FILE_AT EQU 77
|
||||
SYS_OPEN_DIR_AT EQU 78
|
||||
SYS_STAT_AT EQU 79
|
||||
SYS_DELETE_AT EQU 80
|
||||
SYS_RENAME_AT EQU 81
|
||||
SYS_CREATE_DIR_AT EQU 82
|
||||
SYS_REMOVE_DIR_AT EQU 83
|
||||
SYS_READ_FILE EQU 84
|
||||
SYS_WRITE_FILE EQU 85
|
||||
SYS_READ_FILE_ASYNC EQU 86
|
||||
SYS_WRITE_FILE_ASYNC EQU 87
|
||||
SYS_CANCEL_IO EQU 88
|
||||
SYS_SEEK_FILE EQU 89
|
||||
SYS_GET_FILE_POS EQU 90
|
||||
SYS_GET_FILE_SIZE EQU 91
|
||||
SYS_GET_FILE_STAT EQU 92
|
||||
SYS_TRUNCATE_FILE EQU 93
|
||||
SYS_FLUSH_FILE EQU 94
|
||||
SYS_LOCK_FILE EQU 95
|
||||
SYS_UNLOCK_FILE EQU 96
|
||||
SYS_QUERY_FILE_LOCK EQU 97
|
||||
SYS_SET_FILE_STATUS EQU 98
|
||||
SYS_CREATE_PIPE EQU 99
|
||||
SYS_NOTIFY_PIPE EQU 100
|
||||
SYS_READ_DIR EQU 101
|
||||
|
||||
; Console, display, and surfaces.
|
||||
SYS_WRITE_CONSOLE EQU 96
|
||||
SYS_GET_CONSOLE_INFO EQU 97
|
||||
SYS_SET_CONSOLE_CURSOR EQU 98
|
||||
SYS_FILL_CONSOLE_CHARACTER EQU 99
|
||||
SYS_FILL_CONSOLE_ATTRIBUTE EQU 100
|
||||
SYS_PUT_SCREEN_CHAR EQU 101
|
||||
SYS_CLEAR_SCREEN EQU 102
|
||||
SYS_GET_SCREEN_SIZE EQU 103
|
||||
SYS_QUERY_DISPLAY_INFO EQU 104
|
||||
SYS_QUERY_DISPLAY_MANAGER_INFO EQU 105
|
||||
SYS_PRESENT_DISPLAY_MANAGER_SURFACE EQU 106
|
||||
SYS_SET_DISPLAY_MANAGER_CURSOR EQU 107
|
||||
SYS_WRITE_DISPLAY_MANAGER_CONSOLE EQU 108
|
||||
SYS_QUERY_DISPLAY_MANAGER_CONSOLE_INFO EQU 109
|
||||
SYS_SET_DISPLAY_MANAGER_CONSOLE_CURSOR EQU 110
|
||||
SYS_FILL_DISPLAY_MANAGER_CONSOLE_CHARACTER EQU 111
|
||||
SYS_FILL_DISPLAY_MANAGER_CONSOLE_ATTRIBUTE EQU 112
|
||||
SYS_PUT_DISPLAY_MANAGER_CONSOLE_CHARACTER EQU 113
|
||||
SYS_CLEAR_DISPLAY_MANAGER_CONSOLE EQU 114
|
||||
SYS_OPEN_DISPLAY_CLOCK EQU 115
|
||||
SYS_CREATE_SURFACE EQU 116
|
||||
SYS_MAP_SURFACE EQU 117
|
||||
SYS_UNMAP_SURFACE EQU 118
|
||||
SYS_QUERY_SURFACE EQU 119
|
||||
SYS_COMMIT_SURFACE EQU 120
|
||||
SYS_WRITE_CONSOLE EQU 102
|
||||
SYS_GET_CONSOLE_INFO EQU 103
|
||||
SYS_SET_CONSOLE_CURSOR EQU 104
|
||||
SYS_FILL_CONSOLE_CHARACTER EQU 105
|
||||
SYS_FILL_CONSOLE_ATTRIBUTE EQU 106
|
||||
SYS_PUT_SCREEN_CHAR EQU 107
|
||||
SYS_CLEAR_SCREEN EQU 108
|
||||
SYS_GET_SCREEN_SIZE EQU 109
|
||||
SYS_QUERY_DISPLAY_INFO EQU 110
|
||||
SYS_QUERY_DISPLAY_MANAGER_INFO EQU 111
|
||||
SYS_PRESENT_DISPLAY_MANAGER_SURFACE EQU 112
|
||||
SYS_SET_DISPLAY_MANAGER_CURSOR EQU 113
|
||||
SYS_WRITE_DISPLAY_MANAGER_CONSOLE EQU 114
|
||||
SYS_QUERY_DISPLAY_MANAGER_CONSOLE_INFO EQU 115
|
||||
SYS_SET_DISPLAY_MANAGER_CONSOLE_CURSOR EQU 116
|
||||
SYS_FILL_DISPLAY_MANAGER_CONSOLE_CHARACTER EQU 117
|
||||
SYS_FILL_DISPLAY_MANAGER_CONSOLE_ATTRIBUTE EQU 118
|
||||
SYS_PUT_DISPLAY_MANAGER_CONSOLE_CHARACTER EQU 119
|
||||
SYS_CLEAR_DISPLAY_MANAGER_CONSOLE EQU 120
|
||||
SYS_OPEN_DISPLAY_CLOCK EQU 121
|
||||
SYS_CREATE_SURFACE EQU 122
|
||||
SYS_MAP_SURFACE EQU 123
|
||||
SYS_UNMAP_SURFACE EQU 124
|
||||
SYS_QUERY_SURFACE EQU 125
|
||||
SYS_COMMIT_SURFACE EQU 126
|
||||
|
||||
; Native render audio.
|
||||
SYS_AUDIO_ENUMERATE_ENDPOINTS EQU 121
|
||||
SYS_AUDIO_OPEN_STREAM EQU 122
|
||||
SYS_AUDIO_WRITE EQU 123
|
||||
SYS_AUDIO_ARM_WAIT EQU 124
|
||||
SYS_AUDIO_QUERY_STREAM EQU 125
|
||||
SYS_AUDIO_START EQU 126
|
||||
SYS_AUDIO_PAUSE EQU 127
|
||||
SYS_AUDIO_RESUME EQU 128
|
||||
SYS_AUDIO_DRAIN EQU 129
|
||||
SYS_AUDIO_STOP EQU 130
|
||||
SYS_AUDIO_RESET EQU 131
|
||||
SYS_AUDIO_SET_VOLUME EQU 132
|
||||
SYS_AUDIO_SET_MASTER_VOLUME EQU 133
|
||||
SYS_AUDIO_ENUMERATE_ENDPOINTS EQU 127
|
||||
SYS_AUDIO_OPEN_STREAM EQU 128
|
||||
SYS_AUDIO_WRITE EQU 129
|
||||
SYS_AUDIO_ARM_WAIT EQU 130
|
||||
SYS_AUDIO_QUERY_STREAM EQU 131
|
||||
SYS_AUDIO_START EQU 132
|
||||
SYS_AUDIO_PAUSE EQU 133
|
||||
SYS_AUDIO_RESUME EQU 134
|
||||
SYS_AUDIO_DRAIN EQU 135
|
||||
SYS_AUDIO_STOP EQU 136
|
||||
SYS_AUDIO_RESET EQU 137
|
||||
SYS_AUDIO_SET_VOLUME EQU 138
|
||||
SYS_AUDIO_SET_MASTER_VOLUME EQU 139
|
||||
|
||||
; Input.
|
||||
SYS_READ_INPUT_MANAGER_EVENT EQU 134
|
||||
SYS_POLL_KEYBOARD EQU 135
|
||||
SYS_IS_KEY_DOWN EQU 136
|
||||
SYS_READ_KEYBOARD_CHAR EQU 137
|
||||
SYS_READ_KEY EQU 138
|
||||
SYS_GET_KEY_MODIFIERS EQU 139
|
||||
SYS_QUERY_GLOBAL_INPUT_STATE EQU 140
|
||||
SYS_OPEN_INPUT_QUEUE EQU 141
|
||||
SYS_READ_INPUT_EVENT EQU 142
|
||||
SYS_PEEK_INPUT_EVENT EQU 143
|
||||
SYS_PEEK_MOUSE EQU 144
|
||||
SYS_READ_MOUSE EQU 145
|
||||
SYS_GET_MOUSE_POS EQU 146
|
||||
SYS_READ_INPUT_MANAGER_EVENT EQU 140
|
||||
SYS_POLL_KEYBOARD EQU 141
|
||||
SYS_IS_KEY_DOWN EQU 142
|
||||
SYS_READ_KEYBOARD_CHAR EQU 143
|
||||
SYS_READ_KEY EQU 144
|
||||
SYS_GET_KEY_MODIFIERS EQU 145
|
||||
SYS_QUERY_GLOBAL_INPUT_STATE EQU 146
|
||||
SYS_OPEN_INPUT_QUEUE EQU 147
|
||||
SYS_READ_INPUT_EVENT EQU 148
|
||||
SYS_PEEK_INPUT_EVENT EQU 149
|
||||
SYS_PEEK_MOUSE EQU 150
|
||||
SYS_READ_MOUSE EQU 151
|
||||
SYS_GET_MOUSE_POS EQU 152
|
||||
|
||||
; Time, debug, and system information.
|
||||
SYS_CREATE_TIMER EQU 147
|
||||
SYS_SET_TIMER EQU 148
|
||||
SYS_CANCEL_TIMER EQU 149
|
||||
SYS_GET_TICK EQU 150
|
||||
SYS_GET_TICK_FREQUENCY EQU 151
|
||||
SYS_GET_SYSTEM_TIME EQU 152
|
||||
SYS_PRINT_DEBUG EQU 153
|
||||
SYS_QUERY_TRAP_FRAME EQU 154
|
||||
SYS_GET_MEMORY_STATUS EQU 155
|
||||
SYS_QUERY_KERNEL_STATS EQU 156
|
||||
SYS_CREATE_TIMER EQU 153
|
||||
SYS_SET_TIMER EQU 154
|
||||
SYS_CANCEL_TIMER EQU 155
|
||||
SYS_GET_TICK EQU 156
|
||||
SYS_GET_TICK_FREQUENCY EQU 157
|
||||
SYS_GET_SYSTEM_TIME EQU 158
|
||||
SYS_PRINT_DEBUG EQU 159
|
||||
SYS_QUERY_TRAP_FRAME EQU 160
|
||||
SYS_GET_MEMORY_STATUS EQU 161
|
||||
SYS_QUERY_KERNEL_STATS EQU 162
|
||||
|
||||
; Native sockets and polling.
|
||||
SYS_CREATE_SOCKET EQU 157
|
||||
SYS_SOCKET_IO_ASYNC EQU 158
|
||||
SYS_BIND_SOCKET EQU 159
|
||||
SYS_LISTEN_SOCKET EQU 160
|
||||
SYS_ACCEPT_SOCKET EQU 161
|
||||
SYS_CONNECT_SOCKET EQU 162
|
||||
SYS_SEND_SOCKET EQU 163
|
||||
SYS_RECV_SOCKET EQU 164
|
||||
SYS_SHUTDOWN_SOCKET EQU 165
|
||||
SYS_SEND_TO_SOCKET EQU 166
|
||||
SYS_RECV_FROM_SOCKET EQU 167
|
||||
SYS_RESOLVE_HOST EQU 168
|
||||
SYS_SET_SOCKET_OPTION EQU 169
|
||||
SYS_GET_SOCKET_OPTION EQU 170
|
||||
SYS_POLL EQU 171
|
||||
SYS_CREATE_SOCKET EQU 163
|
||||
SYS_SOCKET_IO_ASYNC EQU 164
|
||||
SYS_BIND_SOCKET EQU 165
|
||||
SYS_LISTEN_SOCKET EQU 166
|
||||
SYS_ACCEPT_SOCKET EQU 167
|
||||
SYS_CONNECT_SOCKET EQU 168
|
||||
SYS_SEND_SOCKET EQU 169
|
||||
SYS_RECV_SOCKET EQU 170
|
||||
SYS_SHUTDOWN_SOCKET EQU 171
|
||||
SYS_SEND_TO_SOCKET EQU 172
|
||||
SYS_RECV_FROM_SOCKET EQU 173
|
||||
SYS_RESOLVE_HOST EQU 174
|
||||
SYS_SET_SOCKET_OPTION EQU 175
|
||||
SYS_GET_SOCKET_OPTION EQU 176
|
||||
SYS_POLL EQU 177
|
||||
|
||||
SYS_MAX EQU 172
|
||||
SYS_MAX EQU 178
|
||||
@@ -53,9 +53,12 @@ SYSCALL_STUB KillProcess, SYS_KILL_PROCESS
|
||||
SYSCALL_STUB GetProcessList, SYS_GET_PROCESS_LIST
|
||||
SYSCALL_STUB GetProcessPid, SYS_GET_PROCESS_PID
|
||||
SYSCALL_STUB GetThreadList, SYS_GET_THREAD_LIST
|
||||
SYSCALL_STUB GetThreadTid, SYS_GET_THREAD_TID
|
||||
|
||||
SYSCALL_STUB CreateThread, SYS_CREATE_THREAD
|
||||
SYSCALL_STUB OpenCurrentThread, SYS_OPEN_CURRENT_THREAD
|
||||
SYSCALL_STUB ResumeThread, SYS_RESUME_THREAD
|
||||
SYSCALL_STUB ResumeThreadAndWait, SYS_RESUME_THREAD_AND_WAIT
|
||||
SYSCALL_STUB GetCurrentTid, SYS_GET_CURRENT_TID
|
||||
SYSCALL_STUB GetCurrentPid, SYS_GET_CURRENT_PID
|
||||
SYSCALL_STUB SetThreadPriority, SYS_SET_THREAD_PRIORITY
|
||||
@@ -64,6 +67,7 @@ SYSCALL_STUB QueryThreadName, SYS_QUERY_THREAD_NAME
|
||||
SYSCALL_STUB Yield, SYS_YIELD
|
||||
SYSCALL_STUB Sleep, SYS_SLEEP
|
||||
SYSCALL_STUB SetUserApcDispatcher, SYS_SET_USER_APC_DISPATCHER
|
||||
SYSCALL_STUB QueueUserApc, SYS_QUEUE_USER_APC
|
||||
SYSCALL_STUB ApcReturn, SYS_APC_RETURN
|
||||
SYSCALL_STUB SetExceptionDispatcher, SYS_SET_EXCEPTION_DISPATCHER
|
||||
SYSCALL_STUB GetExceptionDispatcher, SYS_GET_EXCEPTION_DISPATCHER
|
||||
@@ -116,6 +120,7 @@ SYSCALL_STUB DeriveHandle, SYS_DERIVE_HANDLE
|
||||
SYSCALL_STUB RevokeHandle, SYS_REVOKE_HANDLE
|
||||
SYSCALL_STUB DeriveSecurityContext, SYS_DERIVE_SECURITY_CONTEXT
|
||||
SYSCALL_STUB QuerySecurityContext, SYS_QUERY_SECURITY_CONTEXT
|
||||
SYSCALL_STUB OpenProcessSecurityContext, SYS_OPEN_PROCESS_SECURITY_CONTEXT
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; Synchronization objects
|
||||
@@ -155,6 +160,7 @@ SYSCALL_STUB ReceivePort, SYS_RECEIVE_PORT
|
||||
SYSCALL_STUB CallPort, SYS_CALL_PORT
|
||||
SYSCALL_STUB ReplyPort, SYS_REPLY_PORT
|
||||
SYSCALL_STUB DisconnectPort, SYS_DISCONNECT_PORT
|
||||
SYSCALL_STUB OpenPortPeerProcess, SYS_OPEN_PORT_PEER_PROCESS
|
||||
SYSCALL_STUB RegisterSystemService, SYS_REGISTER_SYSTEM_SERVICE
|
||||
SYSCALL_STUB UnregisterSystemService, SYS_UNREGISTER_SYSTEM_SERVICE
|
||||
SYSCALL_STUB ConnectSystemService, SYS_CONNECT_SYSTEM_SERVICE
|
||||
|
||||
Reference in new issue
Block a user