// Native userspace path policy. RSSRV resolves global resource prefixes; kernel I/O sees only capabilities and relative paths. #include #include #include #include #include #include "module_loader_internal.h" #define NTL_PATH_COMPONENT_MAX 255u typedef struct NTL_RESOLVED_ROOT { SYS_HANDLE Handle; SYS_STRING_VIEW RelativePath; uint32_t Kind; size_t ResolvedLength; } NTL_RESOLVED_ROOT; static volatile int32_t gPathState; static volatile int32_t gPathLock; static char gCurrentDirectory[SYS_PATH_MAX + 1u]; static size_t gCurrentDirectoryLength; static size_t gCurrentDirectoryRootLength; // Acquires the tiny userspace CWD lock without introducing a kernel object. static void NtlpLockPathState(void) { while (NtlAtomicCompareExchange32(&gPathLock, 1, 0) != 0) (void)SysYield(); } // Releases the userspace CWD lock. static void NtlpUnlockPathState(void) { NtlAtomicExchange32(&gPathLock, 0); } // Initializes the process-local CWD from opaque loader data, or /SystemRoot for bootstrap init. static KSTATUS NtlpEnsurePathState(void) { if (NtlAtomicCompareExchange32(&gPathState, 2, 2) == 2) return NTLSTATUS_SUCCESS; if (NtlAtomicCompareExchange32(&gPathState, 1, 0) == 0) { SYS_STRING_VIEW inherited; KSTATUS status = NtlpGetLoaderCurrentDirectory(&inherited); if (!KSUCCESS(status)) inherited = SYS_SV_LITERAL("/SystemRoot"); if (!SysSvIsValid(inherited) || inherited.Length == 0 || inherited.Length > SYS_PATH_MAX || inherited.Data[0] != '/' || SysSvContainsByte(inherited, '\\') || SysSvContainsByte(inherited, '\0')) { NtlAtomicExchange32(&gPathState, 0); return NTLSTATUS_FAILURE; } memcpy(gCurrentDirectory, inherited.Data, inherited.Length); gCurrentDirectory[inherited.Length] = '\0'; gCurrentDirectoryLength = inherited.Length; gCurrentDirectoryRootLength = 0; NtlAtomicExchange32(&gPathState, 2); return NTLSTATUS_SUCCESS; } while (NtlAtomicCompareExchange32(&gPathState, 2, 2) == 1) (void)SysYield(); return NtlAtomicCompareExchange32(&gPathState, 2, 2) == 2 ? NTLSTATUS_SUCCESS : NTLSTATUS_FAILURE; } // Appends one normalized path component while enforcing the owning resource boundary. static KSTATUS NtlpAppendComponent(char* output, size_t outputSize, size_t* lengthInOut, size_t componentStart, const char* component, size_t componentLength, uint32_t clampAtBoundary) { if (!output || !lengthInOut || !component || componentLength == 0 || componentLength > NTL_PATH_COMPONENT_MAX) return NTLSTATUS_INVALID_PARAMETER; size_t length = *lengthInOut; if (componentLength == 1 && component[0] == '.') return NTLSTATUS_SUCCESS; if (componentLength == 2 && component[0] == '.' && component[1] == '.') { if (length <= componentStart) return clampAtBoundary ? NTLSTATUS_SUCCESS : NTLSTATUS_ACCESS_DENIED; size_t slash = length; while (slash > componentStart && output[slash - 1u] != '/') slash--; if (slash <= componentStart) return clampAtBoundary ? NTLSTATUS_SUCCESS : NTLSTATUS_ACCESS_DENIED; length = slash - 1u; *lengthInOut = length; output[length] = '\0'; return NTLSTATUS_SUCCESS; } if (length && output[length - 1u] != '/') { if (length + 1u >= outputSize) return NTLSTATUS_BUFFER_TOO_SMALL; output[length++] = '/'; } if (componentLength > outputSize - length - 1u) return NTLSTATUS_BUFFER_TOO_SMALL; memcpy(output + length, component, componentLength); length += componentLength; output[length] = '\0'; *lengthInOut = length; return NTLSTATUS_SUCCESS; } // Returns whether one relative path contains a parent-traversal component. static uint32_t NtlpContainsParentComponent(SYS_STRING_VIEW path) { size_t componentStart = 0; for (size_t i = 0; i <= path.Length; ++i) { if (i != path.Length && path.Data[i] != '/') continue; size_t componentLength = i - componentStart; if (componentLength == 2 && path.Data[componentStart] == '.' && path.Data[componentStart + 1u] == '.') return 1; componentStart = i + 1u; } return 0; } // Builds the canonical absolute prefix preceding the first parent component. static KSTATUS NtlpBuildAbsoluteParentPrefix(SYS_STRING_VIEW path, char output[SYS_PATH_MAX + 1u], size_t* lengthOut) { if (!output || !lengthOut || !SysSvIsValid(path) || path.Length == 0 || path.Data[0] != '/') return NTLSTATUS_INVALID_PARAMETER; size_t length = 1u; output[0] = '/'; output[1] = '\0'; size_t componentStart = 1u; for (size_t i = 1u; i <= path.Length; ++i) { if (i != path.Length && path.Data[i] != '/') continue; size_t componentLength = i - componentStart; if (componentLength == 1u && path.Data[componentStart] == '.') { componentStart = i + 1u; continue; } if (componentLength == 2u && path.Data[componentStart] == '.' && path.Data[componentStart + 1u] == '.') { if (length <= 1u) return NTLSTATUS_ACCESS_DENIED; *lengthOut = length; return NTLSTATUS_SUCCESS; } if (componentLength != 0) { KSTATUS status = NtlpAppendComponent(output, SYS_PATH_MAX + 1u, &length, 1u, path.Data + componentStart, componentLength, 0); if (!KSUCCESS(status)) return status; } componentStart = i + 1u; } return NTLSTATUS_INVALID_PARAMETER; } // Resolves one canonical path solely to discover the owning RSSRV resource-prefix boundary. static KSTATUS NtlpResolveResourceBoundary(const char* canonical, size_t canonicalLength, size_t* boundaryOut) { if (!canonical || canonicalLength < 2u || !boundaryOut) return NTLSTATUS_INVALID_PARAMETER; *boundaryOut = 0; SYS_HANDLE session = SYS_HANDLE_INVALID; KSTATUS status = NtlResourceConnect(&session); if (!KSUCCESS(status)) return status; SYS_HANDLE root = SYS_HANDLE_INVALID; uint32_t kind = NTL_RESOURCE_KIND_INVALID; uint32_t resolvedLength = 0; status = NtlResourceResolve(session, SysSvFromParts(canonical, canonicalLength), NTL_RESOURCE_FLAG_NONE, &root, &kind, &resolvedLength); (void)NtlResourceClose(session); if (root != SYS_HANDLE_INVALID) (void)SysCloseHandle(root); if (!KSUCCESS(status)) return status; if (kind == NTL_RESOURCE_KIND_INVALID || resolvedLength < 2u || resolvedLength > canonicalLength || (resolvedLength != canonicalLength && canonical[resolvedLength] != '/')) return NTLSTATUS_FAILURE; *boundaryOut = resolvedLength; return NTLSTATUS_SUCCESS; } // Normalizes one absolute or CWD-relative native path into a canonical resource path. static KSTATUS NtlpNormalizePath(SYS_STRING_VIEW path, char output[SYS_PATH_MAX + 1u], size_t* lengthOut) { if (!output || !lengthOut || !SysSvIsValid(path) || SysSvContainsByte(path, '\0') || SysSvContainsByte(path, '\\')) return NTLSTATUS_INVALID_PARAMETER; KSTATUS status = NtlpEnsurePathState(); if (!KSUCCESS(status)) return status; size_t outputLength = 0; size_t rootBoundary = 1u; size_t sourceOffset = 0; uint32_t absolutePath = path.Length && path.Data[0] == '/'; if (absolutePath) { output[0] = '/'; output[1] = '\0'; outputLength = 1u; sourceOffset = 1u; if (NtlpContainsParentComponent(path)) { char prefix[SYS_PATH_MAX + 1u]; size_t prefixLength = 0; status = NtlpBuildAbsoluteParentPrefix(path, prefix, &prefixLength); if (!KSUCCESS(status)) return status; status = NtlpResolveResourceBoundary(prefix, prefixLength, &rootBoundary); if (!KSUCCESS(status)) return status; } } else { NtlpLockPathState(); if (gCurrentDirectoryLength > SYS_PATH_MAX || gCurrentDirectoryRootLength > gCurrentDirectoryLength) { NtlpUnlockPathState(); return NTLSTATUS_FAILURE; } memcpy(output, gCurrentDirectory, gCurrentDirectoryLength + 1u); outputLength = gCurrentDirectoryLength; rootBoundary = gCurrentDirectoryRootLength; NtlpUnlockPathState(); sourceOffset = 0; if (rootBoundary == 0 && NtlpContainsParentComponent(path)) { status = NtlpResolveResourceBoundary(output, outputLength, &rootBoundary); if (!KSUCCESS(status)) return status; NtlpLockPathState(); if (gCurrentDirectoryLength == outputLength && memcmp(gCurrentDirectory, output, outputLength + 1u) == 0) gCurrentDirectoryRootLength = rootBoundary; NtlpUnlockPathState(); } } size_t componentStart = sourceOffset; for (size_t i = sourceOffset; i <= path.Length; ++i) { if (i != path.Length && path.Data[i] != '/') continue; size_t componentLength = i - componentStart; if (componentLength != 0) { status = NtlpAppendComponent(output, SYS_PATH_MAX + 1u, &outputLength, rootBoundary, path.Data + componentStart, componentLength, absolutePath ? 0u : 1u); if (!KSUCCESS(status)) return status; } componentStart = i + 1u; } while (outputLength > 1u && output[outputLength - 1u] == '/') outputLength--; output[outputLength] = '\0'; if (outputLength < 2u || output[0] != '/') return NTLSTATUS_INVALID_PARAMETER; *lengthOut = outputLength; return NTLSTATUS_SUCCESS; } // Resolves a canonical resource path to one volume/directory capability and a relative tail. static KSTATUS NtlpResolveRoot(const char* canonical, size_t canonicalLength, uint32_t modify, NTL_RESOLVED_ROOT* rootOut) { if (!canonical || canonicalLength < 2u || !rootOut) return NTLSTATUS_INVALID_PARAMETER; memset(rootOut, 0, sizeof(*rootOut)); SYS_HANDLE session = SYS_HANDLE_INVALID; KSTATUS status = NtlResourceConnect(&session); if (!KSUCCESS(status)) return status; SYS_HANDLE root = SYS_HANDLE_INVALID; uint32_t kind = NTL_RESOURCE_KIND_INVALID; uint32_t resolvedLength = 0; status = NtlResourceResolve(session, SysSvFromParts(canonical, canonicalLength), modify ? NTL_RESOURCE_RESOLVE_FLAG_MODIFY : NTL_RESOURCE_FLAG_NONE, &root, &kind, &resolvedLength); (void)NtlResourceClose(session); if (!KSUCCESS(status)) return status; size_t relativeOffset = resolvedLength; if (relativeOffset < canonicalLength) relativeOffset++; if (relativeOffset > canonicalLength) { (void)SysCloseHandle(root); return NTLSTATUS_FAILURE; } rootOut->Handle = root; rootOut->Kind = kind; rootOut->ResolvedLength = resolvedLength; rootOut->RelativePath = SysSvFromParts(canonical + relativeOffset, canonicalLength - relativeOffset); return NTLSTATUS_SUCCESS; } // Returns one canonical absolute resource path. KSTATUS NtlRealPath(SYS_STRING_VIEW path, char* buffer, size_t bufferSize, size_t* requiredSizeOut) { if (requiredSizeOut) *requiredSizeOut = 0; if (!buffer && bufferSize) return NTLSTATUS_INVALID_PARAMETER; char canonical[SYS_PATH_MAX + 1u]; size_t length = 0; KSTATUS status = NtlpNormalizePath(path, canonical, &length); if (!KSUCCESS(status)) return status; size_t required = length + 1u; if (requiredSizeOut) *requiredSizeOut = required; if (!buffer) return NTLSTATUS_SUCCESS; if (bufferSize < required) return NTLSTATUS_BUFFER_TOO_SMALL; memcpy(buffer, canonical, required); return NTLSTATUS_SUCCESS; } // Returns the process-local userspace current directory. KSTATUS NtlGetCurrentDirectory(char* buffer, size_t bufferSize, size_t* requiredSizeOut) { if (requiredSizeOut) *requiredSizeOut = 0; if (!buffer && bufferSize) return NTLSTATUS_INVALID_PARAMETER; KSTATUS status = NtlpEnsurePathState(); if (!KSUCCESS(status)) return status; NtlpLockPathState(); size_t required = gCurrentDirectoryLength + 1u; if (requiredSizeOut) *requiredSizeOut = required; if (buffer && bufferSize >= required) memcpy(buffer, gCurrentDirectory, required); NtlpUnlockPathState(); if (!buffer) return NTLSTATUS_SUCCESS; return bufferSize >= required ? NTLSTATUS_SUCCESS : NTLSTATUS_BUFFER_TOO_SMALL; } // Validates and installs one process-local userspace current directory. KSTATUS NtlSetCurrentDirectory(SYS_STRING_VIEW path) { char canonical[SYS_PATH_MAX + 1u]; size_t length = 0; KSTATUS status = NtlpNormalizePath(path, canonical, &length); if (!KSUCCESS(status)) return status; NTL_RESOLVED_ROOT root; status = NtlpResolveRoot(canonical, length, 0, &root); if (!KSUCCESS(status)) return status; SYS_HANDLE directory = SYS_HANDLE_INVALID; SYS_OPEN_DIR_AT_REQUEST open = SysMakeOpenDirAtRequest(root.Handle, root.RelativePath, SYS_DIR_ACCESS_ENUMERATE | SYS_DIR_ACCESS_OPEN, SYS_DIR_FLAG_NONE, &directory); status = SysOpenDirAt(&open); (void)SysCloseHandle(root.Handle); if (!KSUCCESS(status)) return status; (void)SysCloseHandle(directory); NtlpLockPathState(); memcpy(gCurrentDirectory, canonical, length + 1u); gCurrentDirectoryLength = length; gCurrentDirectoryRootLength = root.ResolvedLength; NtlpUnlockPathState(); return NTLSTATUS_SUCCESS; } // Opens or creates one file through RSSRV resource resolution and capability-relative kernel I/O. KSTATUS NtlOpenFile(SYS_STRING_VIEW path, uint32_t access, uint32_t disposition, uint32_t flags, SYS_HANDLE* handleOut) { if (!handleOut) return NTLSTATUS_INVALID_PARAMETER; *handleOut = SYS_HANDLE_INVALID; char canonical[SYS_PATH_MAX + 1u]; size_t length = 0; KSTATUS status = NtlpNormalizePath(path, canonical, &length); if (!KSUCCESS(status)) return status; uint32_t modify = ((access & (SYS_FILE_ACCESS_WRITE | SYS_FILE_ACCESS_APPEND | SYS_FILE_ACCESS_LOCK)) != 0 || disposition != SYS_FILE_OPEN_EXISTING); NTL_RESOLVED_ROOT root; status = NtlpResolveRoot(canonical, length, modify, &root); if (!KSUCCESS(status)) return status; if (root.RelativePath.Length == 0) { (void)SysCloseHandle(root.Handle); return NTLSTATUS_INVALID_PARAMETER; } SYS_OPEN_FILE_AT_REQUEST request = SysMakeOpenFileAtRequest(root.Handle, root.RelativePath, access, disposition, flags, handleOut); status = SysOpenFileAt(&request); (void)SysCloseHandle(root.Handle); return status; } // Opens one directory through RSSRV resource resolution and capability-relative kernel I/O. KSTATUS NtlOpenDir(SYS_STRING_VIEW path, uint32_t access, uint32_t flags, SYS_HANDLE* handleOut) { if (!handleOut) return NTLSTATUS_INVALID_PARAMETER; *handleOut = SYS_HANDLE_INVALID; char canonical[SYS_PATH_MAX + 1u]; size_t length = 0; KSTATUS status = NtlpNormalizePath(path, canonical, &length); if (!KSUCCESS(status)) return status; NTL_RESOLVED_ROOT root; status = NtlpResolveRoot(canonical, length, (access & SYS_DIR_ACCESS_MODIFY) != 0, &root); if (!KSUCCESS(status)) return status; SYS_OPEN_DIR_AT_REQUEST request = SysMakeOpenDirAtRequest(root.Handle, root.RelativePath, access, flags, handleOut); status = SysOpenDirAt(&request); (void)SysCloseHandle(root.Handle); return status; } // Queries file metadata through one resolved root capability. KSTATUS NtlStatPath(SYS_STRING_VIEW path, SYS_FILE_STAT* statOut) { if (!statOut) return NTLSTATUS_INVALID_PARAMETER; char canonical[SYS_PATH_MAX + 1u]; size_t length = 0; KSTATUS status = NtlpNormalizePath(path, canonical, &length); if (!KSUCCESS(status)) return status; NTL_RESOLVED_ROOT root; status = NtlpResolveRoot(canonical, length, 0, &root); if (!KSUCCESS(status)) return status; SYS_STAT_AT_REQUEST request = { sizeof(request), root.Handle, root.RelativePath, statOut }; status = SysStatAt(&request); (void)SysCloseHandle(root.Handle); return status; } // Deletes one file through one resolved writable root capability. KSTATUS NtlDeleteFile(SYS_STRING_VIEW path) { char canonical[SYS_PATH_MAX + 1u]; size_t length = 0; KSTATUS status = NtlpNormalizePath(path, canonical, &length); if (!KSUCCESS(status)) return status; NTL_RESOLVED_ROOT root; status = NtlpResolveRoot(canonical, length, 1, &root); if (!KSUCCESS(status)) return status; SYS_PATH_AT_REQUEST request = { sizeof(request), root.Handle, root.RelativePath }; status = root.RelativePath.Length ? SysDeleteAt(&request) : NTLSTATUS_INVALID_PARAMETER; (void)SysCloseHandle(root.Handle); return status; } // Renames one file using independently resolved writable roots. KSTATUS NtlRenameFile(SYS_STRING_VIEW oldPath, SYS_STRING_VIEW newPath) { char oldCanonical[SYS_PATH_MAX + 1u]; char newCanonical[SYS_PATH_MAX + 1u]; size_t oldLength = 0, newLength = 0; KSTATUS status = NtlpNormalizePath(oldPath, oldCanonical, &oldLength); if (!KSUCCESS(status)) return status; status = NtlpNormalizePath(newPath, newCanonical, &newLength); if (!KSUCCESS(status)) return status; NTL_RESOLVED_ROOT oldRoot, newRoot; status = NtlpResolveRoot(oldCanonical, oldLength, 1, &oldRoot); if (!KSUCCESS(status)) return status; status = NtlpResolveRoot(newCanonical, newLength, 1, &newRoot); if (!KSUCCESS(status)) { (void)SysCloseHandle(oldRoot.Handle); return status; } if (oldRoot.RelativePath.Length == 0 || newRoot.RelativePath.Length == 0) { (void)SysCloseHandle(newRoot.Handle); (void)SysCloseHandle(oldRoot.Handle); return NTLSTATUS_INVALID_PARAMETER; } SYS_RENAME_AT_REQUEST request; memset(&request, 0, sizeof(request)); request.Size = sizeof(request); request.OldRootHandle = oldRoot.Handle; request.OldPath = oldRoot.RelativePath; request.NewRootHandle = newRoot.Handle; request.NewPath = newRoot.RelativePath; status = SysRenameAt(&request); (void)SysCloseHandle(newRoot.Handle); (void)SysCloseHandle(oldRoot.Handle); return status; } // Creates one directory through one resolved writable root capability. KSTATUS NtlCreateDirectory(SYS_STRING_VIEW path) { char canonical[SYS_PATH_MAX + 1u]; size_t length = 0; KSTATUS status = NtlpNormalizePath(path, canonical, &length); if (!KSUCCESS(status)) return status; NTL_RESOLVED_ROOT root; status = NtlpResolveRoot(canonical, length, 1, &root); if (!KSUCCESS(status)) return status; SYS_PATH_AT_REQUEST request = { sizeof(request), root.Handle, root.RelativePath }; status = root.RelativePath.Length ? SysCreateDirAt(&request) : NTLSTATUS_INVALID_PARAMETER; (void)SysCloseHandle(root.Handle); return status; } // Removes one directory through one resolved writable root capability. KSTATUS NtlRemoveDirectory(SYS_STRING_VIEW path) { char canonical[SYS_PATH_MAX + 1u]; size_t length = 0; KSTATUS status = NtlpNormalizePath(path, canonical, &length); if (!KSUCCESS(status)) return status; NTL_RESOLVED_ROOT root; status = NtlpResolveRoot(canonical, length, 1, &root); if (!KSUCCESS(status)) return status; SYS_PATH_AT_REQUEST request = { sizeof(request), root.Handle, root.RelativePath }; status = root.RelativePath.Length ? SysRemoveDirAt(&request) : NTLSTATUS_INVALID_PARAMETER; (void)SysCloseHandle(root.Handle); return status; }