[PATCH 3/3] shell32/autocomplete: Revamp pwzsRegKeyPath handling so it can deal with arbitrary sizes and make it more robust

Gabriel Ivăncescu gabrielopcode at gmail.com
Mon Aug 27 12:10:48 CDT 2018


Handle heap_alloc failure, reg strings without a \ character at all, try
harder to find the reg path (if only value fails the lookup), and properly
read the registry value with arbitrary size, even REG_SZ without a NUL
terminator (MSDN states they are possible).

Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---
 dlls/shell32/autocomplete.c | 93 +++++++++++++++++++++++++++++----------------
 1 file changed, 61 insertions(+), 32 deletions(-)

diff --git a/dlls/shell32/autocomplete.c b/dlls/shell32/autocomplete.c
index 5fe48e9..97ce61a 100644
--- a/dlls/shell32/autocomplete.c
+++ b/dlls/shell32/autocomplete.c
@@ -486,40 +486,69 @@ static HRESULT WINAPI IAutoComplete2_fnInit(
     if (This->options & ACO_AUTOSUGGEST)
         create_listbox(This);
 
-    if (pwzsRegKeyPath) {
-	WCHAR *key;
-	WCHAR result[MAX_PATH];
-	WCHAR *value;
-	HKEY hKey = 0;
-	LONG res;
-	LONG len;
-
-	/* pwszRegKeyPath contains the key as well as the value, so we split */
-	key = heap_alloc((lstrlenW(pwzsRegKeyPath)+1)*sizeof(WCHAR));
-	strcpyW(key, pwzsRegKeyPath);
-	value = strrchrW(key, '\\');
-	*value = 0;
-	value++;
-	/* Now value contains the value and buffer the key */
-	res = RegOpenKeyExW(HKEY_CURRENT_USER, key, 0, KEY_READ, &hKey);
-	if (res != ERROR_SUCCESS) {
-	    /* if the key is not found, MSDN states we must seek in HKEY_LOCAL_MACHINE */
-	    res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hKey);  
-	}
-	if (res == ERROR_SUCCESS) {
-	    res = RegQueryValueW(hKey, value, result, &len);
-	    if (res == ERROR_SUCCESS) {
-		This->quickComplete = heap_alloc(len*sizeof(WCHAR));
-		strcpyW(This->quickComplete, result);
-	    }
-	    RegCloseKey(hKey);
-	}
-	heap_free(key);
+    if (pwzsRegKeyPath)
+    {
+        WCHAR *key, *value;
+        HKEY hKey;
+        LSTATUS res;
+        size_t len;
+
+        /* pwszRegKeyPath contains the key as well as the value, so split it */
+        value = strrchrW(pwzsRegKeyPath, '\\');
+        len = value - pwzsRegKeyPath;
+
+        if (value && (key = heap_alloc((len+1) * sizeof(*key))) != NULL) {
+            memcpy(key, pwzsRegKeyPath, len * sizeof(*key));
+            key[len] = '\0';
+            value++;
+
+            res = RegOpenKeyExW(HKEY_CURRENT_USER, key, 0, KEY_READ, &hKey);
+
+            /* if not found, MSDN states we must seek in HKEY_LOCAL_MACHINE */
+            if (res != ERROR_SUCCESS)
+                res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hKey);
+
+            if (res == ERROR_SUCCESS) {
+                WCHAR *qc;
+                DWORD type, sz;
+                res = RegQueryValueExW(hKey, value, NULL, &type, NULL, &sz);
+
+                if (res != ERROR_SUCCESS || type != REG_SZ) {
+                    RegCloseKey(hKey);
+                    res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hKey);
+                    if (res != ERROR_SUCCESS)
+                        goto free_key_str;
+                    res = RegQueryValueExW(hKey, value, NULL, &type, NULL, &sz);
+                }
+
+                /* the size does include the NUL terminator, however, strings
+                   can be stored without it, so make room for NUL just in case */
+                if (res == ERROR_SUCCESS && type == REG_SZ &&
+                    (qc = heap_alloc(sz + sizeof(*qc))) != NULL)
+                {
+                    DWORD old_sz = sz;
+                    res = RegQueryValueExW(hKey, value, NULL, &type, (BYTE*)qc, &sz);
+
+                    /* make sure the value wasn't messed with */
+                    if (res == ERROR_SUCCESS && sz == old_sz && type == REG_SZ) {
+                        qc[sz / sizeof(*qc)] = '\0';
+                        This->quickComplete = qc;
+                    }
+                    else
+                        heap_free(qc);
+                }
+                RegCloseKey(hKey);
+            }
+          free_key_str:
+            heap_free(key);
+        }
     }
 
-    if ((pwszQuickComplete) && (!This->quickComplete)) {
-	This->quickComplete = heap_alloc((lstrlenW(pwszQuickComplete)+1)*sizeof(WCHAR));
-	lstrcpyW(This->quickComplete, pwszQuickComplete);
+    if (!This->quickComplete && pwszQuickComplete)
+    {
+        size_t len = strlenW(pwszQuickComplete)+1;
+        if ((This->quickComplete = heap_alloc(len * sizeof(WCHAR))) != NULL)
+            memcpy(This->quickComplete, pwszQuickComplete, len * sizeof(WCHAR));
     }
 
     return S_OK;
-- 
1.9.1




More information about the wine-devel mailing list