Jacek Caban : kernel32: Fixed buffer overflow in GetShortPathNameW.

Alexandre Julliard julliard at wine.codeweavers.com
Mon May 25 08:41:16 CDT 2015


Module: wine
Branch: master
Commit: 12a134fdc489f1ab23836eae99b500a072db3ae9
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=12a134fdc489f1ab23836eae99b500a072db3ae9

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Sun May 24 20:16:20 2015 +0200

kernel32: Fixed buffer overflow in GetShortPathNameW.

---

 dlls/kernel32/path.c       | 22 ++++++++++++++++++++--
 dlls/kernel32/tests/path.c | 22 ++++++++++++++++++----
 2 files changed, 38 insertions(+), 6 deletions(-)

diff --git a/dlls/kernel32/path.c b/dlls/kernel32/path.c
index eae2ca9..f74b952 100644
--- a/dlls/kernel32/path.c
+++ b/dlls/kernel32/path.c
@@ -443,7 +443,7 @@ DWORD WINAPI GetShortPathNameW( LPCWSTR longpath, LPWSTR shortpath, DWORD shortl
     WCHAR               *tmpshortpath;
     LPCWSTR             p;
     DWORD               sp = 0, lp = 0;
-    DWORD               tmplen;
+    DWORD               tmplen, buf_len;
     WIN32_FIND_DATAW    wfd;
     HANDLE              goit;
 
@@ -462,7 +462,8 @@ DWORD WINAPI GetShortPathNameW( LPCWSTR longpath, LPWSTR shortpath, DWORD shortl
 
     /* code below only removes characters from string, never adds, so this is
      * the largest buffer that tmpshortpath will need to have */
-    tmpshortpath = HeapAlloc(GetProcessHeap(), 0, (strlenW(longpath) + 1) * sizeof(WCHAR));
+    buf_len = strlenW(longpath) + 1;
+    tmpshortpath = HeapAlloc(GetProcessHeap(), 0, buf_len * sizeof(WCHAR));
     if (!tmpshortpath)
     {
         SetLastError(ERROR_OUTOFMEMORY);
@@ -524,6 +525,23 @@ DWORD WINAPI GetShortPathNameW( LPCWSTR longpath, LPWSTR shortpath, DWORD shortl
         goit = FindFirstFileW(tmpshortpath, &wfd);
         if (goit == INVALID_HANDLE_VALUE) goto notfound;
         FindClose(goit);
+
+        /* In rare cases (like "a.abcd") short path may be longer than original path.
+         * Make sure we have enough space in temp buffer. */
+        if (wfd.cAlternateFileName && tmplen < strlenW(wfd.cAlternateFileName))
+        {
+            WCHAR *new_buf;
+            buf_len += strlenW(wfd.cAlternateFileName) - tmplen;
+            new_buf = HeapReAlloc(GetProcessHeap(), 0, tmpshortpath, buf_len * sizeof(WCHAR));
+            if(!new_buf)
+            {
+                HeapFree(GetProcessHeap(), 0, tmpshortpath);
+                SetLastError(ERROR_OUTOFMEMORY);
+                return 0;
+            }
+            tmpshortpath = new_buf;
+        }
+
         strcpyW(tmpshortpath + sp, wfd.cAlternateFileName[0] ? wfd.cAlternateFileName : wfd.cFileName);
         sp += strlenW(tmpshortpath + sp);
         lp += tmplen;
diff --git a/dlls/kernel32/tests/path.c b/dlls/kernel32/tests/path.c
index 3bf82fe..f8dfdc8 100644
--- a/dlls/kernel32/tests/path.c
+++ b/dlls/kernel32/tests/path.c
@@ -1350,7 +1350,8 @@ static void test_GetShortPathNameW(void)
     static const WCHAR test_path[] = { 'L', 'o', 'n', 'g', 'D', 'i', 'r', 'e', 'c', 't', 'o', 'r', 'y', 'N', 'a', 'm', 'e',  0 };
     static const WCHAR name[] = { 't', 'e', 's', 't', 0 };
     static const WCHAR backSlash[] = { '\\', 0 };
-    WCHAR path[MAX_PATH], tmppath[MAX_PATH];
+    static const WCHAR a_bcdeW[] = {'a','.','b','c','d','e',0};
+    WCHAR path[MAX_PATH], tmppath[MAX_PATH], *ptr;
     WCHAR short_path[MAX_PATH];
     DWORD length;
     HANDLE file;
@@ -1387,7 +1388,7 @@ static void test_GetShortPathNameW(void)
     length = GetShortPathNameW( path, short_path, 0 );
     ok( length, "GetShortPathNameW returned 0.\n" );
     ret = GetShortPathNameW( path, short_path, length );
-    ok( ret, "GetShortPathNameW returned 0.\n" );
+    ok( ret && ret == length-1, "GetShortPathNameW returned 0.\n" );
 
     lstrcatW( short_path, name );
 
@@ -1399,11 +1400,24 @@ static void test_GetShortPathNameW(void)
 
     file = CreateFileW( short_path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
     ok( file != INVALID_HANDLE_VALUE, "File was not created.\n" );
-
-    /* End test */
     CloseHandle( file );
     ret = DeleteFileW( short_path );
     ok( ret, "Cannot delete file.\n" );
+
+    ptr = path + lstrlenW(path);
+    lstrcpyW( ptr, a_bcdeW);
+    file = CreateFileW( path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
+    ok( file != INVALID_HANDLE_VALUE, "File was not created.\n" );
+    CloseHandle( file );
+
+    length = GetShortPathNameW( path, short_path, sizeof(short_path)/sizeof(*short_path) );
+    ok( length, "GetShortPathNameW failed: %u.\n", GetLastError() );
+
+    ret = DeleteFileW( path );
+    ok( ret, "Cannot delete file.\n" );
+    *ptr = 0;
+
+    /* End test */
     ret = RemoveDirectoryW( path );
     ok( ret, "Cannot delete directory.\n" );
 }




More information about the wine-cvs mailing list