231 lines
11 KiB
C
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;
|
|
}
|