Akihiro Sagawa : ntdll: Validate directory path when the path name ends with a dos device name.

Alexandre Julliard julliard at winehq.org
Mon Jun 21 16:14:56 CDT 2021


Module: wine
Branch: master
Commit: 0acd98f135b246176f33896bdc13ee6cadc3339e
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=0acd98f135b246176f33896bdc13ee6cadc3339e

Author: Akihiro Sagawa <sagawa.aki at 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 at gmail.com>
Signed-off-by: Alexandre Julliard <julliard at 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 4cb64cbe516..cacb95853ad 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 74ad971392c..dba889fdec7 100644
--- a/dlls/ntdll/tests/path.c
+++ b/dlls/ntdll/tests/path.c
@@ -571,13 +571,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);
         }




More information about the wine-cvs mailing list