// POSIX personality-server bootstrap, stable process identity, shared attributes, and transaction plumbing. #include #include #include #include #include #include #include #include #include #define POSIXSRV_FIRST_PID 0x00010000u #define POSIXSRV_LAST_PID 0x7FFFFFFFu typedef struct POSIXSRV_TRANSACTION { uint32_t Id; uint32_t Kind; } POSIXSRV_TRANSACTION; typedef struct POSIXSRV_OPEN_DESCRIPTION POSIXSRV_OPEN_DESCRIPTION; typedef struct POSIXSRV_PROCESS_RECORD POSIXSRV_PROCESS_RECORD; typedef struct POSIXSRV_FD_INHERITANCE POSIXSRV_FD_INHERITANCE; typedef struct POSIXSRV_PIPE_BACKING { SYS_PIPE_SHARED_STATE* Shared; uint32_t DescriptionCount; } POSIXSRV_PIPE_BACKING; typedef struct POSIXSRV_OPEN_HOLDER { struct POSIXSRV_OPEN_HOLDER* Next; POSIXSRV_OPEN_DESCRIPTION* Description; } POSIXSRV_OPEN_HOLDER; typedef struct POSIXSRV_FD_INHERITANCE_ENTRY { NTL_POSIX_FD_MANIFEST_ENTRY Manifest; POSIXSRV_OPEN_DESCRIPTION* Description; } POSIXSRV_FD_INHERITANCE_ENTRY; typedef struct POSIXSRV_FD_INHERITANCE_MONITOR { uint64_t Token; uint32_t NativeProcessId; SYS_HANDLE ProcessHandle; } POSIXSRV_FD_INHERITANCE_MONITOR; struct POSIXSRV_FD_INHERITANCE { POSIXSRV_FD_INHERITANCE* Next; uint64_t Token; POSIXSRV_PROCESS_RECORD* SourceProcess; POSIXSRV_PROCESS_RECORD* ClaimProcess; uint32_t SecurityId; uint32_t Armed; uint32_t TargetNativeProcessId; uint32_t EntryCount; uint32_t DescriptionCount; POSIXSRV_FD_INHERITANCE_ENTRY Entries[NTL_POSIX_FD_INHERIT_MAX]; POSIXSRV_OPEN_DESCRIPTION* Descriptions[NTL_POSIX_FD_INHERIT_MAX]; }; struct POSIXSRV_OPEN_DESCRIPTION { POSIXSRV_OPEN_DESCRIPTION* Next; uint64_t DescriptionId; uint32_t Type; uint32_t HolderCount; uint32_t InheritanceRefCount; SYS_HANDLE MasterHandle; NTL_POSIX_SHARED_OPEN_DESCRIPTION* Shared; POSIXSRV_PIPE_BACKING* PipeBacking; }; struct POSIXSRV_PROCESS_RECORD { struct POSIXSRV_PROCESS_RECORD* Next; uint32_t PosixPid; uint32_t ParentPosixPid; uint32_t NativeProcessId; uint32_t SecurityId; uint32_t Generation; uint32_t State; uint32_t ConnectionCount; uint32_t MonitorActive; uint32_t UserId; uint32_t EffectiveUserId; uint32_t GroupId; uint32_t EffectiveGroupId; uint32_t ProcessGroupId; uint32_t SessionId; uint32_t SupplementaryGroupCount; uint32_t SupplementaryGroups[NTL_POSIX_SUPPLEMENTARY_GROUP_MAX]; char LoginName[NTL_POSIX_IDENTITY_NAME_MAX + 1u]; char CurrentDirectory[SYS_PATH_MAX + 1u]; int32_t ExitCode; SYS_HANDLE ProcessHandle; POSIXSRV_OPEN_HOLDER* OpenDescriptions; }; typedef struct POSIXSRV_USER_RECORD { const char* Name; uint32_t UserId; uint32_t GroupId; const char* Home; const char* Shell; } POSIXSRV_USER_RECORD; typedef struct POSIXSRV_GROUP_RECORD { const char* Name; uint32_t GroupId; } POSIXSRV_GROUP_RECORD; typedef struct POSIXSRV_CLIENT { SYS_HANDLE Endpoint; SYS_PORT_CONNECTION_INFO Connection; POSIXSRV_PROCESS_RECORD* Process; uint32_t NextTransactionId; uint32_t ActiveTransactions; POSIXSRV_TRANSACTION Transactions[NTL_POSIX_TRANSACTION_CAPACITY]; } POSIXSRV_CLIENT; static SYS_HANDLE gProcessRegistryMutex = SYS_HANDLE_INVALID; static POSIXSRV_PROCESS_RECORD* gProcessRegistry; static POSIXSRV_OPEN_DESCRIPTION* gOpenDescriptionRegistry; static POSIXSRV_FD_INHERITANCE* gFdInheritanceRegistry; static uint32_t gNextPosixPid = POSIXSRV_FIRST_PID; static uint64_t gNextOpenDescriptionId = 1u; static uint64_t gNextFdInheritanceToken = 1u; static uint32_t gRegisteredProcesses; static uint32_t gRegisteredOpenDescriptions; static const POSIXSRV_USER_RECORD gUsers[] = { { "root", 0u, 0u, "/", "/system/shell_posix.exe" }, { "user", 1000u, 1000u, "/", "/system/shell_posix.exe" }, }; static const POSIXSRV_GROUP_RECORD gGroups[] = { { "root", 0u }, { "users", 1000u }, }; // Terminates the server without depending on a compiler runtime return path. static void PosixsrvExit(int code) { for (;;) SysExitProcess(code); } // Gives one server thread a best-effort diagnostic name. static void PosixsrvSetCurrentThreadName(const char* name) { SYS_SET_THREAD_NAME_REQUEST request; memset(&request, 0, sizeof(request)); request.Size = sizeof(request); request.ThreadHandle = SYS_HANDLE_INVALID; request.Name = SysSvFromCstr(name); (void)SysSetThreadName(&request); } // Acquires the process-registry mutex. static KSTATUS PosixsrvLockRegistry(void) { if (gProcessRegistryMutex == SYS_HANDLE_INVALID) return NTLSTATUS_FAILURE; return SysWait(gProcessRegistryMutex, SYS_WAIT_FLAG_NONE); } // Releases the process-registry mutex. static void PosixsrvUnlockRegistry(void) { if (gProcessRegistryMutex != SYS_HANDLE_INVALID) (void)SysReleaseMutex(gProcessRegistryMutex); } // Finds one live or retained record by kernel-stamped native identity. static POSIXSRV_PROCESS_RECORD* PosixsrvFindProcessLocked(uint32_t nativePid, uint32_t securityId) { for (POSIXSRV_PROCESS_RECORD* record = gProcessRegistry; record; record = record->Next) { if (record->NativeProcessId == nativePid && record->SecurityId == securityId) return record; } return (POSIXSRV_PROCESS_RECORD*)0; } // Finds one process by stable POSIX identity while the registry mutex is held. static POSIXSRV_PROCESS_RECORD* PosixsrvFindPosixProcessLocked(uint32_t posixPid) { for (POSIXSRV_PROCESS_RECORD* record = gProcessRegistry; record; record = record->Next) { if (record->PosixPid == posixPid) return record; } return (POSIXSRV_PROCESS_RECORD*)0; } // Returns whether a process group currently exists in one POSIX session. static int PosixsrvProcessGroupExistsLocked(uint32_t sessionId, uint32_t processGroupId) { if (processGroupId == 0) return 0; for (POSIXSRV_PROCESS_RECORD* record = gProcessRegistry; record; record = record->Next) { if (record->State == NTL_POSIX_PROCESS_STATE_RUNNING && record->SessionId == sessionId && record->ProcessGroupId == processGroupId) return 1; } return 0; } // Returns whether one protocol open-description type requires a retained native handle. static int PosixsrvOpenDescriptionNeedsHandle(uint32_t type) { return type == NTL_POSIX_OPEN_TYPE_FILE || type == NTL_POSIX_OPEN_TYPE_SOCKET || type == NTL_POSIX_OPEN_TYPE_PIPE_READ || type == NTL_POSIX_OPEN_TYPE_PIPE_WRITE; } // Returns whether one protocol open-description type is known. static int PosixsrvOpenDescriptionTypeValid(uint32_t type) { return type >= NTL_POSIX_OPEN_TYPE_FILE && type <= NTL_POSIX_OPEN_TYPE_PIPE_WRITE; } // Finds one process holder for a shared open description while the registry lock is held. static POSIXSRV_OPEN_HOLDER* PosixsrvFindOpenHolderLocked(POSIXSRV_PROCESS_RECORD* process, uint64_t descriptionId) { if (!process) return (POSIXSRV_OPEN_HOLDER*)0; for (POSIXSRV_OPEN_HOLDER* holder = process->OpenDescriptions; holder; holder = holder->Next) { if (holder->Description && holder->Description->DescriptionId == descriptionId) return holder; } return (POSIXSRV_OPEN_HOLDER*)0; } // Removes and destroys one globally unheld open description while the registry lock is held. static void PosixsrvDestroyOpenDescriptionLocked(POSIXSRV_OPEN_DESCRIPTION* description) { if (!description || description->HolderCount != 0 || description->InheritanceRefCount != 0) return; POSIXSRV_OPEN_DESCRIPTION** link = &gOpenDescriptionRegistry; while (*link && *link != description) link = &(*link)->Next; if (*link != description) return; *link = description->Next; description->Next = (POSIXSRV_OPEN_DESCRIPTION*)0; if (gRegisteredOpenDescriptions != 0) --gRegisteredOpenDescriptions; if (description->MasterHandle != SYS_HANDLE_INVALID) (void)SysCloseHandle(description->MasterHandle); if (description->PipeBacking) { POSIXSRV_PIPE_BACKING* backing = description->PipeBacking; description->PipeBacking = (POSIXSRV_PIPE_BACKING*)0; if (backing->DescriptionCount != 0) --backing->DescriptionCount; if (backing->DescriptionCount == 0) { if (backing->Shared) (void)SysFreeVm(backing->Shared); free(backing); } } free(description->Shared); free(description); } // Releases one process holder and destroys the description when this was its final holder. static KSTATUS PosixsrvReleaseOpenDescriptionLocked(POSIXSRV_PROCESS_RECORD* process, uint64_t descriptionId) { if (!process || descriptionId == 0) return NTLSTATUS_INVALID_PARAMETER; POSIXSRV_OPEN_HOLDER** link = &process->OpenDescriptions; while (*link && (!(*link)->Description || (*link)->Description->DescriptionId != descriptionId)) link = &(*link)->Next; if (!*link) return NTLSTATUS_NOT_FOUND; POSIXSRV_OPEN_HOLDER* holder = *link; POSIXSRV_OPEN_DESCRIPTION* description = holder->Description; *link = holder->Next; free(holder); if (description && description->HolderCount != 0) --description->HolderCount; PosixsrvDestroyOpenDescriptionLocked(description); return NTLSTATUS_SUCCESS; } // Releases every open-description holder owned by one terminating POSIX process. static void PosixsrvReleaseAllOpenDescriptionsLocked(POSIXSRV_PROCESS_RECORD* process) { if (!process) return; while (process->OpenDescriptions) { POSIXSRV_OPEN_HOLDER* holder = process->OpenDescriptions; POSIXSRV_OPEN_DESCRIPTION* description = holder->Description; process->OpenDescriptions = holder->Next; free(holder); if (description && description->HolderCount != 0) --description->HolderCount; PosixsrvDestroyOpenDescriptionLocked(description); } } // Finds one pending descriptor-inheritance snapshot while the registry lock is held. static POSIXSRV_FD_INHERITANCE* PosixsrvFindFdInheritanceLocked(uint64_t token) { if (token == 0) return (POSIXSRV_FD_INHERITANCE*)0; for (POSIXSRV_FD_INHERITANCE* snapshot = gFdInheritanceRegistry; snapshot; snapshot = snapshot->Next) { if (snapshot->Token == token) return snapshot; } return (POSIXSRV_FD_INHERITANCE*)0; } // Drops one snapshot's temporary description references and removes it from the registry. static void PosixsrvDestroyFdInheritanceLocked(POSIXSRV_FD_INHERITANCE* snapshot) { if (!snapshot) return; POSIXSRV_FD_INHERITANCE** link = &gFdInheritanceRegistry; while (*link && *link != snapshot) link = &(*link)->Next; if (*link != snapshot) return; *link = snapshot->Next; snapshot->Next = (POSIXSRV_FD_INHERITANCE*)0; for (uint32_t i = 0; i < snapshot->DescriptionCount; ++i) { POSIXSRV_OPEN_DESCRIPTION* description = snapshot->Descriptions[i]; if (description && description->InheritanceRefCount != 0) --description->InheritanceRefCount; PosixsrvDestroyOpenDescriptionLocked(description); } free(snapshot); } // Cleans snapshots owned or claimed by one native process generation on genuine exit. static void PosixsrvReleaseFdInheritanceForProcessLocked(POSIXSRV_PROCESS_RECORD* process) { if (!process) return; POSIXSRV_FD_INHERITANCE* snapshot = gFdInheritanceRegistry; while (snapshot) { POSIXSRV_FD_INHERITANCE* next = snapshot->Next; if (snapshot->ClaimProcess == process || (snapshot->SourceProcess == process && !snapshot->ClaimProcess && !snapshot->Armed)) { PosixsrvDestroyFdInheritanceLocked(snapshot); } else if (snapshot->SourceProcess == process) { snapshot->SourceProcess = (POSIXSRV_PROCESS_RECORD*)0; } snapshot = next; } } // Reclaims one armed snapshot if its designated native child dies before import completes. static void PosixsrvFdInheritanceMonitorThread(uintptr_t argument) { POSIXSRV_FD_INHERITANCE_MONITOR* monitor = (POSIXSRV_FD_INHERITANCE_MONITOR*)argument; if (!monitor) { SysExitThread(1); return; } PosixsrvSetCurrentThreadName("posixsrv.fd-inherit"); KSTATUS waitStatus = SysWait(monitor->ProcessHandle, SYS_WAIT_FLAG_NONE); if (KSUCCESS(PosixsrvLockRegistry())) { POSIXSRV_FD_INHERITANCE* snapshot = PosixsrvFindFdInheritanceLocked(monitor->Token); if (snapshot && snapshot->Armed && snapshot->TargetNativeProcessId == monitor->NativeProcessId) PosixsrvDestroyFdInheritanceLocked(snapshot); PosixsrvUnlockRegistry(); } (void)SysCloseHandle(monitor->ProcessHandle); free(monitor); SysExitThread(KSUCCESS(waitStatus) ? 0 : 1); } // Pins one inheritance snapshot to a concrete native child until import or child exit. static KSTATUS PosixsrvArmFdInheritance(POSIXSRV_CLIENT* client, uint64_t token, SYS_HANDLE* targetProcessHandle) { if (!client || !client->Process || token == 0 || !targetProcessHandle || *targetProcessHandle == SYS_HANDLE_INVALID) return NTLSTATUS_INVALID_PARAMETER; uint32_t nativePid = 0; KSTATUS status = SysGetProcessPid(*targetProcessHandle, &nativePid); if (!KSUCCESS(status)) return status; if (nativePid == 0 || nativePid == client->Process->NativeProcessId) return NTLSTATUS_INVALID_PARAMETER; POSIXSRV_FD_INHERITANCE_MONITOR* monitor = (POSIXSRV_FD_INHERITANCE_MONITOR*)calloc(1, sizeof(*monitor)); if (!monitor) return NTLSTATUS_NO_MEMORY; monitor->Token = token; monitor->NativeProcessId = nativePid; monitor->ProcessHandle = *targetProcessHandle; status = PosixsrvLockRegistry(); if (!KSUCCESS(status)) { free(monitor); return status; } POSIXSRV_FD_INHERITANCE* snapshot = PosixsrvFindFdInheritanceLocked(token); if (!snapshot) { PosixsrvUnlockRegistry(); free(monitor); return NTLSTATUS_NOT_FOUND; } if (snapshot->SecurityId != client->Process->SecurityId || snapshot->SourceProcess != client->Process) { PosixsrvUnlockRegistry(); free(monitor); return NTLSTATUS_ACCESS_DENIED; } if (snapshot->ClaimProcess) { status = snapshot->ClaimProcess->NativeProcessId == nativePid ? NTLSTATUS_SUCCESS : NTLSTATUS_ACCESS_DENIED; PosixsrvUnlockRegistry(); free(monitor); return status; } if (snapshot->Armed) { status = snapshot->TargetNativeProcessId == nativePid ? NTLSTATUS_SUCCESS : NTLSTATUS_ACCESS_DENIED; PosixsrvUnlockRegistry(); free(monitor); return status; } snapshot->Armed = 1u; snapshot->TargetNativeProcessId = nativePid; SYS_CREATE_THREAD_REQUEST create; memset(&create, 0, sizeof(create)); create.Size = sizeof(create); create.Entry = (uintptr_t)PosixsrvFdInheritanceMonitorThread; create.Argument = (uintptr_t)monitor; create.Priority = 1; create.Flags = SYS_CREATE_THREAD_FLAG_NONE; status = SysCreateThread(&create); if (!KSUCCESS(status)) { snapshot->Armed = 0; snapshot->TargetNativeProcessId = 0; PosixsrvUnlockRegistry(); free(monitor); return status; } *targetProcessHandle = SYS_HANDLE_INVALID; PosixsrvUnlockRegistry(); return NTLSTATUS_SUCCESS; } // Returns the process-local rights needed by one imported native capability. static SYS_RIGHTS PosixsrvOpenDescriptionClientRights(POSIXSRV_OPEN_DESCRIPTION* description) { if (!description || !description->Shared) return 0; uint32_t statusFlags = (uint32_t)_InterlockedCompareExchange( &description->Shared->StatusFlags, 0, 0); SYS_RIGHTS rights = SYS_RIGHT_QUERY; if (description->Type == NTL_POSIX_OPEN_TYPE_FILE) { rights |= SYS_FILE_RIGHT_LOCK; uint32_t access = statusFlags & NTL_POSIX_OPEN_STATUS_ACCMODE; if (access == NTL_POSIX_OPEN_STATUS_RDONLY || access == NTL_POSIX_OPEN_STATUS_RDWR) rights |= SYS_FILE_RIGHT_READ_DATA | SYS_FILE_RIGHT_MAP_READ; if (access == NTL_POSIX_OPEN_STATUS_WRONLY || access == NTL_POSIX_OPEN_STATUS_RDWR) rights |= SYS_FILE_RIGHT_WRITE_DATA | SYS_FILE_RIGHT_MAP_WRITE; } else if (description->Type == NTL_POSIX_OPEN_TYPE_SOCKET) { rights |= SYS_SOCKET_RIGHT_BIND | SYS_SOCKET_RIGHT_CONNECT | SYS_SOCKET_RIGHT_LISTEN | SYS_SOCKET_RIGHT_ACCEPT | SYS_SOCKET_RIGHT_SEND | SYS_SOCKET_RIGHT_RECEIVE | SYS_SOCKET_RIGHT_SHUTDOWN | SYS_SOCKET_RIGHT_POLL | SYS_SOCKET_RIGHT_SET_OPTION; } else if (description->Type == NTL_POSIX_OPEN_TYPE_PIPE_READ) { rights |= SYS_RIGHT_WAIT | SYS_PIPE_RIGHT_READ | SYS_PIPE_RIGHT_POLL; } else if (description->Type == NTL_POSIX_OPEN_TYPE_PIPE_WRITE) { rights |= SYS_RIGHT_WAIT | SYS_PIPE_RIGHT_WRITE | SYS_PIPE_RIGHT_POLL; } return rights; } // Creates a one-shot server snapshot of the caller's process-local FD table manifest. static KSTATUS PosixsrvCreateFdInheritance(POSIXSRV_CLIENT* client, const NTL_POSIX_REQUEST* request, uint64_t* tokenOut) { if (!client || !client->Process || !request || !tokenOut) return NTLSTATUS_INVALID_PARAMETER; *tokenOut = 0; if (request->FdInheritanceFlags != NTL_POSIX_FD_INHERIT_FLAG_NONE || request->FdInheritanceIndex != 0 || request->FdInheritanceToken != 0 || request->FdInheritanceCount > NTL_POSIX_FD_INHERIT_MAX) return NTLSTATUS_INVALID_PARAMETER; POSIXSRV_FD_INHERITANCE* snapshot = (POSIXSRV_FD_INHERITANCE*)calloc(1, sizeof(*snapshot)); if (!snapshot) return NTLSTATUS_NO_MEMORY; KSTATUS status = PosixsrvLockRegistry(); if (!KSUCCESS(status)) { free(snapshot); return status; } if (client->Process->State != NTL_POSIX_PROCESS_STATE_RUNNING) { PosixsrvUnlockRegistry(); free(snapshot); return NTLSTATUS_OBJECT_DEAD; } if (gNextFdInheritanceToken == 0) { PosixsrvUnlockRegistry(); free(snapshot); return NTLSTATUS_ID_EXHAUSTED; } snapshot->Token = gNextFdInheritanceToken++; snapshot->SourceProcess = client->Process; snapshot->SecurityId = client->Process->SecurityId; snapshot->EntryCount = request->FdInheritanceCount; for (uint32_t i = 0; i < request->FdInheritanceCount; ++i) { const NTL_POSIX_FD_MANIFEST_ENTRY* manifest = &request->FdManifest[i]; if (manifest->Descriptor < 0 || manifest->Descriptor >= (int32_t)NTL_POSIX_FD_INHERIT_MAX || (manifest->DescriptorFlags & ~NTL_POSIX_FD_DESCRIPTOR_CLOEXEC) != 0 || manifest->OpenDescriptionId == 0) { status = NTLSTATUS_INVALID_PARAMETER; break; } for (uint32_t j = 0; j < i; ++j) { if (snapshot->Entries[j].Manifest.Descriptor == manifest->Descriptor) { status = NTLSTATUS_INVALID_PARAMETER; break; } } if (!KSUCCESS(status)) break; POSIXSRV_OPEN_HOLDER* holder = PosixsrvFindOpenHolderLocked(client->Process, manifest->OpenDescriptionId); if (!holder || !holder->Description) { status = NTLSTATUS_NOT_FOUND; break; } snapshot->Entries[i].Manifest = *manifest; snapshot->Entries[i].Description = holder->Description; uint32_t found = 0; for (uint32_t j = 0; j < snapshot->DescriptionCount; ++j) { if (snapshot->Descriptions[j] == holder->Description) { found = 1; break; } } if (!found) snapshot->Descriptions[snapshot->DescriptionCount++] = holder->Description; } for (uint32_t i = request->FdInheritanceCount; i < NTL_POSIX_FD_INHERIT_MAX; ++i) { if (request->FdManifest[i].Descriptor != 0 || request->FdManifest[i].DescriptorFlags != 0 || request->FdManifest[i].OpenDescriptionId != 0) { status = NTLSTATUS_INVALID_PARAMETER; break; } } if (!KSUCCESS(status)) { PosixsrvUnlockRegistry(); free(snapshot); return status; } for (uint32_t i = 0; i < snapshot->DescriptionCount; ++i) ++snapshot->Descriptions[i]->InheritanceRefCount; snapshot->Next = gFdInheritanceRegistry; gFdInheritanceRegistry = snapshot; *tokenOut = snapshot->Token; PosixsrvUnlockRegistry(); return NTLSTATUS_SUCCESS; } // Cancels one unclaimed snapshot owned by the caller. static KSTATUS PosixsrvCancelFdInheritance(POSIXSRV_CLIENT* client, uint64_t token) { if (!client || !client->Process || token == 0) return NTLSTATUS_INVALID_PARAMETER; KSTATUS status = PosixsrvLockRegistry(); if (!KSUCCESS(status)) return status; POSIXSRV_FD_INHERITANCE* snapshot = PosixsrvFindFdInheritanceLocked(token); if (!snapshot) status = NTLSTATUS_NOT_FOUND; else if (snapshot->SourceProcess != client->Process || snapshot->ClaimProcess) status = NTLSTATUS_ACCESS_DENIED; else { PosixsrvDestroyFdInheritanceLocked(snapshot); status = NTLSTATUS_SUCCESS; } PosixsrvUnlockRegistry(); return status; } // Adds one process holder for every unique description before the child imports wrappers. static KSTATUS PosixsrvClaimFdInheritanceLocked(POSIXSRV_FD_INHERITANCE* snapshot, POSIXSRV_PROCESS_RECORD* process) { if (!snapshot || !process) return NTLSTATUS_INVALID_PARAMETER; if (snapshot->Armed && snapshot->TargetNativeProcessId != process->NativeProcessId) return NTLSTATUS_ACCESS_DENIED; if (snapshot->ClaimProcess) return snapshot->ClaimProcess == process ? NTLSTATUS_SUCCESS : NTLSTATUS_ACCESS_DENIED; if (process->OpenDescriptions) return NTLSTATUS_ACCESS_DENIED; POSIXSRV_OPEN_DESCRIPTION* added[NTL_POSIX_FD_INHERIT_MAX]; uint32_t addedCount = 0; for (uint32_t i = 0; i < snapshot->DescriptionCount; ++i) { POSIXSRV_OPEN_DESCRIPTION* description = snapshot->Descriptions[i]; if (PosixsrvFindOpenHolderLocked(process, description->DescriptionId)) continue; POSIXSRV_OPEN_HOLDER* holder = (POSIXSRV_OPEN_HOLDER*)calloc(1, sizeof(*holder)); if (!holder) { for (uint32_t j = 0; j < addedCount; ++j) (void)PosixsrvReleaseOpenDescriptionLocked(process, added[j]->DescriptionId); return NTLSTATUS_NO_MEMORY; } holder->Description = description; holder->Next = process->OpenDescriptions; process->OpenDescriptions = holder; ++description->HolderCount; added[addedCount++] = description; } snapshot->ClaimProcess = process; return NTLSTATUS_SUCCESS; } // Releases one holder owned by the calling POSIX process. static KSTATUS PosixsrvReleaseOpenDescription(POSIXSRV_CLIENT* client, uint64_t descriptionId) { if (!client || !client->Process || descriptionId == 0) return NTLSTATUS_INVALID_PARAMETER; KSTATUS status = PosixsrvLockRegistry(); if (!KSUCCESS(status)) return status; if (client->Process->State != NTL_POSIX_PROCESS_STATE_RUNNING) status = NTLSTATUS_OBJECT_DEAD; else status = PosixsrvReleaseOpenDescriptionLocked(client->Process, descriptionId); PosixsrvUnlockRegistry(); return status; } // Creates one server-owned shared open description and one holder for the calling process. static KSTATUS PosixsrvCreateOpenDescription(POSIXSRV_CLIENT* client, const NTL_POSIX_REQUEST* request, SYS_HANDLE* handles, uint32_t handleCount, uint64_t* descriptionIdOut, NTL_POSIX_SHARED_OPEN_DESCRIPTION** sharedOut) { if (!client || !client->Process || !request || !descriptionIdOut || !sharedOut) return NTLSTATUS_INVALID_PARAMETER; *descriptionIdOut = 0; *sharedOut = (NTL_POSIX_SHARED_OPEN_DESCRIPTION*)0; uint32_t type = request->OpenDescriptionType; uint32_t statusFlags = request->OpenStatusFlags; if (!PosixsrvOpenDescriptionTypeValid(type) || (statusFlags & ~NTL_POSIX_OPEN_STATUS_VALID_MASK) != 0 || (statusFlags & NTL_POSIX_OPEN_STATUS_ACCMODE) == NTL_POSIX_OPEN_STATUS_ACCMODE) return NTLSTATUS_INVALID_PARAMETER; uint32_t expectedHandles = PosixsrvOpenDescriptionNeedsHandle(type) ? 1u : 0u; if (handleCount != expectedHandles || (expectedHandles && !handles)) return NTLSTATUS_INVALID_PARAMETER; POSIXSRV_OPEN_DESCRIPTION* description = (POSIXSRV_OPEN_DESCRIPTION*)calloc(1, sizeof(*description)); POSIXSRV_OPEN_HOLDER* holder = (POSIXSRV_OPEN_HOLDER*)calloc(1, sizeof(*holder)); NTL_POSIX_SHARED_OPEN_DESCRIPTION* shared = (NTL_POSIX_SHARED_OPEN_DESCRIPTION*)calloc(1, sizeof(*shared)); if (!description || !holder || !shared) { free(description); free(holder); free(shared); return NTLSTATUS_NO_MEMORY; } KSTATUS status = PosixsrvLockRegistry(); if (!KSUCCESS(status)) { free(description); free(holder); free(shared); return status; } if (client->Process->State != NTL_POSIX_PROCESS_STATE_RUNNING) { PosixsrvUnlockRegistry(); free(description); free(holder); free(shared); return NTLSTATUS_OBJECT_DEAD; } if (gNextOpenDescriptionId == 0) { PosixsrvUnlockRegistry(); free(description); free(holder); free(shared); return NTLSTATUS_ID_EXHAUSTED; } uint64_t id = gNextOpenDescriptionId++; description->DescriptionId = id; description->Type = type; description->HolderCount = 1u; description->MasterHandle = expectedHandles ? handles[0] : SYS_HANDLE_INVALID; description->Shared = shared; shared->Magic = NTL_POSIX_SHARED_OPEN_MAGIC; shared->Version = NTL_POSIX_SHARED_OPEN_VERSION; shared->Type = type; shared->DescriptionId = id; shared->StatusFlags = (long)statusFlags; holder->Description = description; holder->Next = client->Process->OpenDescriptions; client->Process->OpenDescriptions = holder; description->Next = gOpenDescriptionRegistry; gOpenDescriptionRegistry = description; ++gRegisteredOpenDescriptions; if (expectedHandles) handles[0] = SYS_HANDLE_INVALID; *descriptionIdOut = id; *sharedOut = shared; PosixsrvUnlockRegistry(); return NTLSTATUS_SUCCESS; } // Creates one server-owned pipe backing plus read/write shared open descriptions. static KSTATUS PosixsrvCreatePipe(POSIXSRV_CLIENT* client, uint64_t* readIdOut, uint64_t* writeIdOut) { if (!client || !client->Process || !readIdOut || !writeIdOut) return NTLSTATUS_INVALID_PARAMETER; *readIdOut = 0; *writeIdOut = 0; SYS_HANDLE readHandle = SYS_HANDLE_INVALID; SYS_HANDLE writeHandle = SYS_HANDLE_INVALID; SYS_PIPE_SHARED_STATE* pipeShared = (SYS_PIPE_SHARED_STATE*)0; SYS_CREATE_PIPE_REQUEST pipeRequest; memset(&pipeRequest, 0, sizeof(pipeRequest)); pipeRequest.Size = sizeof(pipeRequest); pipeRequest.ReadHandleOut = &readHandle; pipeRequest.WriteHandleOut = &writeHandle; pipeRequest.SharedStateOut = &pipeShared; KSTATUS status = SysCreatePipe(&pipeRequest); if (!KSUCCESS(status)) return status; if (!pipeShared || pipeShared->Magic != SYS_PIPE_SHARED_MAGIC || pipeShared->Version != SYS_PIPE_SHARED_VERSION || pipeShared->Capacity != SYS_PIPE_BUFFER_CAPACITY || pipeShared->HeaderBytes != SYS_PIPE_SHARED_HEADER_BYTES) { (void)SysCloseHandle(readHandle); (void)SysCloseHandle(writeHandle); if (pipeShared) (void)SysFreeVm(pipeShared); return NTLSTATUS_FAILURE; } POSIXSRV_PIPE_BACKING* backing = (POSIXSRV_PIPE_BACKING*)calloc(1, sizeof(*backing)); POSIXSRV_OPEN_DESCRIPTION* readDescription = (POSIXSRV_OPEN_DESCRIPTION*)calloc(1, sizeof(*readDescription)); POSIXSRV_OPEN_DESCRIPTION* writeDescription = (POSIXSRV_OPEN_DESCRIPTION*)calloc(1, sizeof(*writeDescription)); POSIXSRV_OPEN_HOLDER* readHolder = (POSIXSRV_OPEN_HOLDER*)calloc(1, sizeof(*readHolder)); POSIXSRV_OPEN_HOLDER* writeHolder = (POSIXSRV_OPEN_HOLDER*)calloc(1, sizeof(*writeHolder)); NTL_POSIX_SHARED_OPEN_DESCRIPTION* readShared = (NTL_POSIX_SHARED_OPEN_DESCRIPTION*)calloc(1, sizeof(*readShared)); NTL_POSIX_SHARED_OPEN_DESCRIPTION* writeShared = (NTL_POSIX_SHARED_OPEN_DESCRIPTION*)calloc(1, sizeof(*writeShared)); if (!backing || !readDescription || !writeDescription || !readHolder || !writeHolder || !readShared || !writeShared) { free(backing); free(readDescription); free(writeDescription); free(readHolder); free(writeHolder); free(readShared); free(writeShared); (void)SysCloseHandle(readHandle); (void)SysCloseHandle(writeHandle); (void)SysFreeVm(pipeShared); return NTLSTATUS_NO_MEMORY; } status = PosixsrvLockRegistry(); if (!KSUCCESS(status)) { free(backing); free(readDescription); free(writeDescription); free(readHolder); free(writeHolder); free(readShared); free(writeShared); (void)SysCloseHandle(readHandle); (void)SysCloseHandle(writeHandle); (void)SysFreeVm(pipeShared); return status; } if (client->Process->State != NTL_POSIX_PROCESS_STATE_RUNNING) { PosixsrvUnlockRegistry(); free(backing); free(readDescription); free(writeDescription); free(readHolder); free(writeHolder); free(readShared); free(writeShared); (void)SysCloseHandle(readHandle); (void)SysCloseHandle(writeHandle); (void)SysFreeVm(pipeShared); return NTLSTATUS_OBJECT_DEAD; } if (gNextOpenDescriptionId == 0 || gNextOpenDescriptionId == UINT64_MAX) { PosixsrvUnlockRegistry(); free(backing); free(readDescription); free(writeDescription); free(readHolder); free(writeHolder); free(readShared); free(writeShared); (void)SysCloseHandle(readHandle); (void)SysCloseHandle(writeHandle); (void)SysFreeVm(pipeShared); return NTLSTATUS_ID_EXHAUSTED; } uint64_t readId = gNextOpenDescriptionId++; uint64_t writeId = gNextOpenDescriptionId++; backing->Shared = pipeShared; backing->DescriptionCount = 2u; readDescription->DescriptionId = readId; readDescription->Type = NTL_POSIX_OPEN_TYPE_PIPE_READ; readDescription->HolderCount = 1u; readDescription->MasterHandle = readHandle; readDescription->Shared = readShared; readDescription->PipeBacking = backing; readShared->Magic = NTL_POSIX_SHARED_OPEN_MAGIC; readShared->Version = NTL_POSIX_SHARED_OPEN_VERSION; readShared->Type = NTL_POSIX_OPEN_TYPE_PIPE_READ; readShared->DescriptionId = readId; readShared->StatusFlags = NTL_POSIX_OPEN_STATUS_RDONLY; readShared->SharedObjectData = (uint64_t)(uintptr_t)pipeShared; writeDescription->DescriptionId = writeId; writeDescription->Type = NTL_POSIX_OPEN_TYPE_PIPE_WRITE; writeDescription->HolderCount = 1u; writeDescription->MasterHandle = writeHandle; writeDescription->Shared = writeShared; writeDescription->PipeBacking = backing; writeShared->Magic = NTL_POSIX_SHARED_OPEN_MAGIC; writeShared->Version = NTL_POSIX_SHARED_OPEN_VERSION; writeShared->Type = NTL_POSIX_OPEN_TYPE_PIPE_WRITE; writeShared->DescriptionId = writeId; writeShared->StatusFlags = NTL_POSIX_OPEN_STATUS_WRONLY; writeShared->SharedObjectData = (uint64_t)(uintptr_t)pipeShared; readHolder->Description = readDescription; writeHolder->Description = writeDescription; writeHolder->Next = client->Process->OpenDescriptions; readHolder->Next = writeHolder; client->Process->OpenDescriptions = readHolder; writeDescription->Next = gOpenDescriptionRegistry; readDescription->Next = writeDescription; gOpenDescriptionRegistry = readDescription; gRegisteredOpenDescriptions += 2u; *readIdOut = readId; *writeIdOut = writeId; PosixsrvUnlockRegistry(); return NTLSTATUS_SUCCESS; } // Applies F_SETFL mutable state through the master native capability and publishes the result. static KSTATUS PosixsrvSetOpenStatus(POSIXSRV_CLIENT* client, uint64_t descriptionId, uint32_t requestedFlags, uint32_t* statusFlagsOut, uint32_t* typeOut) { if (!client || !client->Process || descriptionId == 0 || !statusFlagsOut || !typeOut) return NTLSTATUS_INVALID_PARAMETER; KSTATUS status = PosixsrvLockRegistry(); if (!KSUCCESS(status)) return status; POSIXSRV_OPEN_HOLDER* holder = PosixsrvFindOpenHolderLocked(client->Process, descriptionId); if (!holder || !holder->Description || !holder->Description->Shared) { PosixsrvUnlockRegistry(); return NTLSTATUS_NOT_FOUND; } POSIXSRV_OPEN_DESCRIPTION* description = holder->Description; uint32_t current = (uint32_t)_InterlockedCompareExchange( &description->Shared->StatusFlags, 0, 0); uint32_t updated = (current & ~(NTL_POSIX_OPEN_STATUS_APPEND | NTL_POSIX_OPEN_STATUS_NONBLOCK)) | (requestedFlags & (NTL_POSIX_OPEN_STATUS_APPEND | NTL_POSIX_OPEN_STATUS_NONBLOCK)); status = NTLSTATUS_SUCCESS; if (description->Type == NTL_POSIX_OPEN_TYPE_FILE) { SYS_SET_FILE_STATUS_REQUEST fileRequest; memset(&fileRequest, 0, sizeof(fileRequest)); fileRequest.Size = sizeof(fileRequest); fileRequest.FileHandle = description->MasterHandle; fileRequest.Mask = SYS_FILE_STATUS_APPEND; fileRequest.Flags = (updated & NTL_POSIX_OPEN_STATUS_APPEND) ? SYS_FILE_STATUS_APPEND : 0; status = SysSetFileStatus(&fileRequest); } else if (description->Type == NTL_POSIX_OPEN_TYPE_SOCKET) { uint32_t nonblocking = (updated & NTL_POSIX_OPEN_STATUS_NONBLOCK) ? 1u : 0u; SYS_SOCKET_OPTION_REQUEST socketRequest; memset(&socketRequest, 0, sizeof(socketRequest)); socketRequest.Size = sizeof(socketRequest); socketRequest.Option = SYS_SOCKET_OPT_NONBLOCKING; socketRequest.Value = &nonblocking; socketRequest.ValueSize = sizeof(nonblocking); status = SysSetSocketOption(description->MasterHandle, &socketRequest); } if (KSUCCESS(status)) _InterlockedExchange(&description->Shared->StatusFlags, (long)updated); *statusFlagsOut = KSUCCESS(status) ? updated : current; *typeOut = description->Type; PosixsrvUnlockRegistry(); return status; } // Finds one synthesized passwd record by uid or exact name. static const POSIXSRV_USER_RECORD* PosixsrvFindUser(uint32_t lookupKind, uint32_t userId, const char* name) { for (uint32_t i = 0; i < (uint32_t)(sizeof(gUsers) / sizeof(gUsers[0])); ++i) { if ((lookupKind == NTL_POSIX_LOOKUP_BY_ID && gUsers[i].UserId == userId) || (lookupKind == NTL_POSIX_LOOKUP_BY_NAME && name && strcmp(gUsers[i].Name, name) == 0)) return &gUsers[i]; } return (const POSIXSRV_USER_RECORD*)0; } // Finds one synthesized group record by gid or exact name. static const POSIXSRV_GROUP_RECORD* PosixsrvFindGroup(uint32_t lookupKind, uint32_t groupId, const char* name) { for (uint32_t i = 0; i < (uint32_t)(sizeof(gGroups) / sizeof(gGroups[0])); ++i) { if ((lookupKind == NTL_POSIX_LOOKUP_BY_ID && gGroups[i].GroupId == groupId) || (lookupKind == NTL_POSIX_LOOKUP_BY_NAME && name && strcmp(gGroups[i].Name, name) == 0)) return &gGroups[i]; } return (const POSIXSRV_GROUP_RECORD*)0; } // Validates one length-delimited canonical native current-directory string. static int PosixsrvValidateCurrentDirectory(const NTL_POSIX_REQUEST* request) { if (!request || request->PathLength == 0 || request->PathLength > SYS_PATH_MAX) return 0; if (request->Path[0] != '/' || request->Path[request->PathLength] != '\0') return 0; return strlen(request->Path) == request->PathLength; } // Validates one optional length-delimited identity lookup name. static int PosixsrvValidateLookupName(const NTL_POSIX_REQUEST* request) { if (!request || request->NameLength == 0 || request->NameLength > NTL_POSIX_IDENTITY_NAME_MAX) return 0; if (request->Name[request->NameLength] != '\0') return 0; return strlen(request->Name) == request->NameLength; } // Removes one process record from the registry while the registry mutex is held. static void PosixsrvUnlinkProcessLocked(POSIXSRV_PROCESS_RECORD* record) { if (!record) return; POSIXSRV_PROCESS_RECORD** link = &gProcessRegistry; while (*link && *link != record) link = &(*link)->Next; if (*link == record) { *link = record->Next; record->Next = (POSIXSRV_PROCESS_RECORD*)0; if (gRegisteredProcesses != 0) --gRegisteredProcesses; } } // Releases one detached process record and its retained native capability. static void PosixsrvFreeProcessRecord(POSIXSRV_PROCESS_RECORD* record) { if (!record) return; if (record->ProcessHandle != SYS_HANDLE_INVALID) (void)SysCloseHandle(record->ProcessHandle); free(record); } // Allocates one stable positive POSIX PID from the server-owned namespace. static KSTATUS PosixsrvAllocatePidLocked(uint32_t* pidOut) { if (!pidOut) return NTLSTATUS_INVALID_PARAMETER; *pidOut = 0; if (gNextPosixPid < POSIXSRV_FIRST_PID || gNextPosixPid > POSIXSRV_LAST_PID) return NTLSTATUS_ID_EXHAUSTED; *pidOut = gNextPosixPid++; return NTLSTATUS_SUCCESS; } // Verifies that the service runs without ambient privilege or service-registration claims. static KSTATUS PosixsrvValidateSecurity(void) { SYS_SECURITY_CONTEXT_INFO security; memset(&security, 0, sizeof(security)); security.Size = sizeof(security); KSTATUS status = SysQuerySecurityContext(SYS_SECURITY_CONTEXT_CURRENT, &security); if (!KSUCCESS(status)) return status; if (security.EffectivePrivileges != 0 || security.DelegablePrivileges != 0 || security.ServiceClaims != 0 || security.DelegableServiceClaims != 0) return NTLSTATUS_ACCESS_DENIED; return NTLSTATUS_SUCCESS; } // Accepts init's private service-control connection. static KSTATUS PosixsrvAcceptControl(SYS_HANDLE listener, SYS_HANDLE* endpointOut) { if (listener == SYS_HANDLE_INVALID || !endpointOut) return NTLSTATUS_INVALID_PARAMETER; SYS_ACCEPT_PORT_REQUEST accept; memset(&accept, 0, sizeof(accept)); accept.Size = sizeof(accept); accept.ListenerHandle = listener; accept.Flags = SYS_PORT_ACCEPT_FLAG_NONE; accept.TimeoutMilliseconds = SYS_PORT_TIMEOUT_INFINITE; accept.EndpointHandleOut = endpointOut; return SysAcceptPort(&accept); } // Creates the public client listener exported through the generic service READY contract. static KSTATUS PosixsrvCreateListener(SYS_HANDLE* listenerOut) { if (!listenerOut) return NTLSTATUS_INVALID_PARAMETER; *listenerOut = SYS_HANDLE_INVALID; SYS_CREATE_PORT_REQUEST create; memset(&create, 0, sizeof(create)); create.Size = sizeof(create); create.Flags = SYS_PORT_FLAG_NONE; create.Backlog = SYS_PORT_DEFAULT_BACKLOG; create.HandleOut = listenerOut; return SysCreatePort(&create); } // Copies one bounded NUL-terminated string into a protocol field and returns its byte length. static uint32_t PosixsrvCopyText(char* destination, uint32_t capacity, const char* source) { if (!destination || capacity == 0) return 0; if (!source) source = ""; size_t length = strlen(source); if (length >= capacity) length = capacity - 1u; if (length) memcpy(destination, source, length); destination[length] = '\0'; return (uint32_t)length; } // Copies the current process identity and shared attributes into one reply. static void PosixsrvSnapshotReplyIdentity(POSIXSRV_CLIENT* client, NTL_POSIX_REPLY* reply) { if (!client || !reply || !KSUCCESS(PosixsrvLockRegistry())) return; if (client->Process) { POSIXSRV_PROCESS_RECORD* record = client->Process; reply->PosixPid = record->PosixPid; reply->NativeGeneration = record->Generation; reply->ProcessState = record->State; reply->ParentPosixPid = record->ParentPosixPid; reply->UserId = record->UserId; reply->EffectiveUserId = record->EffectiveUserId; reply->GroupId = record->GroupId; reply->EffectiveGroupId = record->EffectiveGroupId; reply->ProcessGroupId = record->ProcessGroupId; reply->SessionId = record->SessionId; reply->SupplementaryGroupCount = record->SupplementaryGroupCount; if (reply->SupplementaryGroupCount > NTL_POSIX_SUPPLEMENTARY_GROUP_MAX) reply->SupplementaryGroupCount = NTL_POSIX_SUPPLEMENTARY_GROUP_MAX; for (uint32_t i = 0; i < reply->SupplementaryGroupCount; ++i) reply->SupplementaryGroups[i] = record->SupplementaryGroups[i]; reply->NameLength = PosixsrvCopyText(reply->Name, sizeof(reply->Name), record->LoginName); reply->CurrentDirectoryLength = PosixsrvCopyText(reply->CurrentDirectory, sizeof(reply->CurrentDirectory), record->CurrentDirectory); } reply->RegisteredProcesses = gRegisteredProcesses; reply->RegisteredOpenDescriptions = gRegisteredOpenDescriptions; PosixsrvUnlockRegistry(); } // Initializes the common fields of one protocol reply. static void PosixsrvInitializeReply(POSIXSRV_CLIENT* client, NTL_POSIX_REPLY* reply, uint32_t operation, KSTATUS status, uint32_t transactionId) { memset(reply, 0, sizeof(*reply)); reply->Size = sizeof(*reply); reply->Version = NTL_POSIX_PROTOCOL_VERSION; reply->Operation = operation; reply->Flags = NTL_POSIX_REQUEST_FLAG_NONE; reply->Status = status; reply->TransactionId = transactionId; reply->ClientProcessId = client->Connection.ClientProcessId; reply->ClientSecurityId = client->Connection.ClientSecurityId; reply->ActiveTransactions = client->ActiveTransactions; reply->TransactionCapacity = NTL_POSIX_TRANSACTION_CAPACITY; PosixsrvSnapshotReplyIdentity(client, reply); } // Sends one already-prepared fixed-size protocol reply with no capability transfer. static KSTATUS PosixsrvSendReply(POSIXSRV_CLIENT* client, uint32_t messageId, const NTL_POSIX_REPLY* reply) { if (!client || !reply) return NTLSTATUS_INVALID_PARAMETER; SYS_REPLY_PORT_REQUEST out; memset(&out, 0, sizeof(out)); out.Size = sizeof(out); out.EndpointHandle = client->Endpoint; out.MessageId = messageId; out.Flags = SYS_PORT_FLAG_NONE; out.Payload = reply; out.PayloadLength = sizeof(*reply); return SysReplyPort(&out); } // Sends one prepared reply with a bounded set of transferred capabilities. static KSTATUS PosixsrvSendReplyWithHandles(POSIXSRV_CLIENT* client, uint32_t messageId, const NTL_POSIX_REPLY* reply, const SYS_PORT_HANDLE_TRANSFER* handles, uint32_t handleCount) { if (!client || !reply || handleCount > SYS_PORT_MAX_TRANSFER_HANDLES || (handleCount != 0 && !handles)) return NTLSTATUS_INVALID_PARAMETER; SYS_REPLY_PORT_REQUEST out; memset(&out, 0, sizeof(out)); out.Size = sizeof(out); out.EndpointHandle = client->Endpoint; out.MessageId = messageId; out.Flags = SYS_PORT_FLAG_NONE; out.Payload = reply; out.PayloadLength = sizeof(*reply); out.Handles = handles; out.HandleCount = handleCount; return SysReplyPort(&out); } // Sends one ordinary process/transaction reply. static KSTATUS PosixsrvReply(POSIXSRV_CLIENT* client, uint32_t messageId, uint32_t operation, KSTATUS status, uint32_t transactionId) { if (!client) return NTLSTATUS_INVALID_PARAMETER; NTL_POSIX_REPLY reply; PosixsrvInitializeReply(client, &reply, operation, status, transactionId); return PosixsrvSendReply(client, messageId, &reply); } // Sends one open-description result while preserving current-process metadata. static KSTATUS PosixsrvReplyOpenDescription(POSIXSRV_CLIENT* client, uint32_t messageId, uint32_t operation, KSTATUS status, uint64_t descriptionId, uint32_t type, uint32_t statusFlags, NTL_POSIX_SHARED_OPEN_DESCRIPTION* shared) { NTL_POSIX_REPLY reply; PosixsrvInitializeReply(client, &reply, operation, status, 0); if (KSUCCESS(status)) { reply.OpenDescriptionId = descriptionId; reply.OpenDescriptionType = type; reply.OpenStatusFlags = statusFlags; reply.SharedOpenDescription = (uint64_t)(uintptr_t)shared; } return PosixsrvSendReply(client, messageId, &reply); } // Sends one server-created pipe result with endpoint capabilities in read/write order. static KSTATUS PosixsrvReplyPipe(POSIXSRV_CLIENT* client, uint32_t messageId, KSTATUS status, uint64_t readId, uint64_t writeId) { NTL_POSIX_REPLY reply; PosixsrvInitializeReply(client, &reply, NTL_POSIX_OP_CREATE_PIPE, status, 0); if (!KSUCCESS(status)) return PosixsrvSendReply(client, messageId, &reply); status = PosixsrvLockRegistry(); if (!KSUCCESS(status)) return status; POSIXSRV_OPEN_HOLDER* readHolder = PosixsrvFindOpenHolderLocked(client->Process, readId); POSIXSRV_OPEN_HOLDER* writeHolder = PosixsrvFindOpenHolderLocked(client->Process, writeId); POSIXSRV_OPEN_DESCRIPTION* readDescription = readHolder ? readHolder->Description : (POSIXSRV_OPEN_DESCRIPTION*)0; POSIXSRV_OPEN_DESCRIPTION* writeDescription = writeHolder ? writeHolder->Description : (POSIXSRV_OPEN_DESCRIPTION*)0; if (!readDescription || !writeDescription || !readDescription->Shared || !writeDescription->Shared || readDescription->Type != NTL_POSIX_OPEN_TYPE_PIPE_READ || writeDescription->Type != NTL_POSIX_OPEN_TYPE_PIPE_WRITE || readDescription->MasterHandle == SYS_HANDLE_INVALID || writeDescription->MasterHandle == SYS_HANDLE_INVALID) { PosixsrvUnlockRegistry(); return PosixsrvReply(client, messageId, NTL_POSIX_OP_CREATE_PIPE, NTLSTATUS_OBJECT_DEAD, 0); } reply.OpenDescriptionId = readDescription->DescriptionId; reply.OpenDescriptionType = readDescription->Type; reply.OpenStatusFlags = (uint32_t)_InterlockedCompareExchange( &readDescription->Shared->StatusFlags, 0, 0); reply.SharedOpenDescription = (uint64_t)(uintptr_t)readDescription->Shared; reply.OpenDescriptionId2 = writeDescription->DescriptionId; reply.OpenDescriptionType2 = writeDescription->Type; reply.OpenStatusFlags2 = (uint32_t)_InterlockedCompareExchange( &writeDescription->Shared->StatusFlags, 0, 0); reply.SharedOpenDescription2 = (uint64_t)(uintptr_t)writeDescription->Shared; SYS_PORT_HANDLE_TRANSFER transfers[2]; memset(transfers, 0, sizeof(transfers)); transfers[0].Handle = readDescription->MasterHandle; transfers[0].DesiredRights = SYS_RIGHT_QUERY | SYS_RIGHT_WAIT | SYS_PIPE_RIGHT_READ | SYS_PIPE_RIGHT_POLL; transfers[0].Flags = SYS_PORT_TRANSFER_FLAG_NONE; transfers[1].Handle = writeDescription->MasterHandle; transfers[1].DesiredRights = SYS_RIGHT_QUERY | SYS_RIGHT_WAIT | SYS_PIPE_RIGHT_WRITE | SYS_PIPE_RIGHT_POLL; transfers[1].Flags = SYS_PORT_TRANSFER_FLAG_NONE; KSTATUS replyStatus = PosixsrvSendReplyWithHandles(client, messageId, &reply, transfers, 2u); PosixsrvUnlockRegistry(); return replyStatus; } // Sends one bounded inherited-description batch and its process-local native aliases. static KSTATUS PosixsrvReplyFdInheritance(POSIXSRV_CLIENT* client, uint32_t messageId, uint64_t token, uint32_t descriptionIndex) { if (!client || !client->Process || token == 0) return NTLSTATUS_INVALID_PARAMETER; NTL_POSIX_REPLY reply; PosixsrvInitializeReply(client, &reply, NTL_POSIX_OP_IMPORT_FD_INHERITANCE, NTLSTATUS_SUCCESS, 0); KSTATUS status = PosixsrvLockRegistry(); if (!KSUCCESS(status)) return status; POSIXSRV_FD_INHERITANCE* snapshot = PosixsrvFindFdInheritanceLocked(token); if (!snapshot || snapshot->SecurityId != client->Process->SecurityId || client->Process->State != NTL_POSIX_PROCESS_STATE_RUNNING) { PosixsrvUnlockRegistry(); return PosixsrvReply(client, messageId, NTL_POSIX_OP_IMPORT_FD_INHERITANCE, snapshot ? NTLSTATUS_ACCESS_DENIED : NTLSTATUS_NOT_FOUND, 0); } if ((snapshot->DescriptionCount != 0 && descriptionIndex >= snapshot->DescriptionCount) || (snapshot->DescriptionCount == 0 && descriptionIndex != 0)) { PosixsrvUnlockRegistry(); return PosixsrvReply(client, messageId, NTL_POSIX_OP_IMPORT_FD_INHERITANCE, NTLSTATUS_INVALID_PARAMETER, 0); } status = PosixsrvClaimFdInheritanceLocked(snapshot, client->Process); if (!KSUCCESS(status)) { PosixsrvUnlockRegistry(); return PosixsrvReply(client, messageId, NTL_POSIX_OP_IMPORT_FD_INHERITANCE, status, 0); } uint32_t count = snapshot->DescriptionCount - descriptionIndex; if (count > NTL_POSIX_FD_IMPORT_BATCH_MAX) count = NTL_POSIX_FD_IMPORT_BATCH_MAX; reply.FdInheritanceToken = token; reply.FdInheritanceIndex = descriptionIndex; reply.FdInheritanceCount = snapshot->EntryCount; reply.FdDescriptionIndex = descriptionIndex; reply.FdDescriptionCount = count; reply.FdDescriptionTotal = snapshot->DescriptionCount; for (uint32_t i = 0; i < snapshot->EntryCount; ++i) reply.FdManifest[i] = snapshot->Entries[i].Manifest; SYS_PORT_HANDLE_TRANSFER transfers[NTL_POSIX_FD_IMPORT_BATCH_MAX]; memset(transfers, 0, sizeof(transfers)); uint32_t handleCount = 0; for (uint32_t i = 0; i < count; ++i) { POSIXSRV_OPEN_DESCRIPTION* description = snapshot->Descriptions[descriptionIndex + i]; if (!description || !description->Shared) { status = NTLSTATUS_OBJECT_DEAD; break; } NTL_POSIX_FD_DESCRIPTION_ENTRY* out = &reply.FdDescriptions[i]; out->OpenDescriptionId = description->DescriptionId; out->SharedOpenDescription = (uint64_t)(uintptr_t)description->Shared; out->OpenDescriptionType = description->Type; out->OpenStatusFlags = (uint32_t)_InterlockedCompareExchange( &description->Shared->StatusFlags, 0, 0); out->HandleIndex = NTL_POSIX_FD_HANDLE_NONE; if (PosixsrvOpenDescriptionNeedsHandle(description->Type)) { if (description->MasterHandle == SYS_HANDLE_INVALID || handleCount >= NTL_POSIX_FD_IMPORT_BATCH_MAX) { status = NTLSTATUS_OBJECT_DEAD; break; } out->HandleIndex = handleCount; transfers[handleCount].Handle = description->MasterHandle; transfers[handleCount].DesiredRights = PosixsrvOpenDescriptionClientRights(description); transfers[handleCount].Flags = SYS_PORT_TRANSFER_FLAG_NONE; ++handleCount; } } if (!KSUCCESS(status)) { PosixsrvUnlockRegistry(); return PosixsrvReply(client, messageId, NTL_POSIX_OP_IMPORT_FD_INHERITANCE, status, 0); } KSTATUS replyStatus = PosixsrvSendReplyWithHandles(client, messageId, &reply, transfers, handleCount); if (KSUCCESS(replyStatus) && descriptionIndex + count == snapshot->DescriptionCount) PosixsrvDestroyFdInheritanceLocked(snapshot); PosixsrvUnlockRegistry(); return replyStatus; } // Sends one passwd-database lookup result while preserving current-process metadata. static KSTATUS PosixsrvReplyUser(POSIXSRV_CLIENT* client, uint32_t messageId, uint32_t operation, KSTATUS status, const POSIXSRV_USER_RECORD* user) { NTL_POSIX_REPLY reply; PosixsrvInitializeReply(client, &reply, operation, status, 0); if (KSUCCESS(status) && user) { reply.UserId = user->UserId; reply.GroupId = user->GroupId; reply.NameLength = PosixsrvCopyText(reply.Name, sizeof(reply.Name), user->Name); reply.HomeLength = PosixsrvCopyText(reply.Home, sizeof(reply.Home), user->Home); reply.ShellLength = PosixsrvCopyText(reply.Shell, sizeof(reply.Shell), user->Shell); } return PosixsrvSendReply(client, messageId, &reply); } // Sends one group-database lookup result while preserving current-process metadata. static KSTATUS PosixsrvReplyGroup(POSIXSRV_CLIENT* client, uint32_t messageId, uint32_t operation, KSTATUS status, const POSIXSRV_GROUP_RECORD* group) { NTL_POSIX_REPLY reply; PosixsrvInitializeReply(client, &reply, operation, status, 0); if (KSUCCESS(status) && group) { reply.GroupId = group->GroupId; reply.NameLength = PosixsrvCopyText(reply.Name, sizeof(reply.Name), group->Name); } return PosixsrvSendReply(client, messageId, &reply); } // Waits for one native process generation and records genuine process termination. static void PosixsrvProcessMonitorThread(uintptr_t argument) { POSIXSRV_PROCESS_RECORD* record = (POSIXSRV_PROCESS_RECORD*)argument; if (!record) { SysExitThread(1); return; } PosixsrvSetCurrentThreadName("posixsrv.process"); KSTATUS waitStatus = SysWait(record->ProcessHandle, SYS_WAIT_FLAG_NONE); int32_t exitCode = (int32_t)NTLSTATUS_PROCESS_UNKNOWN_FAULT; if (KSUCCESS(waitStatus)) (void)SysGetProcessExitCode(record->ProcessHandle, &exitCode); POSIXSRV_PROCESS_RECORD* freeRecord = (POSIXSRV_PROCESS_RECORD*)0; SYS_HANDLE closeHandle = SYS_HANDLE_INVALID; if (KSUCCESS(PosixsrvLockRegistry())) { if (KSUCCESS(waitStatus) && record->State == NTL_POSIX_PROCESS_STATE_RUNNING) { PosixsrvReleaseFdInheritanceForProcessLocked(record); PosixsrvReleaseAllOpenDescriptionsLocked(record); record->State = NTL_POSIX_PROCESS_STATE_EXITED; record->ExitCode = exitCode; closeHandle = record->ProcessHandle; record->ProcessHandle = SYS_HANDLE_INVALID; } record->MonitorActive = 0; if (record->State == NTL_POSIX_PROCESS_STATE_EXITED && record->ConnectionCount == 0) { PosixsrvUnlinkProcessLocked(record); freeRecord = record; } PosixsrvUnlockRegistry(); } if (closeHandle != SYS_HANDLE_INVALID) (void)SysCloseHandle(closeHandle); if (freeRecord) PosixsrvFreeProcessRecord(freeRecord); SysExitThread(KSUCCESS(waitStatus) ? 0 : 1); } // Registers the connection's native process and assigns or recovers its stable POSIX identity. static KSTATUS PosixsrvRegisterProcess(POSIXSRV_CLIENT* client, const NTL_POSIX_REQUEST* request, SYS_HANDLE* transferredProcessHandle) { if (!client || !request || !transferredProcessHandle || *transferredProcessHandle == SYS_HANDLE_INVALID) return NTLSTATUS_INVALID_PARAMETER; // Reserved bootstrap identities become active when server-owned process construction lands. if (request->BootstrapToken != 0 || request->BootstrapPosixPid != 0 || request->BootstrapGeneration != 0) return NTLSTATUS_NOT_SUPPORTED; if (!PosixsrvValidateCurrentDirectory(request) || request->NameLength != 0 || request->TargetPosixPid != 0 || request->UserId != 0 || request->GroupId != 0 || request->ProcessGroupId != 0 || request->LookupKind != NTL_POSIX_LOOKUP_NONE || request->OpenDescriptionType != 0 || request->OpenStatusFlags != 0 || request->OpenDescriptionId != 0) return NTLSTATUS_INVALID_PARAMETER; uint32_t nativePid = 0; KSTATUS status = SysGetProcessPid(*transferredProcessHandle, &nativePid); if (!KSUCCESS(status)) return status; if (nativePid != client->Connection.ClientProcessId) return NTLSTATUS_ACCESS_DENIED; POSIXSRV_PROCESS_RECORD* candidate = (POSIXSRV_PROCESS_RECORD*)calloc(1, sizeof(*candidate)); if (!candidate) return NTLSTATUS_NO_MEMORY; candidate->ProcessHandle = SYS_HANDLE_INVALID; status = PosixsrvLockRegistry(); if (!KSUCCESS(status)) { free(candidate); return status; } if (client->Process) { PosixsrvUnlockRegistry(); free(candidate); return NTLSTATUS_SUCCESS; } POSIXSRV_PROCESS_RECORD* existing = PosixsrvFindProcessLocked(nativePid, client->Connection.ClientSecurityId); if (existing && existing->State == NTL_POSIX_PROCESS_STATE_RUNNING) { existing->ConnectionCount++; client->Process = existing; PosixsrvUnlockRegistry(); free(candidate); return NTLSTATUS_SUCCESS; } uint32_t posixPid = 0; status = PosixsrvAllocatePidLocked(&posixPid); if (!KSUCCESS(status)) { PosixsrvUnlockRegistry(); free(candidate); return status; } candidate->PosixPid = posixPid; candidate->ParentPosixPid = 0; candidate->NativeProcessId = nativePid; candidate->SecurityId = client->Connection.ClientSecurityId; candidate->Generation = 1u; candidate->State = NTL_POSIX_PROCESS_STATE_RUNNING; candidate->ConnectionCount = 1u; candidate->MonitorActive = 1u; candidate->UserId = 0; candidate->EffectiveUserId = 0; candidate->GroupId = 0; candidate->EffectiveGroupId = 0; candidate->ProcessGroupId = posixPid; candidate->SessionId = posixPid; candidate->SupplementaryGroupCount = 0; (void)PosixsrvCopyText(candidate->LoginName, sizeof(candidate->LoginName), "root"); (void)PosixsrvCopyText(candidate->CurrentDirectory, sizeof(candidate->CurrentDirectory), request->Path); candidate->ProcessHandle = *transferredProcessHandle; candidate->Next = gProcessRegistry; gProcessRegistry = candidate; ++gRegisteredProcesses; client->Process = candidate; SYS_CREATE_THREAD_REQUEST create; memset(&create, 0, sizeof(create)); create.Size = sizeof(create); create.Entry = (uintptr_t)PosixsrvProcessMonitorThread; create.Argument = (uintptr_t)candidate; create.Priority = 1; create.Flags = SYS_CREATE_THREAD_FLAG_NONE; status = SysCreateThread(&create); if (!KSUCCESS(status)) { client->Process = (POSIXSRV_PROCESS_RECORD*)0; PosixsrvUnlinkProcessLocked(candidate); candidate->ProcessHandle = SYS_HANDLE_INVALID; PosixsrvUnlockRegistry(); free(candidate); return status; } *transferredProcessHandle = SYS_HANDLE_INVALID; PosixsrvUnlockRegistry(); return NTLSTATUS_SUCCESS; } // Detaches one Port connection without treating transport loss as process termination. static void PosixsrvDetachClientProcess(POSIXSRV_CLIENT* client) { if (!client || !client->Process) return; POSIXSRV_PROCESS_RECORD* freeRecord = (POSIXSRV_PROCESS_RECORD*)0; if (!KSUCCESS(PosixsrvLockRegistry())) return; POSIXSRV_PROCESS_RECORD* record = client->Process; client->Process = (POSIXSRV_PROCESS_RECORD*)0; if (record->ConnectionCount != 0) --record->ConnectionCount; if (record->State == NTL_POSIX_PROCESS_STATE_EXITED && record->ConnectionCount == 0 && !record->MonitorActive) { PosixsrvUnlinkProcessLocked(record); freeRecord = record; } PosixsrvUnlockRegistry(); if (freeRecord) PosixsrvFreeProcessRecord(freeRecord); } // Replaces the current process's authoritative POSIX current directory. static KSTATUS PosixsrvSetCurrentDirectory(POSIXSRV_CLIENT* client, const NTL_POSIX_REQUEST* request) { if (!client || !request || !client->Process) return NTLSTATUS_INVALID_PARAMETER; if (!PosixsrvValidateCurrentDirectory(request)) return NTLSTATUS_INVALID_PARAMETER; KSTATUS status = PosixsrvLockRegistry(); if (!KSUCCESS(status)) return status; if (client->Process->State != NTL_POSIX_PROCESS_STATE_RUNNING) { PosixsrvUnlockRegistry(); return NTLSTATUS_OBJECT_DEAD; } (void)PosixsrvCopyText(client->Process->CurrentDirectory, sizeof(client->Process->CurrentDirectory), request->Path); PosixsrvUnlockRegistry(); return NTLSTATUS_SUCCESS; } // Applies setuid semantics to synthetic POSIX credentials. static KSTATUS PosixsrvSetUid(POSIXSRV_CLIENT* client, uint32_t userId) { if (!client || !client->Process) return NTLSTATUS_INVALID_PARAMETER; KSTATUS status = PosixsrvLockRegistry(); if (!KSUCCESS(status)) return status; POSIXSRV_PROCESS_RECORD* process = client->Process; if (process->State != NTL_POSIX_PROCESS_STATE_RUNNING) { status = NTLSTATUS_OBJECT_DEAD; } else if (process->EffectiveUserId == 0) { process->UserId = userId; process->EffectiveUserId = userId; } else if (userId != process->UserId) { status = NTLSTATUS_ACCESS_DENIED; } PosixsrvUnlockRegistry(); return status; } // Applies setgid semantics to synthetic POSIX credentials. static KSTATUS PosixsrvSetGid(POSIXSRV_CLIENT* client, uint32_t groupId) { if (!client || !client->Process) return NTLSTATUS_INVALID_PARAMETER; KSTATUS status = PosixsrvLockRegistry(); if (!KSUCCESS(status)) return status; POSIXSRV_PROCESS_RECORD* process = client->Process; if (process->State != NTL_POSIX_PROCESS_STATE_RUNNING) { status = NTLSTATUS_OBJECT_DEAD; } else if (process->EffectiveUserId == 0) { process->GroupId = groupId; process->EffectiveGroupId = groupId; } else if (groupId != process->GroupId) { status = NTLSTATUS_ACCESS_DENIED; } PosixsrvUnlockRegistry(); return status; } // Changes one process group using the subset whose parent relationship is already authoritative. static KSTATUS PosixsrvSetProcessGroup(POSIXSRV_CLIENT* client, uint32_t targetPid, uint32_t processGroupId) { if (!client || !client->Process) return NTLSTATUS_INVALID_PARAMETER; KSTATUS status = PosixsrvLockRegistry(); if (!KSUCCESS(status)) return status; POSIXSRV_PROCESS_RECORD* caller = client->Process; if (targetPid == 0) targetPid = caller->PosixPid; POSIXSRV_PROCESS_RECORD* target = PosixsrvFindPosixProcessLocked(targetPid); if (!target || target->State != NTL_POSIX_PROCESS_STATE_RUNNING) { status = NTLSTATUS_NOT_FOUND; goto done; } if (target != caller && target->ParentPosixPid != caller->PosixPid) { status = NTLSTATUS_ACCESS_DENIED; goto done; } if (target->SessionId != caller->SessionId || target->SessionId == target->PosixPid) { status = NTLSTATUS_ACCESS_DENIED; goto done; } if (processGroupId == 0) processGroupId = target->PosixPid; if (processGroupId != target->PosixPid && !PosixsrvProcessGroupExistsLocked(target->SessionId, processGroupId)) { status = NTLSTATUS_ACCESS_DENIED; goto done; } target->ProcessGroupId = processGroupId; done: PosixsrvUnlockRegistry(); return status; } // Creates a new session for the caller when it is not currently a process-group leader. static KSTATUS PosixsrvCreateSession(POSIXSRV_CLIENT* client) { if (!client || !client->Process) return NTLSTATUS_INVALID_PARAMETER; KSTATUS status = PosixsrvLockRegistry(); if (!KSUCCESS(status)) return status; POSIXSRV_PROCESS_RECORD* process = client->Process; if (process->State != NTL_POSIX_PROCESS_STATE_RUNNING) { status = NTLSTATUS_OBJECT_DEAD; } else if (PosixsrvProcessGroupExistsLocked(process->SessionId, process->PosixPid)) { status = NTLSTATUS_ACCESS_DENIED; } else { process->SessionId = process->PosixPid; process->ProcessGroupId = process->PosixPid; } PosixsrvUnlockRegistry(); return status; } // Allocates one bounded connection-local transaction identifier for future spawn/exec work. static KSTATUS PosixsrvBeginTransaction(POSIXSRV_CLIENT* client, uint32_t kind, uint32_t* transactionIdOut) { if (!client || !transactionIdOut) return NTLSTATUS_INVALID_PARAMETER; *transactionIdOut = 0; if (kind != NTL_POSIX_TRANSACTION_SPAWN && kind != NTL_POSIX_TRANSACTION_EXEC) return NTLSTATUS_INVALID_PARAMETER; uint32_t slot = NTL_POSIX_TRANSACTION_CAPACITY; for (uint32_t i = 0; i < NTL_POSIX_TRANSACTION_CAPACITY; ++i) { if (client->Transactions[i].Id == 0) { slot = i; break; } } if (slot == NTL_POSIX_TRANSACTION_CAPACITY) return NTLSTATUS_LIMIT_REACHED; uint32_t id = ++client->NextTransactionId; if (id == 0) id = ++client->NextTransactionId; client->Transactions[slot].Id = id; client->Transactions[slot].Kind = kind; ++client->ActiveTransactions; *transactionIdOut = id; return NTLSTATUS_SUCCESS; } // Cancels one transaction owned by the current connection. static KSTATUS PosixsrvCancelTransaction(POSIXSRV_CLIENT* client, uint32_t transactionId) { if (!client || transactionId == 0) return NTLSTATUS_INVALID_PARAMETER; for (uint32_t i = 0; i < NTL_POSIX_TRANSACTION_CAPACITY; ++i) { if (client->Transactions[i].Id != transactionId) continue; memset(&client->Transactions[i], 0, sizeof(client->Transactions[i])); if (client->ActiveTransactions != 0) --client->ActiveTransactions; return NTLSTATUS_SUCCESS; } return NTLSTATUS_NOT_FOUND; } // Returns whether operation-specific bootstrap fields are all unused. static int PosixsrvHasNoBootstrap(const NTL_POSIX_REQUEST* request) { return request && request->BootstrapToken == 0 && request->BootstrapPosixPid == 0 && request->BootstrapGeneration == 0; } // Returns whether all P3 shared-attribute payload fields are unused. static int PosixsrvHasNoAttributePayload(const NTL_POSIX_REQUEST* request) { return request && request->TargetPosixPid == 0 && request->UserId == 0 && request->GroupId == 0 && request->ProcessGroupId == 0 && request->LookupKind == NTL_POSIX_LOOKUP_NONE && request->OpenDescriptionType == 0 && request->OpenStatusFlags == 0 && request->OpenDescriptionId == 0 && request->NameLength == 0 && request->PathLength == 0 && request->Name[0] == '\0' && request->Path[0] == '\0'; } // Returns whether one request carries no descriptor-inheritance payload. static int PosixsrvHasNoFdInheritancePayload(const NTL_POSIX_REQUEST* request) { if (!request || request->FdInheritanceToken != 0 || request->FdInheritanceIndex != 0 || request->FdInheritanceCount != 0 || request->FdInheritanceFlags != 0) return 0; for (uint32_t i = 0; i < NTL_POSIX_FD_INHERIT_MAX; ++i) { if (request->FdManifest[i].Descriptor != 0 || request->FdManifest[i].DescriptorFlags != 0 || request->FdManifest[i].OpenDescriptionId != 0) return 0; } return 1; } // Returns whether one request carries no transaction state. static int PosixsrvHasNoTransaction(const NTL_POSIX_REQUEST* request) { return request && request->TransactionId == 0 && request->TransactionKind == NTL_POSIX_TRANSACTION_NONE; } // Dispatches one validated bootstrap/process request and consumes transferred handles explicitly. static KSTATUS PosixsrvDispatch(POSIXSRV_CLIENT* client, const NTL_POSIX_REQUEST* request, const SYS_PORT_MESSAGE_INFO* info, SYS_HANDLE* handles) { if (!client || !request || !info) return NTLSTATUS_INVALID_PARAMETER; uint32_t operation = request->Operation; if (info->SenderProcessId != client->Connection.ClientProcessId || info->SenderSecurityId != client->Connection.ClientSecurityId) return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_ACCESS_DENIED, 0); if (request->Size != sizeof(*request) || request->Flags != NTL_POSIX_REQUEST_FLAG_NONE || request->Reserved[0] != 0 || request->Reserved[1] != 0) return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_INVALID_PARAMETER, 0); if (request->Version != NTL_POSIX_PROTOCOL_VERSION) return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_NOT_SUPPORTED, 0); if (operation == NTL_POSIX_OP_REGISTER_PROCESS) { if (!PosixsrvHasNoTransaction(request) || !PosixsrvHasNoFdInheritancePayload(request) || info->HandleCount != 1 || !handles) return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_INVALID_PARAMETER, 0); KSTATUS status = PosixsrvRegisterProcess(client, request, &handles[0]); return PosixsrvReply(client, info->MessageId, operation, status, 0); } if (!PosixsrvHasNoBootstrap(request)) return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_INVALID_PARAMETER, 0); if (operation == NTL_POSIX_OP_CREATE_FD_INHERITANCE) { if (!client->Process || client->Process->State != NTL_POSIX_PROCESS_STATE_RUNNING || info->HandleCount != 0 || !PosixsrvHasNoTransaction(request) || request->TargetPosixPid != 0 || request->UserId != 0 || request->GroupId != 0 || request->ProcessGroupId != 0 || request->LookupKind != NTL_POSIX_LOOKUP_NONE || request->OpenDescriptionType != 0 || request->OpenStatusFlags != 0 || request->OpenDescriptionId != 0 || request->NameLength != 0 || request->PathLength != 0 || request->Name[0] != '\0' || request->Path[0] != '\0') return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_INVALID_PARAMETER, 0); uint64_t token = 0; KSTATUS status = PosixsrvCreateFdInheritance(client, request, &token); NTL_POSIX_REPLY reply; PosixsrvInitializeReply(client, &reply, operation, status, 0); if (KSUCCESS(status)) { reply.FdInheritanceToken = token; reply.FdInheritanceCount = request->FdInheritanceCount; } KSTATUS replyStatus = PosixsrvSendReply(client, info->MessageId, &reply); if (!KSUCCESS(replyStatus) && KSUCCESS(status)) (void)PosixsrvCancelFdInheritance(client, token); return replyStatus; } if (operation == NTL_POSIX_OP_IMPORT_FD_INHERITANCE) { if (!client->Process || client->Process->State != NTL_POSIX_PROCESS_STATE_RUNNING || info->HandleCount != 0 || !PosixsrvHasNoTransaction(request) || request->FdInheritanceToken == 0 || request->FdInheritanceCount != 0 || request->FdInheritanceFlags != 0 || request->TargetPosixPid != 0 || request->UserId != 0 || request->GroupId != 0 || request->ProcessGroupId != 0 || request->LookupKind != NTL_POSIX_LOOKUP_NONE || request->OpenDescriptionType != 0 || request->OpenStatusFlags != 0 || request->OpenDescriptionId != 0 || request->NameLength != 0 || request->PathLength != 0 || request->Name[0] != '\0' || request->Path[0] != '\0') return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_INVALID_PARAMETER, 0); for (uint32_t i = 0; i < NTL_POSIX_FD_INHERIT_MAX; ++i) { if (request->FdManifest[i].Descriptor != 0 || request->FdManifest[i].DescriptorFlags != 0 || request->FdManifest[i].OpenDescriptionId != 0) return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_INVALID_PARAMETER, 0); } return PosixsrvReplyFdInheritance(client, info->MessageId, request->FdInheritanceToken, request->FdInheritanceIndex); } if (operation == NTL_POSIX_OP_CANCEL_FD_INHERITANCE) { if (!client->Process || client->Process->State != NTL_POSIX_PROCESS_STATE_RUNNING || info->HandleCount != 0 || !PosixsrvHasNoTransaction(request) || request->FdInheritanceToken == 0 || request->FdInheritanceIndex != 0 || request->FdInheritanceCount != 0 || request->FdInheritanceFlags != 0 || request->TargetPosixPid != 0 || request->UserId != 0 || request->GroupId != 0 || request->ProcessGroupId != 0 || request->LookupKind != NTL_POSIX_LOOKUP_NONE || request->OpenDescriptionType != 0 || request->OpenStatusFlags != 0 || request->OpenDescriptionId != 0 || request->NameLength != 0 || request->PathLength != 0 || request->Name[0] != '\0' || request->Path[0] != '\0') return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_INVALID_PARAMETER, 0); for (uint32_t i = 0; i < NTL_POSIX_FD_INHERIT_MAX; ++i) { if (request->FdManifest[i].Descriptor != 0 || request->FdManifest[i].DescriptorFlags != 0 || request->FdManifest[i].OpenDescriptionId != 0) return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_INVALID_PARAMETER, 0); } KSTATUS status = PosixsrvCancelFdInheritance(client, request->FdInheritanceToken); return PosixsrvReply(client, info->MessageId, operation, status, 0); } if (operation == NTL_POSIX_OP_ARM_FD_INHERITANCE) { if (!client->Process || client->Process->State != NTL_POSIX_PROCESS_STATE_RUNNING || info->HandleCount != 1 || !handles || !PosixsrvHasNoTransaction(request) || request->FdInheritanceToken == 0 || request->FdInheritanceIndex != 0 || request->FdInheritanceCount != 0 || request->FdInheritanceFlags != 0 || request->TargetPosixPid != 0 || request->UserId != 0 || request->GroupId != 0 || request->ProcessGroupId != 0 || request->LookupKind != NTL_POSIX_LOOKUP_NONE || request->OpenDescriptionType != 0 || request->OpenStatusFlags != 0 || request->OpenDescriptionId != 0 || request->NameLength != 0 || request->PathLength != 0 || request->Name[0] != '\0' || request->Path[0] != '\0') return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_INVALID_PARAMETER, 0); for (uint32_t i = 0; i < NTL_POSIX_FD_INHERIT_MAX; ++i) { if (request->FdManifest[i].Descriptor != 0 || request->FdManifest[i].DescriptorFlags != 0 || request->FdManifest[i].OpenDescriptionId != 0) return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_INVALID_PARAMETER, 0); } KSTATUS status = PosixsrvArmFdInheritance(client, request->FdInheritanceToken, &handles[0]); return PosixsrvReply(client, info->MessageId, operation, status, 0); } if (!PosixsrvHasNoFdInheritancePayload(request)) return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_INVALID_PARAMETER, 0); if (operation == NTL_POSIX_OP_CREATE_OPEN_DESCRIPTION) { if (!client->Process || client->Process->State != NTL_POSIX_PROCESS_STATE_RUNNING || !PosixsrvHasNoTransaction(request) || request->TargetPosixPid != 0 || request->UserId != 0 || request->GroupId != 0 || request->ProcessGroupId != 0 || request->LookupKind != NTL_POSIX_LOOKUP_NONE || request->OpenDescriptionId != 0 || request->NameLength != 0 || request->PathLength != 0 || request->Name[0] != '\0' || request->Path[0] != '\0') return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_INVALID_PARAMETER, 0); uint64_t descriptionId = 0; NTL_POSIX_SHARED_OPEN_DESCRIPTION* shared = (NTL_POSIX_SHARED_OPEN_DESCRIPTION*)0; KSTATUS status = PosixsrvCreateOpenDescription(client, request, handles, info->HandleCount, &descriptionId, &shared); KSTATUS replyStatus = PosixsrvReplyOpenDescription( client, info->MessageId, operation, status, descriptionId, request->OpenDescriptionType, request->OpenStatusFlags, shared); if (!KSUCCESS(replyStatus) && KSUCCESS(status) && descriptionId != 0) (void)PosixsrvReleaseOpenDescription(client, descriptionId); return replyStatus; } if (operation == NTL_POSIX_OP_CREATE_PIPE) { if (!client->Process || client->Process->State != NTL_POSIX_PROCESS_STATE_RUNNING || info->HandleCount != 0 || !PosixsrvHasNoTransaction(request) || !PosixsrvHasNoAttributePayload(request)) return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_INVALID_PARAMETER, 0); uint64_t readId = 0; uint64_t writeId = 0; KSTATUS status = PosixsrvCreatePipe(client, &readId, &writeId); KSTATUS replyStatus = PosixsrvReplyPipe(client, info->MessageId, status, readId, writeId); if (!KSUCCESS(replyStatus) && KSUCCESS(status)) { if (readId != 0) (void)PosixsrvReleaseOpenDescription(client, readId); if (writeId != 0) (void)PosixsrvReleaseOpenDescription(client, writeId); } return replyStatus; } if (info->HandleCount != 0) return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_INVALID_PARAMETER, 0); if (operation != NTL_POSIX_OP_RELEASE_OPEN_DESCRIPTION && operation != NTL_POSIX_OP_SET_OPEN_STATUS && (request->OpenDescriptionType != 0 || request->OpenStatusFlags != 0 || request->OpenDescriptionId != 0)) return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_INVALID_PARAMETER, 0); if (operation == NTL_POSIX_OP_QUERY) { if (!PosixsrvHasNoTransaction(request) || !PosixsrvHasNoAttributePayload(request)) return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_INVALID_PARAMETER, 0); return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_SUCCESS, 0); } if (operation == NTL_POSIX_OP_BEGIN_TRANSACTION) { if (request->TransactionId != 0 || request->TargetPosixPid != 0 || request->UserId != 0 || request->GroupId != 0 || request->ProcessGroupId != 0 || request->LookupKind != NTL_POSIX_LOOKUP_NONE || request->NameLength != 0 || request->PathLength != 0 || request->Name[0] != '\0' || request->Path[0] != '\0') return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_INVALID_PARAMETER, 0); uint32_t transactionId = 0; KSTATUS status = PosixsrvBeginTransaction(client, request->TransactionKind, &transactionId); return PosixsrvReply(client, info->MessageId, operation, status, transactionId); } if (operation == NTL_POSIX_OP_CANCEL_TRANSACTION) { if (request->TransactionKind != NTL_POSIX_TRANSACTION_NONE || request->TargetPosixPid != 0 || request->UserId != 0 || request->GroupId != 0 || request->ProcessGroupId != 0 || request->LookupKind != NTL_POSIX_LOOKUP_NONE || request->NameLength != 0 || request->PathLength != 0 || request->Name[0] != '\0' || request->Path[0] != '\0') return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_INVALID_PARAMETER, 0); KSTATUS status = PosixsrvCancelTransaction(client, request->TransactionId); return PosixsrvReply(client, info->MessageId, operation, status, KSUCCESS(status) ? request->TransactionId : 0); } if (!client->Process || client->Process->State != NTL_POSIX_PROCESS_STATE_RUNNING) return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_NOT_FOUND, 0); if (!PosixsrvHasNoTransaction(request)) return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_INVALID_PARAMETER, 0); if (operation == NTL_POSIX_OP_RELEASE_OPEN_DESCRIPTION) { if (request->OpenDescriptionId == 0 || request->OpenDescriptionType != 0 || request->OpenStatusFlags != 0 || request->TargetPosixPid != 0 || request->UserId != 0 || request->GroupId != 0 || request->ProcessGroupId != 0 || request->LookupKind != NTL_POSIX_LOOKUP_NONE || request->NameLength != 0 || request->PathLength != 0 || request->Name[0] != '\0' || request->Path[0] != '\0') return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_INVALID_PARAMETER, 0); KSTATUS status = PosixsrvReleaseOpenDescription(client, request->OpenDescriptionId); return PosixsrvReply(client, info->MessageId, operation, status, 0); } if (operation == NTL_POSIX_OP_SET_OPEN_STATUS) { if (request->OpenDescriptionId == 0 || request->OpenDescriptionType != 0 || request->TargetPosixPid != 0 || request->UserId != 0 || request->GroupId != 0 || request->ProcessGroupId != 0 || request->LookupKind != NTL_POSIX_LOOKUP_NONE || request->NameLength != 0 || request->PathLength != 0 || request->Name[0] != '\0' || request->Path[0] != '\0') return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_INVALID_PARAMETER, 0); uint32_t statusFlags = 0; uint32_t type = 0; KSTATUS status = PosixsrvSetOpenStatus(client, request->OpenDescriptionId, request->OpenStatusFlags, &statusFlags, &type); return PosixsrvReplyOpenDescription(client, info->MessageId, operation, status, request->OpenDescriptionId, type, statusFlags, (NTL_POSIX_SHARED_OPEN_DESCRIPTION*)0); } if (operation == NTL_POSIX_OP_GET_PROCESS_ATTRIBUTES) { if (!PosixsrvHasNoAttributePayload(request)) return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_INVALID_PARAMETER, 0); return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_SUCCESS, 0); } if (operation == NTL_POSIX_OP_SET_CURRENT_DIRECTORY) { if (request->TargetPosixPid != 0 || request->UserId != 0 || request->GroupId != 0 || request->ProcessGroupId != 0 || request->LookupKind != NTL_POSIX_LOOKUP_NONE || request->NameLength != 0 || request->Name[0] != '\0') return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_INVALID_PARAMETER, 0); KSTATUS status = PosixsrvSetCurrentDirectory(client, request); return PosixsrvReply(client, info->MessageId, operation, status, 0); } if (operation == NTL_POSIX_OP_SET_UID) { if (request->TargetPosixPid != 0 || request->GroupId != 0 || request->ProcessGroupId != 0 || request->LookupKind != NTL_POSIX_LOOKUP_NONE || request->NameLength != 0 || request->PathLength != 0 || request->Name[0] != '\0' || request->Path[0] != '\0') return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_INVALID_PARAMETER, 0); KSTATUS status = PosixsrvSetUid(client, request->UserId); return PosixsrvReply(client, info->MessageId, operation, status, 0); } if (operation == NTL_POSIX_OP_SET_GID) { if (request->TargetPosixPid != 0 || request->UserId != 0 || request->ProcessGroupId != 0 || request->LookupKind != NTL_POSIX_LOOKUP_NONE || request->NameLength != 0 || request->PathLength != 0 || request->Name[0] != '\0' || request->Path[0] != '\0') return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_INVALID_PARAMETER, 0); KSTATUS status = PosixsrvSetGid(client, request->GroupId); return PosixsrvReply(client, info->MessageId, operation, status, 0); } if (operation == NTL_POSIX_OP_SET_PROCESS_GROUP) { if (request->UserId != 0 || request->GroupId != 0 || request->LookupKind != NTL_POSIX_LOOKUP_NONE || request->NameLength != 0 || request->PathLength != 0 || request->Name[0] != '\0' || request->Path[0] != '\0') return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_INVALID_PARAMETER, 0); KSTATUS status = PosixsrvSetProcessGroup(client, request->TargetPosixPid, request->ProcessGroupId); return PosixsrvReply(client, info->MessageId, operation, status, 0); } if (operation == NTL_POSIX_OP_CREATE_SESSION) { if (!PosixsrvHasNoAttributePayload(request)) return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_INVALID_PARAMETER, 0); KSTATUS status = PosixsrvCreateSession(client); return PosixsrvReply(client, info->MessageId, operation, status, 0); } if (operation == NTL_POSIX_OP_LOOKUP_USER) { if (request->TargetPosixPid != 0 || request->ProcessGroupId != 0 || request->GroupId != 0 || request->PathLength != 0 || request->Path[0] != '\0' || (request->LookupKind != NTL_POSIX_LOOKUP_BY_ID && request->LookupKind != NTL_POSIX_LOOKUP_BY_NAME) || (request->LookupKind == NTL_POSIX_LOOKUP_BY_ID && (request->NameLength != 0 || request->Name[0] != '\0')) || (request->LookupKind == NTL_POSIX_LOOKUP_BY_NAME && !PosixsrvValidateLookupName(request))) return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_INVALID_PARAMETER, 0); const POSIXSRV_USER_RECORD* user = PosixsrvFindUser(request->LookupKind, request->UserId, request->Name); return PosixsrvReplyUser(client, info->MessageId, operation, user ? NTLSTATUS_SUCCESS : NTLSTATUS_NOT_FOUND, user); } if (operation == NTL_POSIX_OP_LOOKUP_GROUP) { if (request->TargetPosixPid != 0 || request->ProcessGroupId != 0 || request->UserId != 0 || request->PathLength != 0 || request->Path[0] != '\0' || (request->LookupKind != NTL_POSIX_LOOKUP_BY_ID && request->LookupKind != NTL_POSIX_LOOKUP_BY_NAME) || (request->LookupKind == NTL_POSIX_LOOKUP_BY_ID && (request->NameLength != 0 || request->Name[0] != '\0')) || (request->LookupKind == NTL_POSIX_LOOKUP_BY_NAME && !PosixsrvValidateLookupName(request))) return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_INVALID_PARAMETER, 0); const POSIXSRV_GROUP_RECORD* group = PosixsrvFindGroup(request->LookupKind, request->GroupId, request->Name); return PosixsrvReplyGroup(client, info->MessageId, operation, group ? NTLSTATUS_SUCCESS : NTLSTATUS_NOT_FOUND, group); } return PosixsrvReply(client, info->MessageId, operation, NTLSTATUS_NOT_SUPPORTED, 0); } // Closes every unconsumed capability delivered with one client request. static void PosixsrvCloseReceivedHandles(SYS_HANDLE* handles, uint32_t count) { if (!handles) return; for (uint32_t i = 0; i < count; ++i) { if (handles[i] != SYS_HANDLE_INVALID) (void)SysCloseHandle(handles[i]); } } // Serves one client until disconnect and drops connection-owned transactions on exit. static void PosixsrvClientThread(uintptr_t argument) { POSIXSRV_CLIENT* client = (POSIXSRV_CLIENT*)argument; if (!client) { SysExitThread(1); return; } PosixsrvSetCurrentThreadName("posixsrv.client"); for (;;) { NTL_POSIX_REQUEST request; SYS_PORT_MESSAGE_INFO info; SYS_HANDLE handles[SYS_PORT_MAX_TRANSFER_HANDLES]; memset(&request, 0, sizeof(request)); memset(&info, 0, sizeof(info)); for (uint32_t i = 0; i < SYS_PORT_MAX_TRANSFER_HANDLES; ++i) handles[i] = SYS_HANDLE_INVALID; info.Size = sizeof(info); SYS_RECEIVE_PORT_REQUEST receive; memset(&receive, 0, sizeof(receive)); receive.Size = sizeof(receive); receive.EndpointHandle = client->Endpoint; receive.Flags = SYS_PORT_FLAG_NONE; receive.Payload = &request; receive.PayloadCapacity = sizeof(request); receive.HandlesOut = handles; receive.HandleCapacity = SYS_PORT_MAX_TRANSFER_HANDLES; receive.InfoOut = &info; receive.TimeoutMilliseconds = SYS_PORT_TIMEOUT_INFINITE; KSTATUS status = SysReceivePort(&receive); if (status == NTLSTATUS_PORT_DISCONNECTED || !KSUCCESS(status)) break; if (info.Type != SYS_PORT_MESSAGE_REQUEST || info.PayloadLength != sizeof(request)) { if (info.Type == SYS_PORT_MESSAGE_REQUEST) (void)PosixsrvReply(client, info.MessageId, request.Operation, NTLSTATUS_INVALID_PARAMETER, 0); PosixsrvCloseReceivedHandles(handles, info.HandleCount); continue; } status = PosixsrvDispatch(client, &request, &info, handles); PosixsrvCloseReceivedHandles(handles, info.HandleCount); if (!KSUCCESS(status)) break; } PosixsrvDetachClientProcess(client); (void)SysDisconnectPort(client->Endpoint); (void)SysCloseHandle(client->Endpoint); free(client); SysExitThread(0); } // Accepts public connections and gives each kernel-stamped client identity its own worker. static void PosixsrvListenerThread(uintptr_t argument) { SYS_HANDLE listener = (SYS_HANDLE)argument; PosixsrvSetCurrentThreadName("posixsrv.listen"); for (;;) { POSIXSRV_CLIENT* client = (POSIXSRV_CLIENT*)calloc(1, sizeof(*client)); if (!client) { SysExitThread(1); return; } client->Endpoint = SYS_HANDLE_INVALID; client->Connection.Size = sizeof(client->Connection); SYS_ACCEPT_PORT_REQUEST accept; memset(&accept, 0, sizeof(accept)); accept.Size = sizeof(accept); accept.ListenerHandle = listener; accept.Flags = SYS_PORT_ACCEPT_FLAG_NONE; accept.TimeoutMilliseconds = SYS_PORT_TIMEOUT_INFINITE; accept.EndpointHandleOut = &client->Endpoint; accept.ConnectionInfoOut = &client->Connection; KSTATUS status = SysAcceptPort(&accept); if (!KSUCCESS(status)) { free(client); break; } SYS_CREATE_THREAD_REQUEST create; memset(&create, 0, sizeof(create)); create.Size = sizeof(create); create.Entry = (uintptr_t)PosixsrvClientThread; create.Argument = (uintptr_t)client; create.Priority = 1; create.Flags = SYS_CREATE_THREAD_FLAG_NONE; status = SysCreateThread(&create); if (!KSUCCESS(status)) { (void)SysDisconnectPort(client->Endpoint); (void)SysCloseHandle(client->Endpoint); free(client); } } SysExitThread(0); } // Reports READY and transfers the public listener for init-owned RSSRV namespace publication. static KSTATUS PosixsrvSendReady(SYS_HANDLE controlEndpoint, SYS_HANDLE publicListener) { if (controlEndpoint == SYS_HANDLE_INVALID || publicListener == SYS_HANDLE_INVALID) return NTLSTATUS_INVALID_PARAMETER; NTL_SERVICE_CONTROL_MESSAGE message; memset(&message, 0, sizeof(message)); message.Size = sizeof(message); message.Version = NTL_SERVICE_CONTROL_VERSION; message.Operation = NTL_SERVICE_CONTROL_READY; message.ExportCount = 1u; message.Status = NTLSTATUS_SUCCESS; SYS_PORT_HANDLE_TRANSFER transfer; memset(&transfer, 0, sizeof(transfer)); transfer.Handle = publicListener; transfer.DesiredRights = SYS_RIGHT_TRANSFER | SYS_RIGHT_QUERY | SYS_PORT_RIGHT_CONNECT; transfer.Flags = SYS_PORT_TRANSFER_FLAG_NONE; SYS_SEND_PORT_REQUEST send; memset(&send, 0, sizeof(send)); send.Size = sizeof(send); send.EndpointHandle = controlEndpoint; send.Flags = SYS_PORT_FLAG_NONE; send.Payload = &message; send.PayloadLength = sizeof(message); send.Handles = &transfer; send.HandleCount = 1u; send.TimeoutMilliseconds = SYS_PORT_TIMEOUT_INFINITE; return SysSendPort(&send); } // Waits for init to stop the service or close the private control connection. static void PosixsrvControlLoop(SYS_HANDLE endpoint) { for (;;) { NTL_SERVICE_CONTROL_MESSAGE message; SYS_PORT_MESSAGE_INFO info; memset(&message, 0, sizeof(message)); memset(&info, 0, sizeof(info)); info.Size = sizeof(info); SYS_RECEIVE_PORT_REQUEST receive; memset(&receive, 0, sizeof(receive)); receive.Size = sizeof(receive); receive.EndpointHandle = endpoint; receive.Payload = &message; receive.PayloadCapacity = sizeof(message); receive.InfoOut = &info; receive.TimeoutMilliseconds = SYS_PORT_TIMEOUT_INFINITE; KSTATUS status = SysReceivePort(&receive); if (status == NTLSTATUS_PORT_DISCONNECTED || !KSUCCESS(status)) return; if (info.Type != SYS_PORT_MESSAGE_NOTIFICATION || info.HandleCount != 0 || info.PayloadLength != sizeof(message) || message.Size != sizeof(message) || message.Version != NTL_SERVICE_CONTROL_VERSION || message.ExportCount != 0 || message.Reserved[0] != 0 || message.Reserved[1] != 0 || message.Reserved[2] != 0) continue; if (message.Operation == NTL_SERVICE_CONTROL_STOP) return; } } // Starts the POSIX policy service while keeping stable POSIX process identity out of the kernel. void _start(void) { KSTATUS status = NtlInitializeExceptionRuntime(); if (!KSUCCESS(status)) PosixsrvExit(1); PosixsrvSetCurrentThreadName("posixsrv.main"); status = PosixsrvValidateSecurity(); if (!KSUCCESS(status)) PosixsrvExit(2); status = SysCreateMutex(&gProcessRegistryMutex); if (!KSUCCESS(status)) PosixsrvExit(3); SYS_HANDLE controlListener = SysGetStartupCapability(SYS_STARTUP_CAP_SERVICE_CONTROL); if (controlListener == SYS_HANDLE_INVALID) PosixsrvExit(4); SYS_HANDLE publicListener = SYS_HANDLE_INVALID; status = PosixsrvCreateListener(&publicListener); if (!KSUCCESS(status)) PosixsrvExit(5); SYS_HANDLE controlEndpoint = SYS_HANDLE_INVALID; status = PosixsrvAcceptControl(controlListener, &controlEndpoint); (void)SysCloseHandle(controlListener); if (!KSUCCESS(status)) PosixsrvExit(6); SYS_CREATE_THREAD_REQUEST create; memset(&create, 0, sizeof(create)); create.Size = sizeof(create); create.Entry = (uintptr_t)PosixsrvListenerThread; create.Argument = (uintptr_t)publicListener; create.Priority = 1; create.Flags = SYS_CREATE_THREAD_FLAG_NONE; status = SysCreateThread(&create); if (!KSUCCESS(status)) PosixsrvExit(7); status = PosixsrvSendReady(controlEndpoint, publicListener); if (!KSUCCESS(status)) PosixsrvExit(8); PosixsrvControlLoop(controlEndpoint); (void)SysDisconnectPort(controlEndpoint); (void)SysCloseHandle(controlEndpoint); (void)SysCloseHandle(publicListener); (void)SysCloseHandle(gProcessRegistryMutex); gProcessRegistryMutex = SYS_HANDLE_INVALID; PosixsrvExit(0); }