From 4bcb4881ae9e7fc2cc4d32aa3ba7f36e46d6fc5c Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Fri, 26 Jun 2015 19:37:41 +0200 Subject: [PATCH] user32: Limit number of hooks called recursively. --- dlls/user32/hook.c | 15 ++++++++++++- dlls/user32/tests/msg.c | 54 +++++++++++++++++++++++++++++++++++++++++++++- dlls/user32/user_private.h | 1 + 3 files changed, 68 insertions(+), 2 deletions(-) diff --git a/dlls/user32/hook.c b/dlls/user32/hook.c index 281b88e70e5..090ec17267c 100644 --- a/dlls/user32/hook.c +++ b/dlls/user32/hook.c @@ -413,7 +413,19 @@ static LRESULT call_hook( struct hook_info *info, INT code, WPARAM wparam, LPARA } else if (info->proc) { + struct user_thread_info *thread_info = get_user_thread_info(); HMODULE free_module = 0; + + /* + * Windows protects from stack overflow in recursive hook calls. Different Windows + * allow different depths. + */ + if (thread_info->hook_call_depth >= 25) + { + WARN("Too many hooks called recursively, skipping call.\n"); + return 0; + } + TRACE( "calling hook %p %s code %x wp %lx lp %lx module %s\n", info->proc, hook_names[info->id-WH_MINHOOK], code, wparam, lparam, debugstr_w(info->module) ); @@ -421,16 +433,17 @@ static LRESULT call_hook( struct hook_info *info, INT code, WPARAM wparam, LPARA if (!info->module[0] || (info->proc = get_hook_proc( info->proc, info->module, &free_module )) != NULL) { - struct user_thread_info *thread_info = get_user_thread_info(); HHOOK prev = thread_info->hook; BOOL prev_unicode = thread_info->hook_unicode; thread_info->hook = info->handle; thread_info->hook_unicode = info->next_unicode; + thread_info->hook_call_depth++; ret = call_hook_proc( info->proc, info->id, code, wparam, lparam, info->prev_unicode, info->next_unicode ); thread_info->hook = prev; thread_info->hook_unicode = prev_unicode; + thread_info->hook_call_depth--; if (free_module) FreeLibrary(free_module); } diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index a515550a5a4..831a56bda48 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -9182,6 +9182,54 @@ todo_wine { "unexpected error %d\n", GetLastError()); } +static HWND hook_hwnd; +static HHOOK recursive_hook; +static int hook_depth, max_hook_depth; + +static LRESULT WINAPI rec_get_message_hook(int code, WPARAM w, LPARAM l) +{ + LRESULT res; + MSG msg; + BOOL b; + + hook_depth++; + if(hook_depth > max_hook_depth) + max_hook_depth = hook_depth; + + b = PeekMessageW(&msg, hook_hwnd, 0, 0, PM_NOREMOVE); + ok(b, "PeekMessage failed\n"); + + res = CallNextHookEx(recursive_hook, code, w, l); + + hook_depth--; + return res; +} + +static void test_recursive_hook(void) +{ + MSG msg; + BOOL b; + + hook_hwnd = CreateWindowA("Static", NULL, WS_POPUP, 0, 0, 200, 60, NULL, NULL, NULL, NULL); + ok(hook_hwnd != NULL, "CreateWindow failed\n"); + + recursive_hook = SetWindowsHookExW(WH_GETMESSAGE, rec_get_message_hook, NULL, GetCurrentThreadId()); + ok(recursive_hook != NULL, "SetWindowsHookEx failed\n"); + + PostMessageW(hook_hwnd, WM_USER, 0, 0); + PostMessageW(hook_hwnd, WM_USER+1, 0, 0); + + hook_depth = 0; + GetMessageW(&msg, hook_hwnd, 0, 0); + ok(15 < max_hook_depth && max_hook_depth < 45, "max_hook_depth = %d\n", max_hook_depth); + trace("max_hook_depth = %d\n", max_hook_depth); + + b = UnhookWindowsHookEx(recursive_hook); + ok(b, "UnhokWindowsHookEx failed\n"); + + DestroyWindow(hook_hwnd); +} + static const struct message ScrollWindowPaint1[] = { { WM_PAINT, sent }, { WM_ERASEBKGND, sent|beginpaint }, @@ -14946,7 +14994,11 @@ START_TEST(msg) test_timers(); test_timers_no_wnd(); test_timers_exceptions(); - if (hCBT_hook) test_set_hook(); + if (hCBT_hook) + { + test_set_hook(); + test_recursive_hook(); + } test_DestroyWindow(); test_DispatchMessage(); test_SendMessageTimeout(); diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index 1fbecb99fa8..d3affb0c3e7 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -175,6 +175,7 @@ struct user_thread_info DWORD changed_mask; /* Current queue changed mask */ WORD recursion_count; /* SendMessage recursion counter */ WORD message_count; /* Get/PeekMessage loop counter */ + WORD hook_call_depth; /* Number of recursively called hook procs */ BOOL hook_unicode; /* Is current hook unicode? */ HHOOK hook; /* Current hook */ struct received_message_info *receive_info; /* Message being currently received */ -- 2.11.4.GIT