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
+190
-4
@@ -416,6 +416,33 @@ static uint64_t SyscallCreateThread(const SYS_CREATE_THREAD_REQUEST* request) {
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Implements SYS_OPEN_CURRENT_THREAD.
|
||||
static uint64_t SyscallOpenCurrentThread(SYS_RIGHTS desiredAccess, SYS_HANDLE* handleOut) {
|
||||
if (!handleOut || desiredAccess == 0) return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
SYS_RIGHTS validAccess = KeGetValidHandleRights(ObjectTypeThread);
|
||||
if ((desiredAccess & ~validAccess) != 0) return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
KSTATUS status = MmProbeUserWrite(handleOut, sizeof(SYS_HANDLE));
|
||||
if (!KSUCCESS(status)) return status;
|
||||
|
||||
PROCESS* process = KeGetCurrentProcess();
|
||||
THREAD* thread = KeGetCurrentThread();
|
||||
if (!process || !thread) return NTLSTATUS_FAILURE;
|
||||
|
||||
SYS_HANDLE handle = SYS_HANDLE_INVALID;
|
||||
status = KeCreateHandle(process, &thread->Header, desiredAccess, &handle);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
|
||||
status = KiCopyHandleToUser(handleOut, handle);
|
||||
if (!KSUCCESS(status)) {
|
||||
KeCloseHandle(process, handle);
|
||||
return status;
|
||||
}
|
||||
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Implements SYS_RESUME_THREAD.
|
||||
static uint64_t SyscallResumeThread(SYS_HANDLE threadHandle, uint32_t* previousSuspendCountOut) {
|
||||
if (!threadHandle || !previousSuspendCountOut) return NTLSTATUS_INVALID_PARAMETER;
|
||||
@@ -440,6 +467,61 @@ static uint64_t SyscallResumeThread(SYS_HANDLE threadHandle, uint32_t* previousS
|
||||
return KiCopyU32ToUser(previousSuspendCountOut, previousSuspendCount);
|
||||
}
|
||||
|
||||
// Implements SYS_RESUME_THREAD_AND_WAIT.
|
||||
// Resumes one suspended thread and blocks until that same thread exits without
|
||||
// returning to userspace between the resume and wait operations.
|
||||
static uint64_t SyscallResumeThreadAndWait(SYS_HANDLE threadHandle,
|
||||
uint32_t* previousSuspendCountOut) {
|
||||
if (!threadHandle || !previousSuspendCountOut) return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
KSTATUS status = MmProbeUserWrite(previousSuspendCountOut, sizeof(uint32_t));
|
||||
if (!KSUCCESS(status)) return status;
|
||||
|
||||
PROCESS* process = KeGetCurrentProcess();
|
||||
THREAD* currentThread = KeGetCurrentThread();
|
||||
if (!process || !currentThread) return NTLSTATUS_FAILURE;
|
||||
|
||||
OBJECT* object = (OBJECT*)0;
|
||||
status = KeReferenceHandle(process, threadHandle, ObjectTypeThread,
|
||||
SYS_THREAD_RIGHT_RESUME | SYS_RIGHT_WAIT, &object);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
|
||||
THREAD* thread = CONTAINING_RECORD(object, THREAD, Header);
|
||||
if (thread == currentThread) {
|
||||
ObDereferenceObject(object);
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
uint32_t previousSuspendCount = 0;
|
||||
status = KeResumeThread(thread, &previousSuspendCount);
|
||||
if (KSUCCESS(status))
|
||||
status = KeWaitForEvent(thread->ExitEvent, 0);
|
||||
|
||||
ObDereferenceObject(object);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
return KiCopyU32ToUser(previousSuspendCountOut, previousSuspendCount);
|
||||
}
|
||||
|
||||
// Implements SYS_GET_THREAD_TID.
|
||||
static uint64_t SyscallGetThreadTid(SYS_HANDLE threadHandle, uint32_t* tidOut) {
|
||||
if (!threadHandle || !tidOut) return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
KSTATUS status = MmProbeUserWrite(tidOut, sizeof(uint32_t));
|
||||
if (!KSUCCESS(status)) return status;
|
||||
|
||||
PROCESS* process = KeGetCurrentProcess();
|
||||
if (!process) return NTLSTATUS_FAILURE;
|
||||
|
||||
OBJECT* object = (OBJECT*)0;
|
||||
status = KeReferenceHandle(process, threadHandle, ObjectTypeThread, SYS_RIGHT_QUERY, &object);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
|
||||
THREAD* thread = CONTAINING_RECORD(object, THREAD, Header);
|
||||
uint32_t tid = thread->ThreadId;
|
||||
ObDereferenceObject(object);
|
||||
return KiCopyU32ToUser(tidOut, tid);
|
||||
}
|
||||
|
||||
static void KiFinishAlertableUserWait(uint8_t alertable) {
|
||||
if (!alertable) return;
|
||||
|
||||
@@ -740,6 +822,36 @@ static uint64_t SyscallSetUserApcDispatcher(void* dispatcher) {
|
||||
return KeSetUserApcDispatcher(dispatcher);
|
||||
}
|
||||
|
||||
// Implements SYS_QUEUE_USER_APC.
|
||||
static uint64_t SyscallQueueUserApc(const SYS_QUEUE_USER_APC_REQUEST* userRequest) {
|
||||
SYS_QUEUE_USER_APC_REQUEST request;
|
||||
KSTATUS status = KiCopySizedUserRequest(userRequest, &request, sizeof(request));
|
||||
if (!KSUCCESS(status)) return status;
|
||||
if (!request.ThreadHandle || !request.Routine || request.Reserved != 0 ||
|
||||
(request.Flags & ~SYS_QUEUE_USER_APC_FLAG_INTERRUPT) != 0)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
PROCESS* process = KeGetCurrentProcess();
|
||||
if (!process) return NTLSTATUS_FAILURE;
|
||||
|
||||
OBJECT* object = (OBJECT*)0;
|
||||
status = KeReferenceHandle(process, request.ThreadHandle, ObjectTypeThread,
|
||||
SYS_THREAD_RIGHT_NOTIFY, &object);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
|
||||
THREAD* thread = CONTAINING_RECORD(object, THREAD, Header);
|
||||
status = KeQueueUserApc(thread,
|
||||
(void*)(uintptr_t)request.Routine,
|
||||
request.NormalContext,
|
||||
request.SystemArgument1,
|
||||
request.SystemArgument2,
|
||||
(request.Flags & SYS_QUEUE_USER_APC_FLAG_INTERRUPT) != 0
|
||||
? KE_USER_APC_FLAG_INTERRUPT
|
||||
: KE_USER_APC_FLAG_NONE);
|
||||
ObDereferenceObject(object);
|
||||
return status;
|
||||
}
|
||||
|
||||
// Implements SYS_APC_RETURN.
|
||||
static uint64_t SyscallApcReturn(const SYS_USER_APC_FRAME* frame) {
|
||||
return KeUserApcReturn((const SYS_USER_APC_FRAME_K*)(uintptr_t)frame);
|
||||
@@ -1978,7 +2090,8 @@ static void SyscallUserAsyncNormalRoutine(void* normalContext,
|
||||
(void*)ctx->UserRoutine,
|
||||
ctx->UserContext,
|
||||
iosb,
|
||||
(void*)(uintptr_t)information);
|
||||
(void*)(uintptr_t)information,
|
||||
KE_USER_APC_FLAG_NONE);
|
||||
if (!KSUCCESS(s)) {
|
||||
DbgPrint("USER/APC async: KeQueueUserApc failed status=%u\n", s);
|
||||
}
|
||||
@@ -3105,7 +3218,7 @@ static uint64_t SyscallOpenProcess(uint32_t pid, SYS_RIGHTS desiredAccess, SYS_H
|
||||
|
||||
PROCESS* caller = KeGetCurrentProcess();
|
||||
if (!caller) return NTLSTATUS_FAILURE;
|
||||
if (pid != caller->ProcessId) {
|
||||
if (pid != caller->ProcessId || (desiredAccess & SYS_PROCESS_RIGHT_SECURITY_CONTEXT) != 0) {
|
||||
KSTATUS privilegeStatus = KiRequirePrivilege(SYS_PRIV_PROCESS_OPEN_ANY);
|
||||
if (!KSUCCESS(privilegeStatus)) return privilegeStatus;
|
||||
}
|
||||
@@ -3214,13 +3327,16 @@ static uint64_t SyscallCreatePort(const SYS_CREATE_PORT_REQUEST* request) {
|
||||
SYS_CREATE_PORT_REQUEST req;
|
||||
KSTATUS status = KiCopySizedUserRequest(request, &req, sizeof(req));
|
||||
if (!KSUCCESS(status)) return status;
|
||||
if (req.Flags != SYS_PORT_FLAG_NONE || !req.HandleOut)
|
||||
if (req.Flags != SYS_PORT_FLAG_NONE || req.Reserved != 0 || !req.HandleOut)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
SYS_RIGHTS validPeerRights = KeGetValidHandleRights(ObjectTypeProcess);
|
||||
if ((req.PeerProcessRights & ~validPeerRights) != 0)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
status = MmProbeUserWrite(req.HandleOut, sizeof(*req.HandleOut));
|
||||
if (!KSUCCESS(status)) return status;
|
||||
|
||||
PORT* port = (PORT*)0;
|
||||
status = KePortCreate(req.Backlog, &port);
|
||||
status = KePortCreate(req.Backlog, req.PeerProcessRights, &port);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
|
||||
SYS_HANDLE handle = SYS_HANDLE_INVALID;
|
||||
@@ -3509,6 +3625,36 @@ static uint64_t SyscallDisconnectPort(SYS_HANDLE endpointHandle) {
|
||||
return status;
|
||||
}
|
||||
|
||||
// Implements SYS_OPEN_PORT_PEER_PROCESS.
|
||||
static uint64_t SyscallOpenPortPeerProcess(SYS_HANDLE endpointHandle,
|
||||
SYS_RIGHTS desiredRights,
|
||||
SYS_HANDLE* processHandleOut) {
|
||||
if (!processHandleOut || desiredRights == 0) return NTLSTATUS_INVALID_PARAMETER;
|
||||
SYS_RIGHTS validRights = KeGetValidHandleRights(ObjectTypeProcess);
|
||||
if ((desiredRights & ~validRights) != 0) return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
KSTATUS status = MmProbeUserWrite(processHandleOut, sizeof(*processHandleOut));
|
||||
if (!KSUCCESS(status)) return status;
|
||||
|
||||
KSTATUS handleStatus = NTLSTATUS_SUCCESS;
|
||||
PORT* endpoint = (PORT*)KiHandleToObject(endpointHandle,
|
||||
ObjectTypePort,
|
||||
SYS_PORT_RIGHT_OPEN_PEER_PROCESS,
|
||||
&handleStatus);
|
||||
if (!endpoint) return handleStatus;
|
||||
|
||||
PROCESS* caller = KeGetCurrentProcess();
|
||||
SYS_HANDLE processHandle = SYS_HANDLE_INVALID;
|
||||
status = caller ? KePortOpenPeerProcess(endpoint, caller, desiredRights, &processHandle)
|
||||
: NTLSTATUS_FAILURE;
|
||||
ObDereferenceObject((OBJECT*)endpoint);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
|
||||
status = KiCopyHandleToUser(processHandleOut, processHandle);
|
||||
if (!KSUCCESS(status) && caller) (void)KeCloseHandle(caller, processHandle);
|
||||
return status;
|
||||
}
|
||||
|
||||
// Implements SYS_REGISTER_SYSTEM_SERVICE.
|
||||
static uint64_t SyscallRegisterSystemService(SYS_SERVICE_ID serviceId, SYS_HANDLE listenerHandle) {
|
||||
if (serviceId == SYS_SERVICE_INVALID || serviceId > SYS_SERVICE_MAX)
|
||||
@@ -4060,6 +4206,40 @@ static uint64_t SyscallQuerySecurityContext(SYS_HANDLE contextHandle, SYS_SECURI
|
||||
return CopyToUser(infoOut, &info, sizeof(info));
|
||||
}
|
||||
|
||||
// Implements SYS_OPEN_PROCESS_SECURITY_CONTEXT.
|
||||
static uint64_t SyscallOpenProcessSecurityContext(SYS_HANDLE processHandle,
|
||||
SYS_RIGHTS desiredRights,
|
||||
SYS_HANDLE* contextHandleOut) {
|
||||
if (!contextHandleOut || desiredRights == 0) return NTLSTATUS_INVALID_PARAMETER;
|
||||
SYS_RIGHTS validRights = KeGetValidHandleRights(ObjectTypeSecurityContext);
|
||||
if ((desiredRights & ~validRights) != 0) return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
KSTATUS status = MmProbeUserWrite(contextHandleOut, sizeof(*contextHandleOut));
|
||||
if (!KSUCCESS(status)) return status;
|
||||
|
||||
PROCESS* target = (PROCESS*)KiHandleToObject(processHandle,
|
||||
ObjectTypeProcess,
|
||||
SYS_PROCESS_RIGHT_SECURITY_CONTEXT,
|
||||
&status);
|
||||
if (!target) return status;
|
||||
SECURITY_CONTEXT* context = target->SecurityContext;
|
||||
if (!context || !ObTryReferenceObject(&context->Header)) {
|
||||
ObDereferenceObject(&target->Header);
|
||||
return NTLSTATUS_OBJECT_DEAD;
|
||||
}
|
||||
ObDereferenceObject(&target->Header);
|
||||
|
||||
SYS_HANDLE handle = SYS_HANDLE_INVALID;
|
||||
status = KiAllocHandleForCurrentWithRights(&context->Header, desiredRights, &handle);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
status = KiCopyHandleToUser(contextHandleOut, handle);
|
||||
if (!KSUCCESS(status)) {
|
||||
PROCESS* caller = KeGetCurrentProcess();
|
||||
if (caller) (void)KeCloseHandle(caller, handle);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
// Implements SYS_OPEN_NAMED_QUEUE_OWNER_PROCESS.
|
||||
|
||||
// Opens a process handle for the process that published a named queue.
|
||||
@@ -6542,8 +6722,11 @@ static const SYSCALL_ENTRY gSyscallTable[SYS_MAX] = {
|
||||
[SYS_GET_PROCESS_LIST] = SYSCALL_ENTRY3(SyscallGetProcessList),
|
||||
[SYS_GET_PROCESS_PID] = SYSCALL_ENTRY2(SyscallGetProcessPid),
|
||||
[SYS_CREATE_THREAD] = SYSCALL_ENTRY1(SyscallCreateThread),
|
||||
[SYS_OPEN_CURRENT_THREAD] = SYSCALL_ENTRY2(SyscallOpenCurrentThread),
|
||||
[SYS_RESUME_THREAD] = SYSCALL_ENTRY2(SyscallResumeThread),
|
||||
[SYS_RESUME_THREAD_AND_WAIT] = SYSCALL_ENTRY2(SyscallResumeThreadAndWait),
|
||||
[SYS_GET_THREAD_LIST] = SYSCALL_ENTRY4(SyscallGetThreadList),
|
||||
[SYS_GET_THREAD_TID] = SYSCALL_ENTRY2(SyscallGetThreadTid),
|
||||
[SYS_GET_CURRENT_TID] = SYSCALL_ENTRY0(SyscallGetCurrentTid),
|
||||
[SYS_GET_CURRENT_PID] = SYSCALL_ENTRY0(SyscallGetCurrentPid),
|
||||
[SYS_SET_THREAD_PRIORITY] = SYSCALL_ENTRY1(SyscallSetThreadPriority),
|
||||
@@ -6554,6 +6737,7 @@ static const SYSCALL_ENTRY gSyscallTable[SYS_MAX] = {
|
||||
[SYS_WAIT_SINGLE] = SYSCALL_ENTRY3(SyscallWaitSingle),
|
||||
[SYS_WAIT_MANY] = SYSCALL_ENTRY1(SyscallWaitMany),
|
||||
[SYS_SET_USER_APC_DISPATCHER] = SYSCALL_ENTRY1(SyscallSetUserApcDispatcher),
|
||||
[SYS_QUEUE_USER_APC] = SYSCALL_ENTRY1(SyscallQueueUserApc),
|
||||
[SYS_APC_RETURN] = SYSCALL_ENTRY1(SyscallApcReturn),
|
||||
[SYS_SET_EXCEPTION_DISPATCHER] = SYSCALL_ENTRY1(SyscallSetExceptionDispatcher),
|
||||
[SYS_GET_EXCEPTION_DISPATCHER] = SYSCALL_ENTRY1(SyscallGetExceptionDispatcher),
|
||||
@@ -6571,6 +6755,7 @@ static const SYSCALL_ENTRY gSyscallTable[SYS_MAX] = {
|
||||
[SYS_REVOKE_HANDLE] = SYSCALL_ENTRY1(SyscallRevokeHandle),
|
||||
[SYS_DERIVE_SECURITY_CONTEXT] = SYSCALL_ENTRY1(SyscallDeriveSecurityContext),
|
||||
[SYS_QUERY_SECURITY_CONTEXT] = SYSCALL_ENTRY2(SyscallQuerySecurityContext),
|
||||
[SYS_OPEN_PROCESS_SECURITY_CONTEXT] = SYSCALL_ENTRY3(SyscallOpenProcessSecurityContext),
|
||||
[SYS_CREATE_FILE_MAPPING] = SYSCALL_ENTRY1(SyscallCreateFileMapping),
|
||||
[SYS_MAP_FILE] = SYSCALL_ENTRY1(SyscallMapFile),
|
||||
|
||||
@@ -6603,6 +6788,7 @@ static const SYSCALL_ENTRY gSyscallTable[SYS_MAX] = {
|
||||
[SYS_CALL_PORT] = SYSCALL_ENTRY1(SyscallCallPort),
|
||||
[SYS_REPLY_PORT] = SYSCALL_ENTRY1(SyscallReplyPort),
|
||||
[SYS_DISCONNECT_PORT] = SYSCALL_ENTRY1(SyscallDisconnectPort),
|
||||
[SYS_OPEN_PORT_PEER_PROCESS] = SYSCALL_ENTRY3(SyscallOpenPortPeerProcess),
|
||||
[SYS_REGISTER_SYSTEM_SERVICE] = SYSCALL_ENTRY2(SyscallRegisterSystemService),
|
||||
[SYS_UNREGISTER_SYSTEM_SERVICE] = SYSCALL_ENTRY2(SyscallUnregisterSystemService),
|
||||
[SYS_CONNECT_SYSTEM_SERVICE] = SYSCALL_ENTRY1(SyscallConnectSystemService),
|
||||
|
||||
Reference in new issue
Block a user