From: Jacek Caban Subject: [PATCH try2] kernel32: Fixed buffer overflow in GetShortPathNameW. Message-Id: <55621574.9090805@codeweavers.com> Date: Sun, 24 May 2015 20:16:20 +0200 --- 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" ); }