104 lines
3.1 KiB
C
104 lines
3.1 KiB
C
// Protected-process smoke test.
|
|
// Verifies that kernel-owned processes remain queryable but cannot be terminated.
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <ntlite/syscall.h>
|
|
|
|
#define MAX_PROCESSES 16u
|
|
|
|
// Prints one NUL-terminated string to the console.
|
|
static void print(const char* text) {
|
|
SYS_WRITE_CONSOLE_REQUEST request = { SysSvFromCstr(text) };
|
|
(void)SysWriteConsole(&request);
|
|
}
|
|
|
|
// Prints one unsigned integer to the console.
|
|
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 = { SysSvFromParts(&digit, 1) };
|
|
(void)SysWriteConsole(&request);
|
|
}
|
|
}
|
|
|
|
// Terminates the current test process.
|
|
static void exit_now(int32_t code) {
|
|
for (;;) (void)SysExitProcess(code);
|
|
}
|
|
|
|
// Fails the test with one status value.
|
|
static void fail_status(const char* operation, uint32_t 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;
|
|
uint32_t status = SysOpenProcess(process->ProcessId, &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;
|
|
uint32_t status = SysGetProcessList(processes, MAX_PROCESSES, &count);
|
|
if (status != NTLSTATUS_SUCCESS)
|
|
fail_status("query process list", status);
|
|
|
|
int sawIdle = 0;
|
|
int sawSystem = 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];
|
|
if (!(process->Flags & (SYS_PROCESS_FLAG_IDLE | SYS_PROCESS_FLAG_SYSTEM)))
|
|
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 (!sawIdle || !sawSystem)
|
|
fail_status("missing kernel process", (uint32_t)((sawIdle ? 1u : 0u) | (sawSystem ? 2u : 0u)));
|
|
|
|
print("process_protection_smoke: PASS\n");
|
|
exit_now(0);
|
|
}
|