Jinoh Kang : ntdll/tests: Add tests for DebugPort* info query with security checks.
Alexandre Julliard
julliard at winehq.org
Thu Dec 9 15:34:27 CST 2021
Module: wine
Branch: master
Commit: ee4d38c3b1daced5c956e651edf57026118e17de
URL: https://source.winehq.org/git/wine.git/?a=commit;h=ee4d38c3b1daced5c956e651edf57026118e17de
Author: Jinoh Kang <jinoh.kang.kr at gmail.com>
Date: Wed Dec 8 00:27:50 2021 +0900
ntdll/tests: Add tests for DebugPort* info query with security checks.
Signed-off-by: Jinoh Kang <jinoh.kang.kr at gmail.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/ntdll/tests/info.c | 171 +++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 170 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c
index b16fa4da22f..9d446c0f872 100644
--- a/dlls/ntdll/tests/info.c
+++ b/dlls/ntdll/tests/info.c
@@ -46,6 +46,8 @@ static NTSTATUS (WINAPI * pNtQueryObject)(HANDLE, OBJECT_INFORMATION_CLASS, void
static NTSTATUS (WINAPI * pNtCreateDebugObject)( HANDLE *, ACCESS_MASK, OBJECT_ATTRIBUTES *, ULONG );
static NTSTATUS (WINAPI * pNtSetInformationDebugObject)(HANDLE,DEBUGOBJECTINFOCLASS,PVOID,ULONG,ULONG*);
static NTSTATUS (WINAPI * pDbgUiConvertStateChangeStructure)(DBGUI_WAIT_STATE_CHANGE*,DEBUG_EVENT*);
+static HANDLE (WINAPI * pDbgUiGetThreadDebugObject)(void);
+static void (WINAPI * pDbgUiSetThreadDebugObject)(HANDLE);
static BOOL is_wow64;
@@ -99,6 +101,8 @@ static void InitFunctionPtrs(void)
NTDLL_GET_PROC(NtSetInformationDebugObject);
NTDLL_GET_PROC(NtGetCurrentProcessorNumber);
NTDLL_GET_PROC(DbgUiConvertStateChangeStructure);
+ NTDLL_GET_PROC(DbgUiGetThreadDebugObject);
+ NTDLL_GET_PROC(DbgUiSetThreadDebugObject);
pIsWow64Process = (void *)GetProcAddress(hkernel32, "IsWow64Process");
if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
@@ -2027,6 +2031,127 @@ static void test_query_process_debug_port(int argc, char **argv)
ok(ret, "CloseHandle failed, last error %#x.\n", GetLastError());
}
+static void subtest_query_process_debug_port_custom_dacl(int argc, char **argv, ACCESS_MASK access, PSID sid)
+{
+ HANDLE old_debug_obj, debug_obj;
+ OBJECT_ATTRIBUTES attr;
+ SECURITY_DESCRIPTOR sd;
+ union {
+ ACL acl;
+ DWORD buffer[(sizeof(ACL) +
+ (offsetof(ACCESS_ALLOWED_ACE, SidStart) + SECURITY_MAX_SID_SIZE) +
+ sizeof(DWORD) - 1) / sizeof(DWORD)];
+ } acl;
+ char cmdline[MAX_PATH];
+ PROCESS_INFORMATION pi;
+ STARTUPINFOA si;
+ DEBUG_EVENT ev;
+ NTSTATUS status;
+ BOOL ret;
+
+ InitializeAcl(&acl.acl, sizeof(acl), ACL_REVISION);
+ AddAccessAllowedAce(&acl.acl, ACL_REVISION, access, sid);
+ InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
+ SetSecurityDescriptorDacl(&sd, TRUE, &acl.acl, FALSE);
+
+ InitializeObjectAttributes(&attr, NULL, 0, NULL, &sd);
+ status = NtCreateDebugObject(&debug_obj, MAXIMUM_ALLOWED, &attr, DEBUG_KILL_ON_CLOSE);
+ ok(SUCCEEDED(status), "Failed to create debug object: %#010x\n", status);
+ if (!SUCCEEDED(status)) return;
+
+ old_debug_obj = pDbgUiGetThreadDebugObject();
+ pDbgUiSetThreadDebugObject(debug_obj);
+
+ sprintf(cmdline, "%s %s %s %u", argv[0], argv[1], "debuggee:dbgport", access);
+
+ memset(&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+ ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE,
+ DEBUG_PROCESS, NULL, NULL, &si, &pi);
+ ok(ret, "CreateProcess failed, last error %#x.\n", GetLastError());
+ if (!ret) goto close_debug_obj;
+
+ do
+ {
+ ret = WaitForDebugEvent(&ev, INFINITE);
+ ok(ret, "WaitForDebugEvent failed, last error %#x.\n", GetLastError());
+ if (!ret) break;
+
+ ret = ContinueDebugEvent(ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE);
+ ok(ret, "ContinueDebugEvent failed, last error %#x.\n", GetLastError());
+ if (!ret) break;
+ } while (ev.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT);
+
+ wait_child_process(pi.hProcess);
+ ret = CloseHandle(pi.hThread);
+ ok(ret, "CloseHandle failed, last error %#x.\n", GetLastError());
+ ret = CloseHandle(pi.hProcess);
+ ok(ret, "CloseHandle failed, last error %#x.\n", GetLastError());
+
+close_debug_obj:
+ pDbgUiSetThreadDebugObject(old_debug_obj);
+ NtClose(debug_obj);
+}
+
+static TOKEN_OWNER *get_current_owner(void)
+{
+ TOKEN_OWNER *owner;
+ ULONG length = 0;
+ HANDLE token;
+ BOOL ret;
+
+ ret = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token);
+ ok(ret, "Failed to get process token: %u\n", GetLastError());
+
+ ret = GetTokenInformation(token, TokenOwner, NULL, 0, &length);
+ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+ "GetTokenInformation failed: %u\n", GetLastError());
+ ok(length != 0, "Failed to get token owner information length: %u\n", GetLastError());
+
+ owner = HeapAlloc(GetProcessHeap(), 0, length);
+ ret = GetTokenInformation(token, TokenOwner, owner, length, &length);
+ ok(ret, "Failed to get token owner information: %u)\n", GetLastError());
+
+ CloseHandle(token);
+ return owner;
+}
+
+static void test_query_process_debug_port_custom_dacl(int argc, char **argv)
+{
+ static const ACCESS_MASK all_access_masks[] = {
+ GENERIC_ALL,
+ DEBUG_ALL_ACCESS,
+ STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE,
+ };
+ TOKEN_OWNER *owner;
+ int i;
+
+ if (!pDbgUiSetThreadDebugObject)
+ {
+ skip("DbgUiGetThreadDebugObject not found\n");
+ return;
+ }
+
+ if (!pDbgUiGetThreadDebugObject)
+ {
+ skip("DbgUiSetThreadDebugObject not found\n");
+ return;
+ }
+
+ owner = get_current_owner();
+
+ for (i = 0; i < ARRAY_SIZE(all_access_masks); i++)
+ {
+ ACCESS_MASK access = all_access_masks[i];
+
+ winetest_push_context("debug object access %08x", access);
+ subtest_query_process_debug_port_custom_dacl(argc, argv, access, owner->Owner);
+ winetest_pop_context();
+ }
+
+ HeapFree(GetProcessHeap(), 0, owner);
+}
+
static void test_query_process_priority(void)
{
PROCESS_PRIORITY_CLASS priority[2];
@@ -3374,6 +3499,45 @@ static void test_process_instrumentation_callback(void)
"Got unexpected status %#x.\n", status );
}
+static void test_debuggee_dbgport(int argc, char **argv)
+{
+ NTSTATUS status, expect_status;
+ DWORD_PTR debug_port = 0xdeadbeef;
+ DWORD debug_flags = 0xdeadbeef;
+ HANDLE handle;
+ ACCESS_MASK access;
+
+ if (argc < 2)
+ {
+ ok(0, "insufficient arguments for child process\n");
+ return;
+ }
+
+ access = strtoul(argv[1], NULL, 0);
+ winetest_push_context("debug object access %08x", access);
+
+ status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessDebugPort,
+ &debug_port, sizeof(debug_port), NULL );
+ todo_wine_if(access != DEBUG_ALL_ACCESS && access != GENERIC_ALL)
+ ok( !status, "NtQueryInformationProcess ProcessDebugPort failed, status %#x.\n", status );
+ todo_wine_if(access != DEBUG_ALL_ACCESS && access != GENERIC_ALL)
+ ok( debug_port == ~(DWORD_PTR)0, "Expected port %#lx, got %#lx.\n", ~(DWORD_PTR)0, debug_port );
+
+ status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessDebugFlags,
+ &debug_flags, sizeof(debug_flags), NULL );
+ todo_wine_if(access != DEBUG_ALL_ACCESS && access != GENERIC_ALL)
+ ok( !status, "NtQueryInformationProcess ProcessDebugFlags failed, status %#x.\n", status );
+
+ expect_status = access ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
+ status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessDebugObjectHandle,
+ &handle, sizeof(handle), NULL );
+ todo_wine_if(access != DEBUG_ALL_ACCESS && access != GENERIC_ALL)
+ ok( status == expect_status, "NtQueryInformationProcess ProcessDebugObjectHandle expected status %#x, actual %#x.\n", expect_status, status );
+ if (SUCCEEDED( status )) NtClose( handle );
+
+ winetest_pop_context();
+}
+
START_TEST(info)
{
char **argv;
@@ -3382,7 +3546,11 @@ START_TEST(info)
InitFunctionPtrs();
argc = winetest_get_mainargs(&argv);
- if (argc >= 3) return; /* Child */
+ if (argc >= 3)
+ {
+ if (strcmp(argv[2], "debuggee:dbgport") == 0) test_debuggee_dbgport(argc - 2, argv + 2);
+ return; /* Child */
+ }
/* NtQuerySystemInformation */
test_query_basic();
@@ -3416,6 +3584,7 @@ START_TEST(info)
test_query_process_vm();
test_query_process_times();
test_query_process_debug_port(argc, argv);
+ test_query_process_debug_port_custom_dacl(argc, argv);
test_query_process_priority();
test_query_process_handlecount();
test_query_process_wow64();
More information about the wine-cvs
mailing list