[PATCH 2/4] ntdll: Avoid taking loader lock in LdrGetProcedureAddress().
Paul Gofman
pgofman at codeweavers.com
Fri Oct 30 07:34:36 CDT 2020
Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
dlls/kernel32/tests/loader.c | 70 ++++++++++++++++++++++++++++++++++++
dlls/ntdll/loader.c | 4 +--
2 files changed, 72 insertions(+), 2 deletions(-)
diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c
index 67fd62ef6aa..5d8991bf0f0 100644
--- a/dlls/kernel32/tests/loader.c
+++ b/dlls/kernel32/tests/loader.c
@@ -70,6 +70,7 @@ static NTSTATUS (WINAPI *pLdrLockLoaderLock)(ULONG, ULONG *, ULONG_PTR *);
static NTSTATUS (WINAPI *pLdrUnlockLoaderLock)(ULONG, ULONG_PTR);
static NTSTATUS (WINAPI *pLdrLoadDll)(LPCWSTR,DWORD,const UNICODE_STRING *,HMODULE*);
static NTSTATUS (WINAPI *pLdrUnloadDll)(HMODULE);
+static NTSTATUS (WINAPI *pLdrGetProcedureAddress)(HMODULE, const ANSI_STRING *, ULONG, void **);
static void (WINAPI *pRtlInitUnicodeString)(PUNICODE_STRING,LPCWSTR);
static void (WINAPI *pRtlAcquirePebLock)(void);
static void (WINAPI *pRtlReleasePebLock)(void);
@@ -3992,6 +3993,73 @@ static void test_LoadPackagedLibrary(void)
h, GetLastError());
}
+static HANDLE test_loader_lock_event, test_loader_lock_test_done_event;
+
+static DWORD WINAPI test_loader_lock_thread(void *param)
+{
+ NTSTATUS status;
+ ULONG_PTR magic;
+ DWORD ret;
+
+ status = pLdrLockLoaderLock(0, NULL, &magic);
+ ok(!status, "Got unexpected status %#x.\n", status);
+ pRtlAcquirePebLock();
+ SetEvent(test_loader_lock_event);
+
+ ret = WaitForSingleObject(test_loader_lock_test_done_event, 2000);
+ ok(ret == WAIT_OBJECT_0 || broken(ret == WAIT_TIMEOUT) /* before Win8 */,
+ "Got unexpected ret %#x.\n", ret);
+ pRtlReleasePebLock();
+ status = pLdrUnlockLoaderLock(0, magic);
+ ok(!status, "Got unexpected status %#x.\n", status);
+
+ return 0;
+}
+
+static void test_loader_lock_scope(void)
+{
+ ANSI_STRING name;
+ HMODULE hmodule;
+ ULONG_PTR magic;
+ NTSTATUS status;
+ HANDLE hthread;
+ void *address;
+ ULONG result;
+ DWORD ret;
+
+ if (!pRtlAcquirePebLock || !pLdrLockLoaderLock)
+ {
+ win_skip("RtlAcquirePebLock or LdrLockLoaderLock is not available.\n");
+ return;
+ }
+
+ test_loader_lock_event = CreateEventA(NULL, FALSE, FALSE, NULL);
+ test_loader_lock_test_done_event = CreateEventA(NULL, FALSE, FALSE, NULL);
+
+ hmodule = GetModuleHandleA("ntdll.dll");
+ ok(!!hmodule, "Got NULL hmodule.\n");
+
+ hthread = CreateThread(NULL, 0, test_loader_lock_thread, NULL, 0, NULL);
+ ok(!!hthread, "Thread creation failed.\n");
+
+ ret = WaitForSingleObject(test_loader_lock_event, INFINITE);
+ ok(ret == WAIT_OBJECT_0, "Got unexpected ret %#x.\n", ret);
+
+ result = 0xdeadbeef;
+ status = pLdrLockLoaderLock(2, &result, &magic);
+ ok(!status && result == 2, "Got unexpected status %#x, result %#x,\n", status, result);
+
+ RtlInitAnsiString(&name, "LdrLockLoaderLock");
+ address = (void *)0xdeadbeef;
+ /* Locks up on loader lock before Win7. */
+ status = pLdrGetProcedureAddress(hmodule, &name, 0, &address);
+ ok(!status && address == pLdrLockLoaderLock, "Got unexpected status %#x, address %p.\n", status, address);
+
+ SetEvent(test_loader_lock_test_done_event);
+ ret = WaitForSingleObject(hthread, INFINITE);
+ ok(ret == WAIT_OBJECT_0, "Got unexpected ret %#x.\n", ret);
+}
+
START_TEST(loader)
{
int argc;
@@ -4016,6 +4084,7 @@ START_TEST(loader)
pLdrUnlockLoaderLock = (void *)GetProcAddress(ntdll, "LdrUnlockLoaderLock");
pLdrLoadDll = (void *)GetProcAddress(ntdll, "LdrLoadDll");
pLdrUnloadDll = (void *)GetProcAddress(ntdll, "LdrUnloadDll");
+ pLdrGetProcedureAddress = (void *)GetProcAddress(ntdll, "LdrGetProcedureAddress");
pRtlInitUnicodeString = (void *)GetProcAddress(ntdll, "RtlInitUnicodeString");
pRtlAcquirePebLock = (void *)GetProcAddress(ntdll, "RtlAcquirePebLock");
pRtlReleasePebLock = (void *)GetProcAddress(ntdll, "RtlReleasePebLock");
@@ -4068,6 +4137,7 @@ START_TEST(loader)
test_dll_file( "kernel32.dll" );
test_dll_file( "advapi32.dll" );
test_dll_file( "user32.dll" );
+ test_loader_lock_scope();
/* loader test must be last, it can corrupt the internal loader state on Windows */
test_Loader();
}
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
index 15690524b63..9048885d803 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -1752,7 +1752,7 @@ NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE module, const ANSI_STRING *name,
DWORD exp_size;
NTSTATUS ret = STATUS_PROCEDURE_NOT_FOUND;
- RtlEnterCriticalSection( &loader_section );
+ lock_ldr_data();
/* check if the module itself is invalid to return the proper error */
if (!get_modref( module )) ret = STATUS_DLL_NOT_FOUND;
@@ -1769,7 +1769,7 @@ NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE module, const ANSI_STRING *name,
}
}
- RtlLeaveCriticalSection( &loader_section );
+ unlock_ldr_data();
return ret;
}
--
2.28.0
More information about the wine-devel
mailing list