Module: wine Branch: oldstable Commit: a917d758b37cf7ba73e446e96b01c5976aa27d7b URL: https://source.winehq.org/git/wine.git/?a=commit;h=a917d758b37cf7ba73e446e96...
Author: Akihiro Sagawa sagawa.aki@gmail.com Date: Sat Jun 19 18:25:35 2021 +0900
ntdll: Validate directory path when the path name ends with a dos device name.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51291 Signed-off-by: Akihiro Sagawa sagawa.aki@gmail.com Signed-off-by: Alexandre Julliard julliard@winehq.org (cherry picked from commit 0acd98f135b246176f33896bdc13ee6cadc3339e) Signed-off-by: Michael Stefaniuc mstefani@winehq.org
---
dlls/ntdll/path.c | 91 ++++++++++++++++++++++++++++++++++++++++++------- dlls/ntdll/tests/path.c | 2 -- 2 files changed, 78 insertions(+), 15 deletions(-)
diff --git a/dlls/ntdll/path.c b/dlls/ntdll/path.c index 86760f178e1..9cb4ba7d49b 100644 --- a/dlls/ntdll/path.c +++ b/dlls/ntdll/path.c @@ -129,6 +129,40 @@ ULONG WINAPI RtlIsDosDeviceName_U( PCWSTR dos_name ) return 0; }
+/****************************************************************** + * is_valid_directory + * + * Helper for RtlDosPathNameToNtPathName_U_WithStatus. + * Test if the path is an exisiting directory. + */ +static BOOL is_valid_directory(LPCWSTR path) +{ + OBJECT_ATTRIBUTES attr; + UNICODE_STRING ntpath; + IO_STATUS_BLOCK io; + HANDLE handle; + NTSTATUS nts; + + if (!RtlDosPathNameToNtPathName_U(path, &ntpath, NULL, NULL)) + return FALSE; + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.Attributes = OBJ_CASE_INSENSITIVE; + attr.ObjectName = &ntpath; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + nts = NtOpenFile(&handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &io, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); + RtlFreeUnicodeString(&ntpath); + if (nts != STATUS_SUCCESS) + return FALSE; + NtClose(handle); + return TRUE; +} + /************************************************************************** * RtlDosPathNameToNtPathName_U_WithStatus [NTDLL.@] * @@ -146,9 +180,10 @@ NTSTATUS WINAPI RtlDosPathNameToNtPathName_U_WithStatus(const WCHAR *dos_path, U { static const WCHAR global_prefix[] = {'\','\','?','\'}; static const WCHAR global_prefix2[] = {'\','?','?','\'}; - ULONG sz, offset; + NTSTATUS nts = STATUS_SUCCESS; + ULONG sz, offset, dosdev; WCHAR local[MAX_PATH]; - LPWSTR ptr; + LPWSTR ptr = local;
TRACE("(%s,%p,%p,%p)\n", debugstr_w(dos_path), ntpath, file_part, cd);
@@ -178,28 +213,57 @@ NTSTATUS WINAPI RtlDosPathNameToNtPathName_U_WithStatus(const WCHAR *dos_path, U return STATUS_SUCCESS; }
- ptr = local; - sz = RtlGetFullPathName_U(dos_path, sizeof(local), ptr, file_part); - if (sz == 0) return STATUS_OBJECT_NAME_INVALID; + dosdev = RtlIsDosDeviceName_U(dos_path); + if ((offset = HIWORD(dosdev))) + { + sz = offset + sizeof(WCHAR); + + if (sz > sizeof(local) && + (!(ptr = RtlAllocateHeap(GetProcessHeap(), 0, sz)))) + return STATUS_NO_MEMORY; + + memcpy(ptr, dos_path, offset); + ptr[offset/sizeof(WCHAR)] = '\0'; + + if (!is_valid_directory(ptr)) + { + nts = STATUS_OBJECT_NAME_INVALID; + goto out; + } + + if (*file_part) *file_part = NULL;
- if (sz > sizeof(local)) + sz = LOWORD(dosdev); + + wcscpy(ptr, L"\\.\"); + memcpy(ptr + 4, dos_path + offset / sizeof(WCHAR), sz); + ptr[4 + sz / sizeof(WCHAR)] = '\0'; + sz += 4 * sizeof(WCHAR); + } + else { - if (!(ptr = RtlAllocateHeap(GetProcessHeap(), 0, sz))) return STATUS_NO_MEMORY; - sz = RtlGetFullPathName_U(dos_path, sz, ptr, file_part); + sz = RtlGetFullPathName_U(dos_path, sizeof(local), ptr, file_part); + if (sz == 0) return STATUS_OBJECT_NAME_INVALID; + + if (sz > sizeof(local)) + { + if (!(ptr = RtlAllocateHeap(GetProcessHeap(), 0, sz))) return STATUS_NO_MEMORY; + sz = RtlGetFullPathName_U(dos_path, sz, ptr, file_part); + } } sz += (1 /* NUL */ + 4 /* unc\ */ + 4 /* ??\ */) * sizeof(WCHAR); if (sz > MAXWORD) { - if (ptr != local) RtlFreeHeap(GetProcessHeap(), 0, ptr); - return STATUS_OBJECT_NAME_INVALID; + nts = STATUS_OBJECT_NAME_INVALID; + goto out; }
ntpath->MaximumLength = sz; ntpath->Buffer = RtlAllocateHeap(GetProcessHeap(), 0, ntpath->MaximumLength); if (!ntpath->Buffer) { - if (ptr != local) RtlFreeHeap(GetProcessHeap(), 0, ptr); - return STATUS_NO_MEMORY; + nts = STATUS_NO_MEMORY; + goto out; }
wcscpy(ntpath->Buffer, L"\??\"); @@ -225,8 +289,9 @@ NTSTATUS WINAPI RtlDosPathNameToNtPathName_U_WithStatus(const WCHAR *dos_path, U
/* FIXME: cd filling */
+out: if (ptr != local) RtlFreeHeap(GetProcessHeap(), 0, ptr); - return STATUS_SUCCESS; + return nts; }
/************************************************************************** diff --git a/dlls/ntdll/tests/path.c b/dlls/ntdll/tests/path.c index 66d029b2016..47afaf2aa3a 100644 --- a/dlls/ntdll/tests/path.c +++ b/dlls/ntdll/tests/path.c @@ -553,13 +553,11 @@ static void test_RtlDosPathNameToNtPathName_U(void) winetest_push_context("%s", debugstr_w(error_paths[i]));
ret = pRtlDosPathNameToNtPathName_U(error_paths[i], &nameW, &file_part, NULL); - todo_wine_if(i == 3 || i == 4) ok(!ret, "Got %d.\n", ret);
if (pRtlDosPathNameToNtPathName_U_WithStatus) { status = pRtlDosPathNameToNtPathName_U_WithStatus(error_paths[i], &nameW, &file_part, NULL); - todo_wine_if(i == 3 || i == 4) ok(status == STATUS_OBJECT_NAME_INVALID || broken(status == STATUS_OBJECT_PATH_NOT_FOUND /* 2003 */), "Got status %#x.\n", status); }