// POSIX personality process/thread runtime state backed by the native TEB extension slot. #include #include #include #include #include #include #include #include "posix_internal.h" #include "posix_fd.h" static POSIX_PROCESS_STATE* gPosixProcessState; static int gEmergencyErrno; // Resolves the published POSIX service and opens one private client endpoint. static KSTATUS PosixRuntimeConnectServer(SYS_HANDLE* endpointOut) { if (!endpointOut) return NTLSTATUS_INVALID_PARAMETER; *endpointOut = SYS_HANDLE_INVALID; SYS_HANDLE resource = SYS_HANDLE_INVALID; KSTATUS status = NtlResourceConnect(&resource); if (!KSUCCESS(status)) return status; SYS_HANDLE listener = SYS_HANDLE_INVALID; status = NtlResourceLookup(resource, SYS_SV_LITERAL(NTL_POSIX_SERVICE_PATH), SYS_RIGHT_QUERY | SYS_PORT_RIGHT_CONNECT, &listener); (void)NtlResourceClose(resource); if (!KSUCCESS(status)) return status; SYS_CONNECT_PORT_REQUEST connect; memset(&connect, 0, sizeof(connect)); connect.Size = sizeof(connect); connect.ListenerHandle = listener; connect.Flags = SYS_PORT_CONNECT_FLAG_NONE; connect.EndpointHandleOut = endpointOut; status = SysConnectPort(&connect); (void)SysCloseHandle(listener); return status; } // Calls one fixed-size posixsrv request over an explicitly supplied endpoint. static KSTATUS PosixRuntimeCallEndpoint(SYS_HANDLE endpoint, const NTL_POSIX_REQUEST* request, const SYS_PORT_HANDLE_TRANSFER* requestHandles, uint32_t requestHandleCount, SYS_HANDLE* replyHandlesOut, uint32_t replyHandleCapacity, uint32_t expectedReplyHandleCount, uint32_t* actualReplyHandleCountOut, NTL_POSIX_REPLY* replyOut) { if (endpoint == SYS_HANDLE_INVALID || !request || !replyOut || (expectedReplyHandleCount != UINT32_MAX && expectedReplyHandleCount > replyHandleCapacity) || (replyHandleCapacity != 0 && !replyHandlesOut)) return NTLSTATUS_INVALID_PARAMETER; memset(replyOut, 0, sizeof(*replyOut)); if (replyHandlesOut) { for (uint32_t i = 0; i < replyHandleCapacity; ++i) replyHandlesOut[i] = SYS_HANDLE_INVALID; } SYS_PORT_MESSAGE_INFO info; memset(&info, 0, sizeof(info)); info.Size = sizeof(info); SYS_CALL_PORT_REQUEST call; memset(&call, 0, sizeof(call)); call.Size = sizeof(call); call.EndpointHandle = endpoint; call.Flags = SYS_PORT_FLAG_NONE; call.RequestPayload = request; call.RequestLength = sizeof(*request); call.RequestHandles = requestHandles; call.RequestHandleCount = requestHandleCount; call.ReplyPayload = replyOut; call.ReplyCapacity = sizeof(*replyOut); call.ReplyHandlesOut = replyHandlesOut; call.ReplyHandleCapacity = replyHandleCapacity; call.ReplyInfoOut = &info; call.TimeoutMilliseconds = SYS_PORT_TIMEOUT_INFINITE; KSTATUS status = SysCallPort(&call); if (!KSUCCESS(status)) return status; uint32_t expectedHandles = KSUCCESS(replyOut->Status) ? expectedReplyHandleCount : 0u; int handlesValid = expectedReplyHandleCount == UINT32_MAX ? info.HandleCount <= replyHandleCapacity : info.HandleCount == expectedHandles; if (info.Type != SYS_PORT_MESSAGE_REPLY || !handlesValid || info.PayloadLength != sizeof(*replyOut) || replyOut->Size != sizeof(*replyOut) || replyOut->Version != NTL_POSIX_PROTOCOL_VERSION || replyOut->Operation != request->Operation || replyOut->Flags != NTL_POSIX_REQUEST_FLAG_NONE) { if (replyHandlesOut) { uint32_t closeCount = info.HandleCount < replyHandleCapacity ? info.HandleCount : replyHandleCapacity; for (uint32_t i = 0; i < closeCount; ++i) { if (replyHandlesOut[i] != SYS_HANDLE_INVALID) (void)SysCloseHandle(replyHandlesOut[i]); replyHandlesOut[i] = SYS_HANDLE_INVALID; } } return NTLSTATUS_FAILURE; } if (actualReplyHandleCountOut) *actualReplyHandleCountOut = info.HandleCount; return NTLSTATUS_SUCCESS; } // Calls posixsrv while optionally transferring native capabilities. KSTATUS PosixRuntimeCallServerWithHandles(const NTL_POSIX_REQUEST* request, const SYS_PORT_HANDLE_TRANSFER* handles, uint32_t handleCount, NTL_POSIX_REPLY* replyOut) { POSIX_PROCESS_STATE* process = gPosixProcessState; if (!process || process->Magic != POSIX_PROCESS_STATE_MAGIC) return NTLSTATUS_NOT_FOUND; return PosixRuntimeCallEndpoint(process->ServerEndpoint, request, handles, handleCount, (SYS_HANDLE*)0, 0, 0, (uint32_t*)0, replyOut); } // Calls posixsrv with independent request/reply capability transfer. KSTATUS PosixRuntimeCallServerExchange(const NTL_POSIX_REQUEST* request, const SYS_PORT_HANDLE_TRANSFER* requestHandles, uint32_t requestHandleCount, SYS_HANDLE* replyHandlesOut, uint32_t replyHandleCapacity, uint32_t expectedReplyHandleCount, NTL_POSIX_REPLY* replyOut) { POSIX_PROCESS_STATE* process = gPosixProcessState; if (!process || process->Magic != POSIX_PROCESS_STATE_MAGIC) return NTLSTATUS_NOT_FOUND; return PosixRuntimeCallEndpoint(process->ServerEndpoint, request, requestHandles, requestHandleCount, replyHandlesOut, replyHandleCapacity, expectedReplyHandleCount, (uint32_t*)0, replyOut); } KSTATUS PosixRuntimeCallServerExchangeVariable(const NTL_POSIX_REQUEST* request, SYS_HANDLE* replyHandlesOut, uint32_t replyHandleCapacity, uint32_t* replyHandleCountOut, NTL_POSIX_REPLY* replyOut) { POSIX_PROCESS_STATE* process = gPosixProcessState; if (!process || process->Magic != POSIX_PROCESS_STATE_MAGIC || !replyHandleCountOut) return NTLSTATUS_INVALID_PARAMETER; *replyHandleCountOut = 0; return PosixRuntimeCallEndpoint(process->ServerEndpoint, request, (const SYS_PORT_HANDLE_TRANSFER*)0, 0, replyHandlesOut, replyHandleCapacity, UINT32_MAX, replyHandleCountOut, replyOut); } // Calls posixsrv over the registered process endpoint and validates one reply. KSTATUS PosixRuntimeCallServer(const NTL_POSIX_REQUEST* request, NTL_POSIX_REPLY* replyOut) { return PosixRuntimeCallServerWithHandles(request, (const SYS_PORT_HANDLE_TRANSFER*)0, 0, replyOut); } // Queries the current server-owned POSIX process attributes. KSTATUS PosixRuntimeGetProcessAttributes(NTL_POSIX_REPLY* replyOut) { if (!replyOut) return NTLSTATUS_INVALID_PARAMETER; NTL_POSIX_REQUEST request; memset(&request, 0, sizeof(request)); request.Size = sizeof(request); request.Version = NTL_POSIX_PROTOCOL_VERSION; request.Operation = NTL_POSIX_OP_GET_PROCESS_ATTRIBUTES; request.Flags = NTL_POSIX_REQUEST_FLAG_NONE; KSTATUS status = PosixRuntimeCallServer(&request, replyOut); if (!KSUCCESS(status)) return status; return replyOut->Status; } // Reads and validates optional POSIX bootstrap identity from generic userspace loader data. static KSTATUS PosixRuntimeReadBootstrap(NTL_POSIX_BOOTSTRAP_DATA* bootstrapOut) { if (!bootstrapOut) return NTLSTATUS_INVALID_PARAMETER; memset(bootstrapOut, 0, sizeof(*bootstrapOut)); size_t size = 0; KSTATUS status = NtlGetProcessStartupData(bootstrapOut, sizeof(*bootstrapOut), &size); if (status == NTLSTATUS_NOT_FOUND) return NTLSTATUS_SUCCESS; if (!KSUCCESS(status)) return status; if (size != sizeof(*bootstrapOut) || bootstrapOut->Magic != NTL_POSIX_BOOTSTRAP_MAGIC || bootstrapOut->Version != NTL_POSIX_BOOTSTRAP_VERSION || bootstrapOut->Size != sizeof(*bootstrapOut) || bootstrapOut->Reserved != 0) return NTLSTATUS_INVALID_PARAMETER; return NTLSTATUS_SUCCESS; } // Registers the current native process with posixsrv and caches its stable logical identity. static KSTATUS PosixRuntimeRegisterProcess(POSIX_PROCESS_STATE* process, const NTL_POSIX_BOOTSTRAP_DATA* bootstrap) { if (!process || !bootstrap) return NTLSTATUS_INVALID_PARAMETER; KSTATUS status = NTLSTATUS_SUCCESS; SYS_HANDLE endpoint = SYS_HANDLE_INVALID; status = PosixRuntimeConnectServer(&endpoint); if (!KSUCCESS(status)) return status; SYS_HANDLE selfProcess = SYS_HANDLE_INVALID; status = SysOpenProcess(SysGetCurrentPid(), SYS_RIGHT_QUERY | SYS_RIGHT_WAIT | SYS_RIGHT_TRANSFER, &selfProcess); if (!KSUCCESS(status)) { (void)SysDisconnectPort(endpoint); (void)SysCloseHandle(endpoint); return status; } NTL_POSIX_REQUEST request; memset(&request, 0, sizeof(request)); request.Size = sizeof(request); request.Version = NTL_POSIX_PROTOCOL_VERSION; request.Operation = NTL_POSIX_OP_REGISTER_PROCESS; request.Flags = NTL_POSIX_REQUEST_FLAG_NONE; request.TransactionKind = NTL_POSIX_TRANSACTION_NONE; request.BootstrapToken = bootstrap->Token; request.BootstrapPosixPid = bootstrap->PosixPid; request.BootstrapGeneration = bootstrap->Generation; size_t currentDirectorySize = 0; status = NtlGetCurrentDirectory(request.Path, sizeof(request.Path), ¤tDirectorySize); if (!KSUCCESS(status) || currentDirectorySize == 0 || currentDirectorySize > sizeof(request.Path)) { (void)SysDisconnectPort(endpoint); (void)SysCloseHandle(endpoint); (void)SysCloseHandle(selfProcess); return KSUCCESS(status) ? NTLSTATUS_FAILURE : status; } request.PathLength = (uint32_t)strlen(request.Path); SYS_PORT_HANDLE_TRANSFER transfer; memset(&transfer, 0, sizeof(transfer)); transfer.Handle = selfProcess; transfer.DesiredRights = SYS_RIGHT_QUERY | SYS_RIGHT_WAIT; transfer.Flags = SYS_PORT_TRANSFER_FLAG_NONE; NTL_POSIX_REPLY reply; status = PosixRuntimeCallEndpoint(endpoint, &request, &transfer, 1u, (SYS_HANDLE*)0, 0, 0, (uint32_t*)0, &reply); (void)SysCloseHandle(selfProcess); if (!KSUCCESS(status)) { (void)SysDisconnectPort(endpoint); (void)SysCloseHandle(endpoint); return status; } if (!KSUCCESS(reply.Status)) { (void)SysDisconnectPort(endpoint); (void)SysCloseHandle(endpoint); return reply.Status; } if (reply.ClientProcessId != SysGetCurrentPid() || reply.PosixPid == 0 || reply.PosixPid > 0x7FFFFFFFu || reply.NativeGeneration == 0 || reply.ProcessState != NTL_POSIX_PROCESS_STATE_RUNNING) { (void)SysDisconnectPort(endpoint); (void)SysCloseHandle(endpoint); return NTLSTATUS_FAILURE; } process->ServerEndpoint = endpoint; process->DefaultIdentity.PosixPid = reply.PosixPid; process->DefaultIdentity.Generation = reply.NativeGeneration; return NTLSTATUS_SUCCESS; } // Initializes process-local POSIX state, registers stable identity, and attaches the initial thread. uint32_t PosixRuntimeInitializeProcess(void) { if (gPosixProcessState) return PosixRuntimeAttachThread(); SYS_PEB* peb = SysGetPeb(); if (!peb || peb->Magic != SYS_PEB_MAGIC || peb->Version != SYS_ENV_VERSION) return NTLSTATUS_INVALID_PARAMETER; POSIX_PROCESS_STATE* process = (POSIX_PROCESS_STATE*)calloc(1, sizeof(*process)); if (!process) return NTLSTATUS_NO_MEMORY; process->Magic = POSIX_PROCESS_STATE_MAGIC; process->Peb = peb; process->ServerEndpoint = SYS_HANDLE_INVALID; process->FdLock = SYS_HANDLE_INVALID; gPosixProcessState = process; NTL_POSIX_BOOTSTRAP_DATA bootstrap; uint32_t status = PosixRuntimeReadBootstrap(&bootstrap); if (status != NTLSTATUS_SUCCESS) { gPosixProcessState = (POSIX_PROCESS_STATE*)0; free(process); return status; } status = PosixRuntimeRegisterProcess(process, &bootstrap); if (status != NTLSTATUS_SUCCESS) { gPosixProcessState = (POSIX_PROCESS_STATE*)0; free(process); return status; } status = PosixFdInitializeProcess(process, bootstrap.FdInheritanceToken); if (status != NTLSTATUS_SUCCESS) { (void)SysDisconnectPort(process->ServerEndpoint); (void)SysCloseHandle(process->ServerEndpoint); process->ServerEndpoint = SYS_HANDLE_INVALID; gPosixProcessState = (POSIX_PROCESS_STATE*)0; free(process); return status; } status = PosixRuntimeAttachThread(); if (status != NTLSTATUS_SUCCESS) { PosixFdDestroyProcess(process); (void)SysDisconnectPort(process->ServerEndpoint); (void)SysCloseHandle(process->ServerEndpoint); process->ServerEndpoint = SYS_HANDLE_INVALID; gPosixProcessState = (POSIX_PROCESS_STATE*)0; free(process); return status; } return NTLSTATUS_SUCCESS; } // Returns the POSIX state for the current native process after startup. POSIX_PROCESS_STATE* PosixRuntimeProcessState(void) { POSIX_PROCESS_STATE* process = gPosixProcessState; if (!process || process->Magic != POSIX_PROCESS_STATE_MAGIC) return (POSIX_PROCESS_STATE*)0; return process; } // Attaches the native thread to the process's default logical POSIX identity. uint32_t PosixRuntimeAttachThread(void) { SYS_TEB* teb = SysGetTeb(); POSIX_PROCESS_STATE* process = PosixRuntimeProcessState(); if (!teb || teb->Magic != SYS_TEB_MAGIC || !process) return NTLSTATUS_INVALID_PARAMETER; if (teb->SubsystemData) { POSIX_THREAD_STATE* existing = (POSIX_THREAD_STATE*)teb->SubsystemData; return existing->Magic == POSIX_THREAD_STATE_MAGIC && existing->NativeProcess == process && existing->LogicalProcess ? NTLSTATUS_SUCCESS : NTLSTATUS_ACCESS_DENIED; } POSIX_THREAD_STATE* thread = (POSIX_THREAD_STATE*)calloc(1, sizeof(*thread)); if (!thread) return NTLSTATUS_NO_MEMORY; thread->Magic = POSIX_THREAD_STATE_MAGIC; thread->NativeProcess = process; thread->LogicalProcess = &process->DefaultIdentity; teb->SubsystemData = thread; return NTLSTATUS_SUCCESS; } // Returns the current thread state, attaching lazily when necessary. POSIX_THREAD_STATE* PosixRuntimeThreadState(void) { if (!PosixRuntimeProcessState()) { if (PosixRuntimeInitializeProcess() != NTLSTATUS_SUCCESS) return (POSIX_THREAD_STATE*)0; } SYS_TEB* teb = SysGetTeb(); if (!teb || teb->Magic != SYS_TEB_MAGIC) return (POSIX_THREAD_STATE*)0; if (!teb->SubsystemData && PosixRuntimeAttachThread() != NTLSTATUS_SUCCESS) return (POSIX_THREAD_STATE*)0; POSIX_THREAD_STATE* thread = (POSIX_THREAD_STATE*)teb->SubsystemData; if (!thread || thread->Magic != POSIX_THREAD_STATE_MAGIC || thread->NativeProcess != PosixRuntimeProcessState() || !thread->LogicalProcess) return (POSIX_THREAD_STATE*)0; return thread; } // Releases POSIX state owned by the current native TEB. void PosixRuntimeDetachThread(void) { SYS_TEB* teb = SysGetTeb(); if (!teb || teb->Magic != SYS_TEB_MAGIC || !teb->SubsystemData) return; POSIX_THREAD_STATE* thread = (POSIX_THREAD_STATE*)teb->SubsystemData; if (thread->Magic != POSIX_THREAD_STATE_MAGIC || thread->NativeProcess != PosixRuntimeProcessState()) return; teb->SubsystemData = (void*)0; thread->Magic = 0; free(thread); } // Returns the lvalue backing the current thread's errno value. NTL_POSIX_API int* __ntl_posix_errno_location(void) { POSIX_THREAD_STATE* thread = PosixRuntimeThreadState(); if (!thread) return &gEmergencyErrno; return &thread->ErrnoValue; } // Clears the current thread's dynamic-loader error state. void PosixRuntimeClearDlError(void) { POSIX_THREAD_STATE* thread = PosixRuntimeThreadState(); if (!thread) return; thread->DlError[0] = '\0'; thread->DlErrorPending = 0; } // Stores one dynamic-loader error in current-thread state. void PosixRuntimeSetDlError(const char* message) { POSIX_THREAD_STATE* thread = PosixRuntimeThreadState(); if (!thread) return; if (!message) message = "dynamic loader error"; strncpy(thread->DlError, message, sizeof(thread->DlError) - 1u); thread->DlError[sizeof(thread->DlError) - 1u] = '\0'; thread->DlErrorPending = 1; } // Returns and consumes the current thread's dynamic-loader error. char* PosixRuntimeTakeDlError(void) { POSIX_THREAD_STATE* thread = PosixRuntimeThreadState(); if (!thread || !thread->DlErrorPending || !thread->DlError[0]) return (char*)0; thread->DlErrorPending = 0; return thread->DlError; } // Initializes all POSIX process state required before application main. NTL_POSIX_API uint32_t __ntl_posix_process_start(void) { uint32_t status = PosixRuntimeInitializeProcess(); if (status != NTLSTATUS_SUCCESS) return status; return NTLSTATUS_SUCCESS; }