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

Alexandre Julliard julliard at wine.codeweavers.com
Tue Mar 17 11:01:58 CDT 2015


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

Author: Francois Gouget <fgouget at codeweavers.com>
Date:   Mon Mar 16 17:44:43 2015 +0100

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.

---

 programs/winemenubuilder/winemenubuilder.c | 84 ++++++++++++++++++------------
 1 file changed, 50 insertions(+), 34 deletions(-)

diff --git a/programs/winemenubuilder/winemenubuilder.c b/programs/winemenubuilder/winemenubuilder.c
index 2bdbdbf..4a5639b 100644
--- a/programs/winemenubuilder/winemenubuilder.c
+++ b/programs/winemenubuilder/winemenubuilder.c
@@ -103,7 +103,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(menubuilder);
                                (csidl)==CSIDL_COMMON_DESKTOPDIRECTORY)
 #define in_startmenu(csidl)   ((csidl)==CSIDL_STARTMENU || \
                                (csidl)==CSIDL_COMMON_STARTMENU)
-        
+
 /* link file formats */
 
 #include "pshpack1.h"
@@ -964,20 +964,32 @@ end:
     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 nIndex = 0;
     int i;
     LARGE_INTEGER position;
     HRESULT hr;
 
-    hr = read_ico_direntries(iconStream, &pIconDirEntry, &numEntries);
-    if (FAILED(hr))
-        goto end;
-
     for (i = 0; i < numEntries; i++)
     {
         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)
     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;
 
@@ -1084,16 +1096,25 @@ static HRESULT open_icon(LPCWSTR filename, int index, BOOL bWait, IStream **ppSt
         }
         else
         {
-            static const WCHAR dot_icoW[] = {'.','i','c','o',0};
-            int len = strlenW(filename);
-            if (len >= 4 && strcmpiW(&filename[len - 4], dot_icoW) == 0)
-                hr = SHCreateStreamOnFileW(filename, STGM_READ, ppStream);
+            /* This might be a raw .ico file */
+            hr = SHCreateStreamOnFileW(filename, STGM_READ, ppStream);
         }
     }
+    if (SUCCEEDED(hr))
+        hr = validate_ico(ppStream, ppIconDirEntries, numEntries);
+
     if (FAILED(hr))
+    {
         hr = open_file_type_icon(filename, ppStream);
+        if (SUCCEEDED(hr))
+            hr = validate_ico(ppStream, ppIconDirEntries, numEntries);
+    }
     if (FAILED(hr) && !bWait)
+    {
         hr = open_default_icon(ppStream);
+        if (SUCCEEDED(hr))
+            hr = validate_ico(ppStream, ppIconDirEntries, numEntries);
+    }
     return hr;
 }
 
@@ -1147,11 +1168,10 @@ static inline int size_to_slot(int size)
 
 #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)
 {
-    ICONDIRENTRY *iconDirEntries = NULL;
-    int numEntries;
     struct {
         int index;
         int maxBits;
@@ -1164,9 +1184,6 @@ static HRESULT platform_write_icon(IStream *icoStream, int exeIndex, LPCWSTR ico
     LARGE_INTEGER zero;
     HRESULT hr;
 
-    hr = read_ico_direntries(icoStream, &iconDirEntries, &numEntries);
-    if (FAILED(hr))
-        goto end;
     for (i = 0; i < ICNS_SLOTS; i++)
     {
         best[i].index = -1;
@@ -1254,7 +1271,6 @@ static HRESULT platform_write_icon(IStream *icoStream, int exeIndex, LPCWSTR ico
     }
 
 end:
-    HeapFree(GetProcessHeap(), 0, iconDirEntries);
     HeapFree(GetProcessHeap(), 0, icnsPath);
     return hr;
 }
@@ -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)
 {
-    ICONDIRENTRY *iconDirEntries = NULL;
-    int numEntries;
     int i;
     char *iconsDir = NULL;
     HRESULT hr = S_OK;
     LARGE_INTEGER zero;
 
-    hr = read_ico_direntries(icoStream, &iconDirEntries, &numEntries);
-    if (FAILED(hr))
-        goto end;
-
     if (destFilename)
         *nativeIdentifier = heap_printf("%s", destFilename);
     else
@@ -1372,7 +1383,6 @@ static HRESULT platform_write_icon(IStream *icoStream, int exeIndex, LPCWSTR ico
     refresh_icon_cache(iconsDir);
 
 end:
-    HeapFree(GetProcessHeap(), 0, iconDirEntries);
     HeapFree(GetProcessHeap(), 0, iconsDir);
     return hr;
 }
@@ -1382,24 +1392,27 @@ end:
 static char *extract_icon(LPCWSTR icoPathW, int index, const char *destFilename, BOOL bWait)
 {
     IStream *stream = NULL;
+    ICONDIRENTRY *pIconDirEntries = NULL;
+    int numEntries;
     HRESULT hr;
     char *nativeIdentifier = NULL;
 
     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))
     {
         WINE_WARN("opening icon %s index %d failed, hr=0x%08X\n", wine_dbgstr_w(icoPathW), index, hr);
         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))
         WINE_WARN("writing icon failed, error 0x%08X\n", hr);
 
 end:
     if (stream)
         IStream_Release(stream);
+    HeapFree(GetProcessHeap(), 0, pIconDirEntries);
     if (FAILED(hr))
     {
         HeapFree(GetProcessHeap(), 0, nativeIdentifier);
@@ -3472,6 +3485,8 @@ static void thumbnail_lnk(LPCWSTR lnkPath, LPCWSTR outputPath)
     WCHAR szIconPath[MAX_PATH];
     int iconId;
     IStream *stream = NULL;
+    ICONDIRENTRY *pIconDirEntries = NULL;
+    int numEntries;
     HRESULT hr;
 
     utf8lnkPath = wchars_to_utf8_chars(lnkPath);
@@ -3533,15 +3548,15 @@ static void thumbnail_lnk(LPCWSTR lnkPath, LPCWSTR outputPath)
 
     if (szIconPath[0])
     {
-        hr = open_icon(szIconPath, iconId, FALSE, &stream);
+        hr = open_icon(szIconPath, iconId, FALSE, &stream, &pIconDirEntries, &numEntries);
         if (SUCCEEDED(hr))
-            hr = write_native_icon(stream, utf8OutputPath, NULL);
+            hr = write_native_icon(stream, pIconDirEntries, numEntries, utf8OutputPath, NULL);
     }
     else
     {
-        hr = open_icon(szPath, iconId, FALSE, &stream);
+        hr = open_icon(szPath, iconId, FALSE, &stream, &pIconDirEntries, &numEntries);
         if (SUCCEEDED(hr))
-            hr = write_native_icon(stream, utf8OutputPath, NULL);
+            hr = write_native_icon(stream, pIconDirEntries, numEntries, utf8OutputPath, NULL);
     }
 
 end:
@@ -3554,6 +3569,7 @@ end:
         IPersistFile_Release(persistFile);
     if (stream != NULL)
         IStream_Release(stream);
+    HeapFree(GetProcessHeap(), 0, pIconDirEntries);
 }
 
 static WCHAR *next_token( LPWSTR *p )




More information about the wine-cvs mailing list