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