Commit 520dcb4c authored by Francois Gouget's avatar Francois Gouget Committed by Alexandre Julliard

winemenubuilder: Handle icons disguised as executables and better validate icon streams.

For some applications the shortcut's icon points to a .exe file which in fact contains a .ico file. This means open_icon() cannot rely on the file extension. Also reject icon streams that don't actually contain a valid icon and use the next source as a fallback.
parent d4b9ac46
...@@ -103,7 +103,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(menubuilder); ...@@ -103,7 +103,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(menubuilder);
(csidl)==CSIDL_COMMON_DESKTOPDIRECTORY) (csidl)==CSIDL_COMMON_DESKTOPDIRECTORY)
#define in_startmenu(csidl) ((csidl)==CSIDL_STARTMENU || \ #define in_startmenu(csidl) ((csidl)==CSIDL_STARTMENU || \
(csidl)==CSIDL_COMMON_STARTMENU) (csidl)==CSIDL_COMMON_STARTMENU)
/* link file formats */ /* link file formats */
#include "pshpack1.h" #include "pshpack1.h"
...@@ -964,20 +964,32 @@ end: ...@@ -964,20 +964,32 @@ end:
return hr; return hr;
} }
static HRESULT write_native_icon(IStream *iconStream, const char *icon_name, LPCWSTR szFileName) static HRESULT validate_ico(IStream **ppStream, ICONDIRENTRY **ppIconDirEntries, int *numEntries)
{
HRESULT hr;
hr = read_ico_direntries(*ppStream, ppIconDirEntries, numEntries);
if (SUCCEEDED(hr))
{
if (*numEntries)
return hr;
HeapFree(GetProcessHeap(), 0, *ppIconDirEntries);
*ppIconDirEntries = NULL;
}
IStream_Release(*ppStream);
*ppStream = NULL;
return E_FAIL;
}
static HRESULT write_native_icon(IStream *iconStream, ICONDIRENTRY *pIconDirEntry,
int numEntries, const char *icon_name, LPCWSTR szFileName)
{ {
ICONDIRENTRY *pIconDirEntry = NULL;
int numEntries;
int nMax = 0, nMaxBits = 0; int nMax = 0, nMaxBits = 0;
int nIndex = 0; int nIndex = 0;
int i; int i;
LARGE_INTEGER position; LARGE_INTEGER position;
HRESULT hr; HRESULT hr;
hr = read_ico_direntries(iconStream, &pIconDirEntry, &numEntries);
if (FAILED(hr))
goto end;
for (i = 0; i < numEntries; i++) for (i = 0; i < numEntries; i++)
{ {
WINE_TRACE("[%d]: %d x %d @ %d\n", i, pIconDirEntry[i].bWidth, pIconDirEntry[i].bHeight, pIconDirEntry[i].wBitCount); WINE_TRACE("[%d]: %d x %d @ %d\n", i, pIconDirEntry[i].bWidth, pIconDirEntry[i].bHeight, pIconDirEntry[i].wBitCount);
...@@ -1069,7 +1081,7 @@ static HRESULT open_default_icon(IStream **ppStream) ...@@ -1069,7 +1081,7 @@ static HRESULT open_default_icon(IStream **ppStream)
return open_module_icon(user32W, -(INT_PTR)IDI_WINLOGO, ppStream); return open_module_icon(user32W, -(INT_PTR)IDI_WINLOGO, ppStream);
} }
static HRESULT open_icon(LPCWSTR filename, int index, BOOL bWait, IStream **ppStream) static HRESULT open_icon(LPCWSTR filename, int index, BOOL bWait, IStream **ppStream, ICONDIRENTRY **ppIconDirEntries, int *numEntries)
{ {
HRESULT hr; HRESULT hr;
...@@ -1084,16 +1096,25 @@ static HRESULT open_icon(LPCWSTR filename, int index, BOOL bWait, IStream **ppSt ...@@ -1084,16 +1096,25 @@ static HRESULT open_icon(LPCWSTR filename, int index, BOOL bWait, IStream **ppSt
} }
else else
{ {
static const WCHAR dot_icoW[] = {'.','i','c','o',0}; /* This might be a raw .ico file */
int len = strlenW(filename); hr = SHCreateStreamOnFileW(filename, STGM_READ, ppStream);
if (len >= 4 && strcmpiW(&filename[len - 4], dot_icoW) == 0)
hr = SHCreateStreamOnFileW(filename, STGM_READ, ppStream);
} }
} }
if (SUCCEEDED(hr))
hr = validate_ico(ppStream, ppIconDirEntries, numEntries);
if (FAILED(hr)) if (FAILED(hr))
{
hr = open_file_type_icon(filename, ppStream); hr = open_file_type_icon(filename, ppStream);
if (SUCCEEDED(hr))
hr = validate_ico(ppStream, ppIconDirEntries, numEntries);
}
if (FAILED(hr) && !bWait) if (FAILED(hr) && !bWait)
{
hr = open_default_icon(ppStream); hr = open_default_icon(ppStream);
if (SUCCEEDED(hr))
hr = validate_ico(ppStream, ppIconDirEntries, numEntries);
}
return hr; return hr;
} }
...@@ -1147,11 +1168,10 @@ static inline int size_to_slot(int size) ...@@ -1147,11 +1168,10 @@ static inline int size_to_slot(int size)
#define CLASSIC_SLOT 3 #define CLASSIC_SLOT 3
static HRESULT platform_write_icon(IStream *icoStream, int exeIndex, LPCWSTR icoPathW, static HRESULT platform_write_icon(IStream *icoStream, ICONDIRENTRY *pIconDirEntry,
int numEntries, int exeIndex, LPCWSTR icoPathW,
const char *destFilename, char **nativeIdentifier) const char *destFilename, char **nativeIdentifier)
{ {
ICONDIRENTRY *iconDirEntries = NULL;
int numEntries;
struct { struct {
int index; int index;
int maxBits; int maxBits;
...@@ -1164,9 +1184,6 @@ static HRESULT platform_write_icon(IStream *icoStream, int exeIndex, LPCWSTR ico ...@@ -1164,9 +1184,6 @@ static HRESULT platform_write_icon(IStream *icoStream, int exeIndex, LPCWSTR ico
LARGE_INTEGER zero; LARGE_INTEGER zero;
HRESULT hr; HRESULT hr;
hr = read_ico_direntries(icoStream, &iconDirEntries, &numEntries);
if (FAILED(hr))
goto end;
for (i = 0; i < ICNS_SLOTS; i++) for (i = 0; i < ICNS_SLOTS; i++)
{ {
best[i].index = -1; best[i].index = -1;
...@@ -1254,7 +1271,6 @@ static HRESULT platform_write_icon(IStream *icoStream, int exeIndex, LPCWSTR ico ...@@ -1254,7 +1271,6 @@ static HRESULT platform_write_icon(IStream *icoStream, int exeIndex, LPCWSTR ico
} }
end: end:
HeapFree(GetProcessHeap(), 0, iconDirEntries);
HeapFree(GetProcessHeap(), 0, icnsPath); HeapFree(GetProcessHeap(), 0, icnsPath);
return hr; return hr;
} }
...@@ -1279,20 +1295,15 @@ static void refresh_icon_cache(const char *iconsDir) ...@@ -1279,20 +1295,15 @@ static void refresh_icon_cache(const char *iconsDir)
} }
} }
static HRESULT platform_write_icon(IStream *icoStream, int exeIndex, LPCWSTR icoPathW, static HRESULT platform_write_icon(IStream *icoStream, ICONDIRENTRY *iconDirEntries,
int numEntries, int exeIndex, LPCWSTR icoPathW,
const char *destFilename, char **nativeIdentifier) const char *destFilename, char **nativeIdentifier)
{ {
ICONDIRENTRY *iconDirEntries = NULL;
int numEntries;
int i; int i;
char *iconsDir = NULL; char *iconsDir = NULL;
HRESULT hr = S_OK; HRESULT hr = S_OK;
LARGE_INTEGER zero; LARGE_INTEGER zero;
hr = read_ico_direntries(icoStream, &iconDirEntries, &numEntries);
if (FAILED(hr))
goto end;
if (destFilename) if (destFilename)
*nativeIdentifier = heap_printf("%s", destFilename); *nativeIdentifier = heap_printf("%s", destFilename);
else else
...@@ -1372,7 +1383,6 @@ static HRESULT platform_write_icon(IStream *icoStream, int exeIndex, LPCWSTR ico ...@@ -1372,7 +1383,6 @@ static HRESULT platform_write_icon(IStream *icoStream, int exeIndex, LPCWSTR ico
refresh_icon_cache(iconsDir); refresh_icon_cache(iconsDir);
end: end:
HeapFree(GetProcessHeap(), 0, iconDirEntries);
HeapFree(GetProcessHeap(), 0, iconsDir); HeapFree(GetProcessHeap(), 0, iconsDir);
return hr; return hr;
} }
...@@ -1382,24 +1392,27 @@ end: ...@@ -1382,24 +1392,27 @@ end:
static char *extract_icon(LPCWSTR icoPathW, int index, const char *destFilename, BOOL bWait) static char *extract_icon(LPCWSTR icoPathW, int index, const char *destFilename, BOOL bWait)
{ {
IStream *stream = NULL; IStream *stream = NULL;
ICONDIRENTRY *pIconDirEntries = NULL;
int numEntries;
HRESULT hr; HRESULT hr;
char *nativeIdentifier = NULL; char *nativeIdentifier = NULL;
WINE_TRACE("path=[%s] index=%d destFilename=[%s]\n", wine_dbgstr_w(icoPathW), index, wine_dbgstr_a(destFilename)); WINE_TRACE("path=[%s] index=%d destFilename=[%s]\n", wine_dbgstr_w(icoPathW), index, wine_dbgstr_a(destFilename));
hr = open_icon(icoPathW, index, bWait, &stream); hr = open_icon(icoPathW, index, bWait, &stream, &pIconDirEntries, &numEntries);
if (FAILED(hr)) if (FAILED(hr))
{ {
WINE_WARN("opening icon %s index %d failed, hr=0x%08X\n", wine_dbgstr_w(icoPathW), index, hr); WINE_WARN("opening icon %s index %d failed, hr=0x%08X\n", wine_dbgstr_w(icoPathW), index, hr);
goto end; goto end;
} }
hr = platform_write_icon(stream, index, icoPathW, destFilename, &nativeIdentifier); hr = platform_write_icon(stream, pIconDirEntries, numEntries, index, icoPathW, destFilename, &nativeIdentifier);
if (FAILED(hr)) if (FAILED(hr))
WINE_WARN("writing icon failed, error 0x%08X\n", hr); WINE_WARN("writing icon failed, error 0x%08X\n", hr);
end: end:
if (stream) if (stream)
IStream_Release(stream); IStream_Release(stream);
HeapFree(GetProcessHeap(), 0, pIconDirEntries);
if (FAILED(hr)) if (FAILED(hr))
{ {
HeapFree(GetProcessHeap(), 0, nativeIdentifier); HeapFree(GetProcessHeap(), 0, nativeIdentifier);
...@@ -3472,6 +3485,8 @@ static void thumbnail_lnk(LPCWSTR lnkPath, LPCWSTR outputPath) ...@@ -3472,6 +3485,8 @@ static void thumbnail_lnk(LPCWSTR lnkPath, LPCWSTR outputPath)
WCHAR szIconPath[MAX_PATH]; WCHAR szIconPath[MAX_PATH];
int iconId; int iconId;
IStream *stream = NULL; IStream *stream = NULL;
ICONDIRENTRY *pIconDirEntries = NULL;
int numEntries;
HRESULT hr; HRESULT hr;
utf8lnkPath = wchars_to_utf8_chars(lnkPath); utf8lnkPath = wchars_to_utf8_chars(lnkPath);
...@@ -3533,15 +3548,15 @@ static void thumbnail_lnk(LPCWSTR lnkPath, LPCWSTR outputPath) ...@@ -3533,15 +3548,15 @@ static void thumbnail_lnk(LPCWSTR lnkPath, LPCWSTR outputPath)
if (szIconPath[0]) if (szIconPath[0])
{ {
hr = open_icon(szIconPath, iconId, FALSE, &stream); hr = open_icon(szIconPath, iconId, FALSE, &stream, &pIconDirEntries, &numEntries);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
hr = write_native_icon(stream, utf8OutputPath, NULL); hr = write_native_icon(stream, pIconDirEntries, numEntries, utf8OutputPath, NULL);
} }
else else
{ {
hr = open_icon(szPath, iconId, FALSE, &stream); hr = open_icon(szPath, iconId, FALSE, &stream, &pIconDirEntries, &numEntries);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
hr = write_native_icon(stream, utf8OutputPath, NULL); hr = write_native_icon(stream, pIconDirEntries, numEntries, utf8OutputPath, NULL);
} }
end: end:
...@@ -3554,6 +3569,7 @@ end: ...@@ -3554,6 +3569,7 @@ end:
IPersistFile_Release(persistFile); IPersistFile_Release(persistFile);
if (stream != NULL) if (stream != NULL)
IStream_Release(stream); IStream_Release(stream);
HeapFree(GetProcessHeap(), 0, pIconDirEntries);
} }
static WCHAR *next_token( LPWSTR *p ) static WCHAR *next_token( LPWSTR *p )
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment