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

111 lines
3.6 KiB
C

// Protected-process smoke test.
// Verifies that kernel-owned processes remain queryable but cannot be terminated.
#include <stddef.h>
#include <string.h>
#include <stdint.h>
#include <ntlite/syscall.h>
#define MAX_PROCESSES 64u
static void print(const char* text) {
SYS_WRITE_CONSOLE_REQUEST request = { sizeof(SYS_WRITE_CONSOLE_REQUEST), SysSvFromCstr(text) };
(void)SysWriteConsole(&request);
}
static void print_u32(uint32_t value) {
char buffer[16];
size_t length = 0;
if (value == 0) {
print("0");
return;
}
while (value && length < sizeof(buffer)) {
buffer[length++] = (char)('0' + (value % 10u));
value /= 10u;
}
while (length) {
char digit = buffer[--length];
SYS_WRITE_CONSOLE_REQUEST request = { sizeof(SYS_WRITE_CONSOLE_REQUEST), SysSvFromParts(&digit, 1) };
(void)SysWriteConsole(&request);
}
}
static void exit_now(int32_t code) {
while (true) (void)SysExitProcess(code);
}
static void fail_status(const char* operation, KSTATUS status) {
print("process_protection_smoke: ");
print(operation);
print(" status=");
print_u32(status);
print("\n");
exit_now(1);
}
// Verifies one protected process remains alive after a kill attempt.
static void verify_protected_process(const SYS_PROCESS_INFO* process) {
uint32_t handle = 0;
KSTATUS status = SysOpenProcess(process->ProcessId, SYS_PROCESS_RIGHT_TERMINATE | SYS_RIGHT_WAIT | SYS_RIGHT_QUERY, &handle);
if (status != NTLSTATUS_SUCCESS)
fail_status("open protected process", status);
status = SysKillProcess(handle, (int32_t)NTLSTATUS_PROCESS_KILLED);
if (status != NTLSTATUS_ACCESS_DENIED) {
SysCloseHandle(handle);
fail_status("kill protected process", status);
}
status = SysWaitSingle(handle, SYS_WAIT_FLAG_NONE, 0);
SysCloseHandle(handle);
if (status != NTLSTATUS_TIMEOUT)
fail_status("protected process remained signaled", status);
}
// Runs the protected-process contract checks.
void main(void) {
print("process_protection_smoke: start\n");
SYS_PROCESS_INFO processes[MAX_PROCESSES];
size_t count = 0;
KSTATUS status = SysGetProcessList(processes, MAX_PROCESSES, &count);
if (status != NTLSTATUS_SUCCESS)
fail_status("query process list", status);
int sawIdle = 0;
int sawSystem = 0;
int sawInit = 0;
size_t limit = count < MAX_PROCESSES ? count : MAX_PROCESSES;
for (size_t i = 0; i < limit; i++) {
const SYS_PROCESS_INFO* process = &processes[i];
int isInit = strcmp(process->Name, "system/init.exe") == 0;
if (!(process->Flags & (SYS_PROCESS_FLAG_IDLE | SYS_PROCESS_FLAG_SYSTEM)) && !isInit)
continue;
if (!(process->Flags & SYS_PROCESS_FLAG_TERMINATION_PROTECTED))
fail_status("missing protected flag", process->ProcessId);
verify_protected_process(process);
if (process->Flags & SYS_PROCESS_FLAG_IDLE) sawIdle = 1;
if (process->Flags & SYS_PROCESS_FLAG_SYSTEM) sawSystem = 1;
if (isInit) sawInit = 1;
}
if (!sawIdle || !sawSystem || !sawInit)
fail_status("missing kernel process", (uint32_t)((sawIdle ? 1u : 0u) | (sawSystem ? 2u : 0u)));
uint32_t action = 0;
SYS_HANDLE event = SYS_HANDLE_INVALID;
if (SysOpenPowerEvent(&event) != NTLSTATUS_ACCESS_DENIED ||
SysQuerySystemPower(&action) != NTLSTATUS_ACCESS_DENIED ||
SysCompleteSystemPower(SYS_POWER_ACTION_SHUTDOWN) != NTLSTATUS_ACCESS_DENIED)
fail_status("power coordinator ownership", NTLSTATUS_FAILURE);
print("process_protection_smoke: PASS\n");
exit_now(0);
}