Add tests for various paths and undefined behavior with regards to LdrGetDllPath with LOAD_ALTERED_SEARCH_PATH and relative module names. Also update the build_search_path helper function to correctly build the search path when LOAD_WITH_ALTERED_SEARCH_PATH is set.
Signed-off-by: Nick Fox nick@foxsec.net --- v5: use helper function to duplicate less code per julliard's feedback --- dlls/kernel32/tests/path.c | 93 +++++++++++++++++++++++++++++++------- 1 file changed, 77 insertions(+), 16 deletions(-)
diff --git a/dlls/kernel32/tests/path.c b/dlls/kernel32/tests/path.c index f49af6d5bfe..2737910931c 100644 --- a/dlls/kernel32/tests/path.c +++ b/dlls/kernel32/tests/path.c @@ -2409,12 +2409,16 @@ static void test_SetSearchPathMode(void)
static const WCHAR pathW[] = {'P','A','T','H',0};
-static void build_search_path( WCHAR *buffer, UINT size, const WCHAR *dlldir, BOOL safe ) +static void build_search_path( const WCHAR *path, WCHAR *buffer, UINT size, const WCHAR *dlldir, BOOL safe, ULONG flags ) { WCHAR *p; - GetModuleFileNameW( NULL, buffer, size ); - if (!(p = wcsrchr( buffer, '\' ))) return; + if (path && (flags & LOAD_WITH_ALTERED_SEARCH_PATH) && (p = wcsrchr( path, L'\' ))) + lstrcpynW( buffer, path, p - path + 2 ); + else + GetModuleFileNameW( NULL, buffer, size ); + if (!(p = wcsrchr( buffer, L'\' ))) return; *p++ = ';'; + if (dlldir) { lstrcpyW( p, dlldir ); @@ -2471,7 +2475,7 @@ static void test_RtlGetSearchPath(void) GetWindowsDirectoryW( buffer, ARRAY_SIZE(buffer) ); lstrcpynW( dlldir, buffer, ARRAY_SIZE(dlldir) );
- build_search_path( buffer, ARRAY_SIZE(buffer), NULL, TRUE ); + build_search_path( NULL, buffer, ARRAY_SIZE(buffer), NULL, TRUE, 0 ); path = (WCHAR *)0xdeadbeef; ret = pRtlGetSearchPath( &path ); ok( !ret, "RtlGetSearchPath failed %x\n", ret ); @@ -2479,7 +2483,7 @@ static void test_RtlGetSearchPath(void) pRtlReleasePath( path );
SetEnvironmentVariableA( "PATH", "foo" ); - build_search_path( buffer, ARRAY_SIZE(buffer), NULL, TRUE ); + build_search_path( NULL, buffer, ARRAY_SIZE(buffer), NULL, TRUE, 0 ); path = (WCHAR *)0xdeadbeef; ret = pRtlGetSearchPath( &path ); ok( !ret, "RtlGetSearchPath failed %x\n", ret ); @@ -2489,7 +2493,7 @@ static void test_RtlGetSearchPath(void) if (pSetDllDirectoryW) { ok( pSetDllDirectoryW( dlldir ), "SetDllDirectoryW failed\n" ); - build_search_path( buffer, ARRAY_SIZE(buffer), NULL, TRUE ); + build_search_path( NULL, buffer, ARRAY_SIZE(buffer), NULL, TRUE, 0 ); path = (WCHAR *)0xdeadbeef; ret = pRtlGetSearchPath( &path ); ok( !ret, "RtlGetSearchPath failed %x\n", ret ); @@ -2520,14 +2524,14 @@ static void test_RtlGetExePath(void) lstrcpynW( dlldir, buffer, ARRAY_SIZE(dlldir) ); SetEnvironmentVariableA( "NoDefaultCurrentDirectoryInExePath", NULL );
- build_search_path( buffer, ARRAY_SIZE(buffer), NULL, FALSE ); + build_search_path( NULL, buffer, ARRAY_SIZE(buffer), NULL, FALSE, 0 ); path = (WCHAR *)0xdeadbeef; ret = pRtlGetExePath( fooW, &path ); ok( !ret, "RtlGetExePath failed %x\n", ret ); ok( path_equal( path, buffer ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(buffer)); pRtlReleasePath( path );
- build_search_path( buffer, ARRAY_SIZE(buffer), NULL, FALSE ); + build_search_path( NULL, buffer, ARRAY_SIZE(buffer), NULL, FALSE, 0 ); path = (WCHAR *)0xdeadbeef; ret = pRtlGetExePath( fooW + 1, &path ); ok( !ret, "RtlGetExePath failed %x\n", ret ); @@ -2536,14 +2540,14 @@ static void test_RtlGetExePath(void)
SetEnvironmentVariableA( "NoDefaultCurrentDirectoryInExePath", "yes" );
- build_search_path( buffer, ARRAY_SIZE(buffer), NULL, FALSE ); + build_search_path( NULL, buffer, ARRAY_SIZE(buffer), NULL, FALSE, 0 ); path = (WCHAR *)0xdeadbeef; ret = pRtlGetExePath( fooW, &path ); ok( !ret, "RtlGetExePath failed %x\n", ret ); ok( path_equal( path, buffer ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(buffer)); pRtlReleasePath( path );
- build_search_path( buffer, ARRAY_SIZE(buffer), emptyW, TRUE ); + build_search_path( NULL, buffer, ARRAY_SIZE(buffer), emptyW, TRUE, 0 ); path = (WCHAR *)0xdeadbeef; ret = pRtlGetExePath( fooW + 1, &path ); ok( !ret, "RtlGetExePath failed %x\n", ret ); @@ -2551,7 +2555,7 @@ static void test_RtlGetExePath(void) pRtlReleasePath( path );
SetEnvironmentVariableA( "PATH", "foo" ); - build_search_path( buffer, ARRAY_SIZE(buffer), NULL, FALSE ); + build_search_path( NULL, buffer, ARRAY_SIZE(buffer), NULL, FALSE, 0 ); path = (WCHAR *)0xdeadbeef; ret = pRtlGetExePath( fooW, &path ); ok( !ret, "RtlGetExePath failed %x\n", ret ); @@ -2561,7 +2565,7 @@ static void test_RtlGetExePath(void) if (pSetDllDirectoryW) { ok( pSetDllDirectoryW( dlldir ), "SetDllDirectoryW failed\n" ); - build_search_path( buffer, ARRAY_SIZE(buffer), NULL, FALSE ); + build_search_path( NULL, buffer, ARRAY_SIZE(buffer), NULL, FALSE, 0 ); path = (WCHAR *)0xdeadbeef; ret = pRtlGetExePath( fooW, &path ); ok( !ret, "RtlGetExePath failed %x\n", ret ); @@ -2578,7 +2582,7 @@ static void test_LdrGetDllPath(void) static const WCHAR fooW[] = {'f','o','o',0}; NTSTATUS ret; WCHAR *path, *unknown_ptr, *p; - WCHAR buffer[2048], old_path[2048], dlldir[4]; + WCHAR buffer[2048], old_path[2048], module_path[2048], dlldir[4];
if (!pLdrGetDllPath) { @@ -2589,7 +2593,7 @@ static void test_LdrGetDllPath(void) GetWindowsDirectoryW( buffer, ARRAY_SIZE(buffer) ); lstrcpynW( dlldir, buffer, ARRAY_SIZE(dlldir) );
- build_search_path( buffer, ARRAY_SIZE(buffer), NULL, TRUE ); + build_search_path( NULL, buffer, ARRAY_SIZE(buffer), NULL, TRUE, 0 );
path = unknown_ptr = (WCHAR *)0xdeadbeef; ret = pLdrGetDllPath( 0, 0, &path, &unknown_ptr ); @@ -2599,7 +2603,7 @@ static void test_LdrGetDllPath(void) pRtlReleasePath( path );
SetEnvironmentVariableA( "PATH", "foo" ); - build_search_path( buffer, ARRAY_SIZE(buffer), NULL, TRUE ); + build_search_path( NULL, buffer, ARRAY_SIZE(buffer), NULL, TRUE, 0 ); ret = pLdrGetDllPath( 0, 0, &path, &unknown_ptr ); ok( !ret, "LdrGetDllPath failed %x\n", ret ); ok( !unknown_ptr, "unknown ptr %p\n", unknown_ptr ); @@ -2609,7 +2613,7 @@ static void test_LdrGetDllPath(void) if (pSetDllDirectoryW) { ok( pSetDllDirectoryW( dlldir ), "SetDllDirectoryW failed\n" ); - build_search_path( buffer, ARRAY_SIZE(buffer), dlldir, TRUE ); + build_search_path( NULL, buffer, ARRAY_SIZE(buffer), dlldir, TRUE, 0 ); ret = pLdrGetDllPath( 0, 0, &path, &unknown_ptr ); ok( !ret, "LdrGetDllPath failed %x\n", ret ); ok( !unknown_ptr, "unknown ptr %p\n", unknown_ptr ); @@ -2654,6 +2658,63 @@ static void test_LdrGetDllPath(void) ok( !lstrcmpW( path, L"\\?\c:" ), "got %s expected \\?\c:\n", wine_dbgstr_w(path)); pRtlReleasePath( path );
+ lstrcpyW( module_path, fooW ); + ret = pLdrGetDllPath( module_path, LOAD_WITH_ALTERED_SEARCH_PATH, &path, &unknown_ptr ); + ok( !ret, "LdrGetDllPath failed %x\n", ret ); + ok( !unknown_ptr, "unknown ptr %p\n", unknown_ptr ); + build_search_path( module_path, buffer, ARRAY_SIZE(buffer), NULL, TRUE, LOAD_WITH_ALTERED_SEARCH_PATH ); + todo_wine + ok( path_equal( path, buffer ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(buffer)); + pRtlReleasePath( path ); + + lstrcpyW( module_path, L"temp" ); + p = module_path + lstrlenW( module_path ); + *p++ = '/'; + lstrcpyW( p, fooW ); + ret = pLdrGetDllPath( module_path, LOAD_WITH_ALTERED_SEARCH_PATH, &path, &unknown_ptr ); + ok( !ret, "LdrGetDllPath failed %x\n", ret ); + ok( !unknown_ptr, "unknown ptr %p\n", unknown_ptr ); + build_search_path( module_path, buffer, ARRAY_SIZE(buffer), NULL, TRUE, LOAD_WITH_ALTERED_SEARCH_PATH ); + todo_wine + ok( path_equal( path, buffer ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(buffer)); + pRtlReleasePath( path ); + + lstrcpyW( module_path, L".\foo\foobar" ); + ret = pLdrGetDllPath( module_path, LOAD_WITH_ALTERED_SEARCH_PATH, &path, &unknown_ptr ); + ok( !ret, "LdrGetDllPath failed %x\n", ret ); + ok( !unknown_ptr, "unknown ptr %p\n", unknown_ptr ); + build_search_path( module_path, buffer, ARRAY_SIZE(buffer), NULL, TRUE, LOAD_WITH_ALTERED_SEARCH_PATH ); + ok( path_equal( path, buffer ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(buffer)); + pRtlReleasePath( path ); + + lstrcpyW( module_path, L"temp" ); + p = module_path + lstrlenW( module_path ); + *p++ = '\'; + lstrcpyW( p, fooW ); + ret = pLdrGetDllPath( module_path, LOAD_WITH_ALTERED_SEARCH_PATH, &path, &unknown_ptr ); + ok( !ret, "LdrGetDllPath failed %x\n", ret ); + ok( !unknown_ptr, "unknown ptr %p\n", unknown_ptr ); + build_search_path( module_path, buffer, ARRAY_SIZE(buffer), NULL, TRUE,LOAD_WITH_ALTERED_SEARCH_PATH ); + ok( path_equal( path, buffer ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(buffer)); + pRtlReleasePath( path ); + + lstrcpyW( module_path, L"c:\temp" ); + p = module_path + lstrlenW(module_path); + *p++ = '\'; + lstrcpyW( p, fooW ); + ret = pLdrGetDllPath( module_path, LOAD_WITH_ALTERED_SEARCH_PATH, &path, &unknown_ptr ); + ok( !ret, "LdrGetDllPath failed %x\n", ret ); + ok( !unknown_ptr, "unknown ptr %p\n", unknown_ptr ); + build_search_path( module_path, buffer, ARRAY_SIZE(buffer), NULL, TRUE, LOAD_WITH_ALTERED_SEARCH_PATH ); + ok( path_equal( path, buffer ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(buffer)); + pRtlReleasePath( path ); + + lstrcpyW( buffer, fooW ); + ret = pLdrGetDllPath( buffer, LOAD_WITH_ALTERED_SEARCH_PATH | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR, &path, &unknown_ptr ); + ok( ret == STATUS_INVALID_PARAMETER, "got %x expected %x\n", ret, STATUS_INVALID_PARAMETER ); + ok( !unknown_ptr, "unknown ptr %p\n", unknown_ptr ); + pRtlReleasePath( path ); + lstrcpyW( buffer, dlldir ); p = buffer + lstrlenW(buffer); *p++ = '\'; -- 2.33.1
Windows adds the executable directory to the path when LdrGetDllPath is called with LOAD_WITH_ALTERED_SEARCH_PATH and a relative module name, but only when the module name does not include directories.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=26350 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51821 Signed-off-by: Nick Fox nick@foxsec.net --- v5: use helper function to duplicate less code per julliard's feedback --- dlls/kernel32/tests/path.c | 2 -- dlls/ntdll/loader.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-)
diff --git a/dlls/kernel32/tests/path.c b/dlls/kernel32/tests/path.c index 2737910931c..0a0353d9f6d 100644 --- a/dlls/kernel32/tests/path.c +++ b/dlls/kernel32/tests/path.c @@ -2663,7 +2663,6 @@ static void test_LdrGetDllPath(void) ok( !ret, "LdrGetDllPath failed %x\n", ret ); ok( !unknown_ptr, "unknown ptr %p\n", unknown_ptr ); build_search_path( module_path, buffer, ARRAY_SIZE(buffer), NULL, TRUE, LOAD_WITH_ALTERED_SEARCH_PATH ); - todo_wine ok( path_equal( path, buffer ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(buffer)); pRtlReleasePath( path );
@@ -2675,7 +2674,6 @@ static void test_LdrGetDllPath(void) ok( !ret, "LdrGetDllPath failed %x\n", ret ); ok( !unknown_ptr, "unknown ptr %p\n", unknown_ptr ); build_search_path( module_path, buffer, ARRAY_SIZE(buffer), NULL, TRUE, LOAD_WITH_ALTERED_SEARCH_PATH ); - todo_wine ok( path_equal( path, buffer ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(buffer)); pRtlReleasePath( path );
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index dd41d6b66d2..28f59d59e0d 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -4211,7 +4211,7 @@ NTSTATUS WINAPI LdrGetDllPath( PCWSTR module, ULONG flags, PWSTR *path, PWSTR *u else { const WCHAR *dlldir = dll_directory.Length ? dll_directory.Buffer : NULL; - if (!(flags & LOAD_WITH_ALTERED_SEARCH_PATH)) + if (!(flags & LOAD_WITH_ALTERED_SEARCH_PATH) || !wcschr( module, L'\' )) module = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer; status = get_dll_load_path( module, dlldir, dll_safe_mode, path ); } -- 2.33.1
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=100988
Your paranoid android.
=== w8adm (32 bit report) ===
kernel32: path: Timeout