Files
nt-lite/code/user/tests/resource_service_smoke/resource_service_smoke.c
T

231 lines
11 KiB
C

// Resource-service smoke test. Proves public RSSRV lookup is capability-based and namespace administration is private.
#include <ntlite/resource.h>
#include <ntlite/syscall.h>
#include <ntlite/path.h>
#include <stdint.h>
#include <string.h>
static void print(const char* text) {
SYS_WRITE_CONSOLE_REQUEST request = { sizeof(request), SysSvFromCstr(text) };
(void)SysWriteConsole(&request);
}
static int fail(const char* what, KSTATUS status) {
(void)status;
print("resource_service_smoke: FAIL ");
print(what);
print("\n");
return 1;
}
int main(void) {
SYS_HANDLE session = SYS_HANDLE_INVALID;
KSTATUS status = NtlResourceConnect(&session);
if (!KSUCCESS(status)) return fail("connect", status);
uint32_t kind = NTL_RESOURCE_KIND_INVALID;
status = NtlResourceQuery(session, SYS_SV_LITERAL("/"), &kind);
if (!KSUCCESS(status) || kind != NTL_RESOURCE_KIND_NAMESPACE_DIRECTORY)
return fail("query namespace root", status);
status = NtlResourceQuery(session, SYS_SV_LITERAL("/Device"), &kind);
if (!KSUCCESS(status) || kind != NTL_RESOURCE_KIND_NAMESPACE_DIRECTORY)
return fail("query /Device", status);
status = NtlResourceQuery(session, SYS_SV_LITERAL("/SystemRoot"), &kind);
if (!KSUCCESS(status) || kind != NTL_RESOURCE_KIND_SYMBOLIC_LINK)
return fail("query /SystemRoot link", status);
// Root enumeration exposes namespace directories and symbolic links without transferring authority.
NTL_RESOURCE_ENUM_CURSOR rootCursor;
memset(&rootCursor, 0, sizeof(rootCursor));
uint32_t sawDevice = 0;
uint32_t sawSessions = 0;
uint32_t sawServices = 0;
uint32_t sawSystemRoot = 0;
for (;;) {
NTL_RESOURCE_ENUM_ENTRY entry;
status = NtlResourceEnumerate(session, SYS_SV_LITERAL("/"), &rootCursor, &entry);
if (status == NTLSTATUS_NO_MORE_FILES) break;
if (!KSUCCESS(status)) return fail("enumerate namespace root", status);
if (strcmp(entry.Name, "Device") == 0 && entry.Kind == NTL_RESOURCE_KIND_NAMESPACE_DIRECTORY) sawDevice = 1;
if (strcmp(entry.Name, "Sessions") == 0 && entry.Kind == NTL_RESOURCE_KIND_NAMESPACE_DIRECTORY) sawSessions = 1;
if (strcmp(entry.Name, "Services") == 0 && entry.Kind == NTL_RESOURCE_KIND_NAMESPACE_DIRECTORY) sawServices = 1;
if (strcmp(entry.Name, "SystemRoot") == 0 && entry.Kind == NTL_RESOURCE_KIND_SYMBOLIC_LINK) sawSystemRoot = 1;
}
if (!sawDevice || !sawSessions || !sawServices || !sawSystemRoot)
return fail("root enumeration contents", NTLSTATUS_NOT_FOUND);
// RSSRV assigns its own monotonic /Device/HarddiskVolumeN names to mounted IO_VOLUME instances.
uint32_t publishedVolumes = 0;
uint32_t systemVolumePublished = 0;
NTL_RESOURCE_ENUM_CURSOR deviceCursor;
memset(&deviceCursor, 0, sizeof(deviceCursor));
for (;;) {
NTL_RESOURCE_ENUM_ENTRY entry;
status = NtlResourceEnumerate(session, SYS_SV_LITERAL("/Device"), &deviceCursor, &entry);
if (status == NTLSTATUS_NO_MORE_FILES) break;
if (!KSUCCESS(status)) return fail("enumerate /Device", status);
if (entry.Kind != NTL_RESOURCE_KIND_VOLUME || strncmp(entry.Name, "HarddiskVolume", 14) != 0)
continue;
char volumePathBuffer[48];
size_t nameLength = strlen(entry.Name);
if (sizeof("/Device/") - 1u + nameLength + 1u > sizeof(volumePathBuffer))
return fail("dynamic volume name too long", NTLSTATUS_FAILURE);
memcpy(volumePathBuffer, "/Device/", sizeof("/Device/") - 1u);
memcpy(volumePathBuffer + sizeof("/Device/") - 1u, entry.Name, nameLength + 1u);
SYS_STRING_VIEW volumePath = SysSvFromCstr(volumePathBuffer);
SYS_HANDLE published = SYS_HANDLE_INVALID;
status = NtlResourceLookup(session, volumePath, SYS_RIGHT_QUERY | SYS_VOLUME_RIGHT_OPEN, &published);
if (!KSUCCESS(status))
return fail("lookup enumerated volume", status);
publishedVolumes++;
SYS_HANDLE probe = SYS_HANDLE_INVALID;
SYS_OPEN_FILE_AT_REQUEST probeOpen;
memset(&probeOpen, 0, sizeof(probeOpen));
probeOpen.Size = sizeof(probeOpen);
probeOpen.RootHandle = published;
probeOpen.Path = SYS_SV_LITERAL("system/init.exe");
probeOpen.Access = SYS_FILE_ACCESS_READ | SYS_FILE_ACCESS_QUERY;
probeOpen.Disposition = SYS_FILE_OPEN_EXISTING;
probeOpen.Flags = SYS_FILE_FLAG_NONE;
probeOpen.HandleOut = &probe;
KSTATUS probeStatus = SysOpenFileAt(&probeOpen);
if (KSUCCESS(probeStatus)) {
systemVolumePublished = 1;
(void)SysCloseHandle(probe);
} else if (probeStatus != NTLSTATUS_NOT_FOUND) {
(void)SysCloseHandle(published);
return fail("probe dynamic volume", probeStatus);
}
(void)SysCloseHandle(published);
}
if (!publishedVolumes || !systemVolumePublished)
return fail("dynamic volume publication", NTLSTATUS_NOT_FOUND);
SYS_HANDLE volume = SYS_HANDLE_INVALID;
status = NtlResourceLookup(session, SYS_SV_LITERAL("/SystemRoot"),
SYS_RIGHT_QUERY | SYS_VOLUME_RIGHT_OPEN, &volume);
if (!KSUCCESS(status)) return fail("lookup /SystemRoot", status);
SYS_HANDLE file = SYS_HANDLE_INVALID;
SYS_OPEN_FILE_AT_REQUEST open;
memset(&open, 0, sizeof(open));
open.Size = sizeof(open);
open.RootHandle = volume;
open.Path = SYS_SV_LITERAL("system/init.exe");
open.Access = SYS_FILE_ACCESS_READ | SYS_FILE_ACCESS_QUERY;
open.Disposition = SYS_FILE_OPEN_EXISTING;
open.Flags = SYS_FILE_FLAG_NONE;
open.HandleOut = &file;
status = SysOpenFileAt(&open);
if (!KSUCCESS(status)) return fail("open through resource volume", status);
(void)SysCloseHandle(file);
(void)SysCloseHandle(volume);
// RESOLVE returns the longest bound resource prefix and leaves only a relative tail for I/O.
SYS_HANDLE resolvedRoot = SYS_HANDLE_INVALID;
uint32_t resolvedLength = 0;
status = NtlResourceResolve(session, SYS_SV_LITERAL("/SystemRoot/system/init.exe"),
NTL_RESOURCE_FLAG_NONE, &resolvedRoot, &kind, &resolvedLength);
if (!KSUCCESS(status) || kind != NTL_RESOURCE_KIND_VOLUME ||
resolvedLength != sizeof("/SystemRoot") - 1u)
return fail("resolve longest prefix", status);
file = SYS_HANDLE_INVALID;
memset(&open, 0, sizeof(open));
open.Size = sizeof(open);
open.RootHandle = resolvedRoot;
open.Path = SYS_SV_LITERAL("system/init.exe");
open.Access = SYS_FILE_ACCESS_READ | SYS_FILE_ACCESS_QUERY;
open.Disposition = SYS_FILE_OPEN_EXISTING;
open.Flags = SYS_FILE_FLAG_NONE;
open.HandleOut = &file;
status = SysOpenFileAt(&open);
if (!KSUCCESS(status)) return fail("open through resolved prefix", status);
(void)SysCloseHandle(file);
(void)SysCloseHandle(resolvedRoot);
// MODIFY resolution returns write authority without exporting RSSRV's private TRANSFER right.
resolvedRoot = SYS_HANDLE_INVALID;
resolvedLength = 0;
status = NtlResourceResolve(session, SYS_SV_LITERAL("/SystemRoot/tests/resource_f.tmp"),
NTL_RESOURCE_RESOLVE_FLAG_MODIFY,
&resolvedRoot, &kind, &resolvedLength);
if (!KSUCCESS(status) || kind != NTL_RESOURCE_KIND_VOLUME ||
resolvedLength != sizeof("/SystemRoot") - 1u)
return fail("resolve modify authority", status);
file = SYS_HANDLE_INVALID;
memset(&open, 0, sizeof(open));
open.Size = sizeof(open);
open.RootHandle = resolvedRoot;
open.Path = SYS_SV_LITERAL("tests/resource_f.tmp");
open.Access = SYS_FILE_ACCESS_WRITE | SYS_FILE_ACCESS_QUERY;
open.Disposition = SYS_FILE_CREATE_ALWAYS;
open.Flags = SYS_FILE_FLAG_NONE;
open.HandleOut = &file;
status = SysOpenFileAt(&open);
if (!KSUCCESS(status)) return fail("create through resolved modify root", status);
(void)SysCloseHandle(file);
SYS_PATH_AT_REQUEST remove = { sizeof(remove), resolvedRoot, SYS_SV_LITERAL("tests/resource_f.tmp") };
status = SysDeleteAt(&remove);
if (!KSUCCESS(status)) return fail("delete through resolved modify root", status);
(void)SysCloseHandle(resolvedRoot);
SYS_HANDLE overbroad = SYS_HANDLE_INVALID;
status = NtlResourceLookup(session, SYS_SV_LITERAL("/SystemRoot"),
SYS_RIGHT_QUERY | SYS_RIGHT_TRANSFER | SYS_VOLUME_RIGHT_OPEN, &overbroad);
if (status != NTLSTATUS_ACCESS_DENIED || overbroad != SYS_HANDLE_INVALID)
return fail("export-rights ceiling", status);
SYS_HANDLE missing = SYS_HANDLE_INVALID;
status = NtlResourceLookup(session, SYS_SV_LITERAL("/Missing"), SYS_RIGHT_QUERY, &missing);
if (status != NTLSTATUS_NOT_FOUND || missing != SYS_HANDLE_INVALID)
return fail("missing lookup", status);
SYS_HANDLE event = SYS_HANDLE_INVALID;
status = SysCreateEvent(0, 0, &event);
if (!KSUCCESS(status)) return fail("create bind probe", status);
status = NtlResourceBind(session, SYS_SV_LITERAL("/PublicBindMustFail"),
NTL_RESOURCE_KIND_CAPABILITY, event,
SYS_RIGHT_TRANSFER | SYS_RIGHT_QUERY, SYS_RIGHT_QUERY);
(void)SysCloseHandle(event);
if (status != NTLSTATUS_ACCESS_DENIED)
return fail("public bind authority", status);
status = NtlResourceQuery(session, SYS_SV_LITERAL("/PublicBindMustFail"), &kind);
if (status != NTLSTATUS_NOT_FOUND)
return fail("rejected bind visibility", status);
// Well-formed multibyte identities are accepted as paths without normalization.
static const char validPath[] = { '/', 'X', (char)0xC3, (char)0xA9 };
status = NtlResourceQuery(session, SysSvFromParts(validPath, sizeof(validPath)), &kind);
if (status != NTLSTATUS_NOT_FOUND)
return fail("valid UTF-8 namespace path rejected", status);
// Namespace identities are UTF-8 byte strings, never arbitrary byte paths.
static const char invalidPath[] = { '/', 'B', 'a', 'd', (char)0xED, (char)0xA0, (char)0x80 };
status = NtlResourceQuery(session, SysSvFromParts(invalidPath, sizeof(invalidPath)), &kind);
if (status != NTLSTATUS_INVALID_PARAMETER)
return fail("malformed UTF-8 namespace path accepted", status);
static const char embeddedNulPath[] = { '/', 'A', 0, 'B' };
status = NtlResourceQuery(session, SysSvFromParts(embeddedNulPath, sizeof(embeddedNulPath)), &kind);
if (status != NTLSTATUS_INVALID_PARAMETER)
return fail("embedded NUL namespace path accepted", status);
status = NtlResourceQuery(session, SYS_SV_LITERAL("/SystemRoot/../Bad"), &kind);
if (status != NTLSTATUS_INVALID_PARAMETER)
return fail("canonical path rejection", status);
status = NtlResourceClose(session);
if (!KSUCCESS(status)) return fail("close session", status);
print("resource_service_smoke: PASS\n");
return 0;
}