shell32/autocomplete: Fix a vulnerability by avoiding the use of snprintf.
The quickComplete format can have more than one % argument, or stuff like %*.* or %1234s, which can be exploited since the format string can be read from the registry, so handle it manually instead of using sprintf. Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com> Signed-off-by: Huw Davies <huw@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
be3a3ad825
commit
74c0c0574e
|
@ -93,6 +93,32 @@ static inline IAutoCompleteImpl *impl_from_IAutoCompleteDropDown(IAutoCompleteDr
|
||||||
return CONTAINING_RECORD(iface, IAutoCompleteImpl, IAutoCompleteDropDown_iface);
|
return CONTAINING_RECORD(iface, IAutoCompleteImpl, IAutoCompleteDropDown_iface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t format_quick_complete(WCHAR *dst, const WCHAR *qc, const WCHAR *str, size_t str_len)
|
||||||
|
{
|
||||||
|
/* Replace the first %s directly without using snprintf, to avoid
|
||||||
|
exploits since the format string can be retrieved from the registry */
|
||||||
|
WCHAR *base = dst;
|
||||||
|
UINT args = 0;
|
||||||
|
while (*qc != '\0')
|
||||||
|
{
|
||||||
|
if (qc[0] == '%')
|
||||||
|
{
|
||||||
|
if (args < 1 && qc[1] == 's')
|
||||||
|
{
|
||||||
|
memcpy(dst, str, str_len * sizeof(WCHAR));
|
||||||
|
dst += str_len;
|
||||||
|
qc += 2;
|
||||||
|
args++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
qc += (qc[1] == '%');
|
||||||
|
}
|
||||||
|
*dst++ = *qc++;
|
||||||
|
}
|
||||||
|
*dst = '\0';
|
||||||
|
return dst - base;
|
||||||
|
}
|
||||||
|
|
||||||
static void destroy_autocomplete_object(IAutoCompleteImpl *ac)
|
static void destroy_autocomplete_object(IAutoCompleteImpl *ac)
|
||||||
{
|
{
|
||||||
ac->hwndEdit = NULL;
|
ac->hwndEdit = NULL;
|
||||||
|
@ -109,7 +135,6 @@ static LRESULT APIENTRY ACEditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam,
|
||||||
IAutoCompleteImpl *This = GetPropW(hwnd, autocomplete_propertyW);
|
IAutoCompleteImpl *This = GetPropW(hwnd, autocomplete_propertyW);
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
WCHAR hwndText[255];
|
WCHAR hwndText[255];
|
||||||
WCHAR *hwndQCText;
|
|
||||||
RECT r;
|
RECT r;
|
||||||
BOOL control, filled, displayall = FALSE;
|
BOOL control, filled, displayall = FALSE;
|
||||||
int cpt, height, sel;
|
int cpt, height, sel;
|
||||||
|
@ -138,11 +163,16 @@ static LRESULT APIENTRY ACEditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam,
|
||||||
/* If quickComplete is set and control is pressed, replace the string */
|
/* If quickComplete is set and control is pressed, replace the string */
|
||||||
control = GetKeyState(VK_CONTROL) & 0x8000;
|
control = GetKeyState(VK_CONTROL) & 0x8000;
|
||||||
if (control && This->quickComplete) {
|
if (control && This->quickComplete) {
|
||||||
hwndQCText = heap_alloc((lstrlenW(This->quickComplete)+lstrlenW(hwndText))*sizeof(WCHAR));
|
WCHAR *buf;
|
||||||
sel = sprintfW(hwndQCText, This->quickComplete, hwndText);
|
size_t len = strlenW(hwndText);
|
||||||
SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)hwndQCText);
|
size_t sz = strlenW(This->quickComplete) + 1 + len;
|
||||||
SendMessageW(hwnd, EM_SETSEL, 0, sel);
|
if ((buf = heap_alloc(sz * sizeof(WCHAR))))
|
||||||
heap_free(hwndQCText);
|
{
|
||||||
|
len = format_quick_complete(buf, This->quickComplete, hwndText, len);
|
||||||
|
SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)buf);
|
||||||
|
SendMessageW(hwnd, EM_SETSEL, 0, len);
|
||||||
|
heap_free(buf);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ShowWindow(This->hwndListBox, SW_HIDE);
|
ShowWindow(This->hwndListBox, SW_HIDE);
|
||||||
|
|
Loading…
Reference in New Issue