118 lines
4.0 KiB
C
118 lines
4.0 KiB
C
// Userspace current-directory smoke test.
|
|
// Verifies CWD inheritance and parent traversal clamped at the owning RSSRV resource binding.
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <ntlite/syscall.h>
|
|
#include <ntlite/path.h>
|
|
#include <ntlite/resource.h>
|
|
|
|
static void print(const char* s) {
|
|
SYS_WRITE_CONSOLE_REQUEST req = { sizeof(req), SysSvFromCstr(s) };
|
|
SysWriteConsole(&req);
|
|
}
|
|
|
|
static void exit_now(int code) {
|
|
while (true) SysExitProcess(code);
|
|
}
|
|
|
|
static void fail_status(const char* what, KSTATUS status) {
|
|
(void)status;
|
|
print("cwd_userspace_smoke: "); print(what); print("\n");
|
|
exit_now(1);
|
|
}
|
|
|
|
static void fail(const char* what) {
|
|
print("cwd_userspace_smoke: "); print(what); print("\n");
|
|
exit_now(1);
|
|
}
|
|
|
|
static void get_cwd_or_fail(char out[SYS_PATH_MAX + 1u]) {
|
|
size_t required = 0;
|
|
KSTATUS status = NtlGetCurrentDirectory(out, SYS_PATH_MAX + 1u, &required);
|
|
if (status != NTLSTATUS_SUCCESS || required == 0 || required > SYS_PATH_MAX + 1u)
|
|
fail_status("get cwd", status);
|
|
}
|
|
|
|
static void set_cwd_or_fail(const char* path, const char* what) {
|
|
KSTATUS status = NtlSetCurrentDirectory(SysSvFromCstr(path));
|
|
if (status != NTLSTATUS_SUCCESS) fail_status(what, status);
|
|
}
|
|
|
|
static void expect_cwd(const char* expected) {
|
|
char current[SYS_PATH_MAX + 1u];
|
|
get_cwd_or_fail(current);
|
|
if (strcmp(current, expected) != 0) fail("cwd value mismatch");
|
|
}
|
|
|
|
// Resolves the current absolute resource path and returns the owning namespace-prefix length.
|
|
static size_t resource_root_length_or_fail(const char* cwd) {
|
|
SYS_HANDLE session = SYS_HANDLE_INVALID;
|
|
KSTATUS status = NtlResourceConnect(&session);
|
|
if (status != NTLSTATUS_SUCCESS) fail_status("resource connect", status);
|
|
|
|
SYS_HANDLE root = SYS_HANDLE_INVALID;
|
|
uint32_t kind = NTL_RESOURCE_KIND_INVALID;
|
|
uint32_t resolvedLength = 0;
|
|
status = NtlResourceResolve(session, SysSvFromCstr(cwd), NTL_RESOURCE_FLAG_NONE,
|
|
&root, &kind, &resolvedLength);
|
|
(void)NtlResourceClose(session);
|
|
if (root != SYS_HANDLE_INVALID) (void)SysCloseHandle(root);
|
|
if (status != NTLSTATUS_SUCCESS) fail_status("resolve cwd root", status);
|
|
|
|
size_t length = strlen(cwd);
|
|
if (kind == NTL_RESOURCE_KIND_INVALID || resolvedLength < 2u || resolvedLength > length ||
|
|
(resolvedLength != length && cwd[resolvedLength] != '/'))
|
|
fail("initial cwd malformed");
|
|
return resolvedLength;
|
|
}
|
|
|
|
static void parent_of_cwd(const char* cwd, size_t rootLength, char* out, size_t cap) {
|
|
size_t length = strlen(cwd);
|
|
if (rootLength < 2u || rootLength > length || length + 1u > cap ||
|
|
(rootLength != length && cwd[rootLength] != '/'))
|
|
fail("initial cwd malformed");
|
|
|
|
memcpy(out, cwd, length + 1u);
|
|
if (length == rootLength) return;
|
|
while (length > rootLength && out[length - 1u] == '/') out[--length] = '\0';
|
|
while (length > rootLength && out[length - 1u] != '/') length--;
|
|
if (length <= rootLength + 1u) length = rootLength;
|
|
else length--;
|
|
out[length] = '\0';
|
|
}
|
|
|
|
int main(void) {
|
|
char original[SYS_PATH_MAX + 1u];
|
|
char parent[SYS_PATH_MAX + 1u];
|
|
char root[SYS_PATH_MAX + 1u];
|
|
|
|
print("cwd_userspace_smoke: start\n");
|
|
get_cwd_or_fail(original);
|
|
size_t rootLength = resource_root_length_or_fail(original);
|
|
parent_of_cwd(original, rootLength, parent, sizeof(parent));
|
|
memcpy(root, original, rootLength);
|
|
root[rootLength] = '\0';
|
|
|
|
// Refresh the cached binding boundary without changing the path.
|
|
set_cwd_or_fail(".", "set dot cwd");
|
|
expect_cwd(original);
|
|
|
|
set_cwd_or_fail("..", "set parent cwd");
|
|
expect_cwd(parent);
|
|
|
|
// Relative traversal stops at the actual bound resource, including multi-component roots.
|
|
set_cwd_or_fail(root, "set resource root cwd");
|
|
expect_cwd(root);
|
|
set_cwd_or_fail("..", "clamp parent at resource root");
|
|
expect_cwd(root);
|
|
|
|
set_cwd_or_fail(original, "restore original cwd");
|
|
expect_cwd(original);
|
|
|
|
print("cwd_userspace_smoke: PASS\n");
|
|
exit_now(0);
|
|
return 0;
|
|
}
|