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