// Native handle duplication smoke test. // Verifies explicit rights reduction, same-rights duplication, and invalid duplicate requests. #include #include #include typedef struct TEST_QUEUE_MESSAGE { uint32_t Type; uint32_t Flags; uint64_t Param[6]; } TEST_QUEUE_MESSAGE; typedef char TEST_QUEUE_MESSAGE_SIZE_CHECK[ (sizeof(TEST_QUEUE_MESSAGE) == SYS_QUEUE_MESSAGE_SIZE) ? 1 : -1 ]; // Prints one NUL-terminated string to the kernel console. static void print(const char* s) { SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromCstr(s) }; SysWriteConsole(&req); } // Prints one unsigned integer to the kernel console. static void print_u64(uint64_t v) { char buf[32]; int i = 0; if (v == 0) { print("0"); return; } while (v && i < (int)sizeof(buf)) { buf[i++] = (char)('0' + (v % 10)); v /= 10; } while (i--) { char c = buf[i]; SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromParts(&c, 1) }; SysWriteConsole(&req); } } // Terminates the current test process. static void exit_now(int code) { while (true) SysExitProcess(code); } // Fails the test with one plain message. static void fail(const char* msg) { print("handle_dup_smoke: "); print(msg); print("\n"); exit_now(1); } // Fails the test with one status value. static void fail_status(const char* what, uint32_t status) { print("handle_dup_smoke: "); print(what); print(" status="); print_u64(status); print("\n"); exit_now(1); } // Requires one exact status value. static void expect_status(const char* what, uint32_t got, uint32_t expected) { if (got == expected) return; print("handle_dup_smoke: "); print(what); print(" got="); print_u64(got); print(" expected="); print_u64(expected); print("\n"); exit_now(1); } // Duplicates one handle into the current process. static uint32_t duplicate_handle(uint32_t source, uint32_t process, uint32_t desiredRights, uint32_t flags, uint32_t* out) { SYS_DUPLICATE_HANDLE_REQUEST req = { source, process, desiredRights, flags, out, }; return SysDuplicateHandle(&req); } // Sends one queue message. static uint32_t send_message(uint32_t queue, uint32_t type, uint64_t value) { TEST_QUEUE_MESSAGE msg = {0}; msg.Type = type; msg.Param[0] = value; SYS_QUEUE_SEND_REQUEST req = { sizeof(req), queue, SYS_QUEUE_FLAG_NONE, 0, &msg, }; return SysSendQueue(&req); } // Receives one queue message. static uint32_t recv_message(uint32_t queue, TEST_QUEUE_MESSAGE* msg) { SYS_QUEUE_RECV_REQUEST req = { sizeof(req), queue, SYS_QUEUE_FLAG_NONE, 0, msg, }; return SysRecvQueue(&req); } // Verifies one received queue message. static void check_message(const TEST_QUEUE_MESSAGE* msg, uint32_t type, uint64_t value) { if (msg->Type != type || msg->Param[0] != value) fail("message payload mismatch"); } // Runs the native handle duplication smoke test. int main(void) { print("handle_dup_smoke: start\n"); uint32_t currentPid = SysGetCurrentPid(); uint32_t process = 0; uint32_t s = SysOpenProcess(currentPid, &process); if (s != NTLSTATUS_SUCCESS) fail_status("open current process", s); uint32_t queue = 0; s = SysCreateQueue(&queue); if (s != NTLSTATUS_SUCCESS) fail_status("create queue", s); uint32_t readOnly = 0; s = duplicate_handle(queue, process, SYS_HANDLE_RIGHT_READ, SYS_DUPLICATE_HANDLE_FLAG_NONE, &readOnly); if (s != NTLSTATUS_SUCCESS) fail_status("duplicate read-only", s); uint32_t writeOnly = 0; s = duplicate_handle(queue, process, SYS_HANDLE_RIGHT_WRITE, SYS_DUPLICATE_HANDLE_FLAG_NONE, &writeOnly); if (s != NTLSTATUS_SUCCESS) fail_status("duplicate write-only", s); uint32_t sameRights = 0; s = duplicate_handle(queue, process, 0, SYS_DUPLICATE_HANDLE_FLAG_SAME_RIGHTS, &sameRights); if (s != NTLSTATUS_SUCCESS) fail_status("duplicate same rights", s); s = send_message(readOnly, 10, 100); if (s == NTLSTATUS_SUCCESS) fail("read-only duplicate allowed send"); TEST_QUEUE_MESSAGE msg; s = recv_message(writeOnly, &msg); if (s == NTLSTATUS_SUCCESS) fail("write-only duplicate allowed receive"); s = send_message(queue, 11, 101); if (s != NTLSTATUS_SUCCESS) fail_status("send original", s); s = recv_message(readOnly, &msg); if (s != NTLSTATUS_SUCCESS) fail_status("receive read-only", s); check_message(&msg, 11, 101); s = send_message(writeOnly, 12, 102); if (s != NTLSTATUS_SUCCESS) fail_status("send write-only", s); s = recv_message(queue, &msg); if (s != NTLSTATUS_SUCCESS) fail_status("receive original", s); check_message(&msg, 12, 102); s = send_message(sameRights, 13, 103); if (s != NTLSTATUS_SUCCESS) fail_status("send same-rights", s); s = recv_message(sameRights, &msg); if (s != NTLSTATUS_SUCCESS) fail_status("receive same-rights", s); check_message(&msg, 13, 103); uint32_t ignored = 0; s = duplicate_handle(readOnly, process, SYS_HANDLE_RIGHT_READ, SYS_DUPLICATE_HANDLE_FLAG_NONE, &ignored); expect_status("duplicate non-duplicable handle", s, NTLSTATUS_ACCESS_DENIED); s = duplicate_handle(queue, process, SYS_HANDLE_RIGHT_READ | 0x80000000u, SYS_DUPLICATE_HANDLE_FLAG_NONE, &ignored); expect_status("duplicate unknown rights", s, NTLSTATUS_INVALID_PARAMETER); s = duplicate_handle(queue, process, SYS_HANDLE_RIGHT_READ, SYS_DUPLICATE_HANDLE_FLAG_SAME_RIGHTS, &ignored); expect_status("duplicate same-rights with desired rights", s, NTLSTATUS_INVALID_PARAMETER); s = duplicate_handle(queue, process, 0, SYS_DUPLICATE_HANDLE_FLAG_NONE, &ignored); expect_status("duplicate zero rights", s, NTLSTATUS_INVALID_PARAMETER); SYS_DUPLICATE_HANDLE_REQUEST badOut = { queue, process, SYS_HANDLE_RIGHT_READ, SYS_DUPLICATE_HANDLE_FLAG_NONE, 0, }; s = SysDuplicateHandle(&badOut); expect_status("duplicate null output", s, NTLSTATUS_INVALID_PARAMETER); SysCloseHandle(sameRights); SysCloseHandle(writeOnly); SysCloseHandle(readOnly); SysCloseHandle(queue); SysCloseHandle(process); print("handle_dup_smoke: PASS\n"); exit_now(0); return 0; }