Author: tkreuzer Date: Mon May 17 00:24:26 2010 New Revision: 47246
URL: http://svn.reactos.org/svn/reactos?rev=47246&view=rev Log: [KERNEL32] Protect GlobalLock, GlobalUnlock and GlobalSize with SEH, use IsBadReadPtr in GlobalLock. Inspired by wine code. Fixes user32_winetest dde crash.
Modified: trunk/reactos/dll/win32/kernel32/mem/global.c
Modified: trunk/reactos/dll/win32/kernel32/mem/global.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/kernel32/mem/glob... ============================================================================== --- trunk/reactos/dll/win32/kernel32/mem/global.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/kernel32/mem/global.c [iso-8859-1] Mon May 17 00:24:26 2010 @@ -380,44 +380,53 @@ /* Check if this was a simple allocated heap entry */ if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)) { - /* Then simply return the pointer */ - return hMem; + /* Verify and return the pointer */ + return IsBadReadPtr(hMem, 1) ? NULL : hMem; }
/* Otherwise, lock the heap */ RtlLockHeap(hProcessHeap);
- /* Get the handle entry */ - HandleEntry = BaseHeapGetEntry(hMem); - BASE_TRACE_HANDLE(HandleEntry, hMem); - - /* Make sure it's valid */ - if (!BaseHeapValidateEntry(HandleEntry)) - { - /* It's not, fail */ - BASE_TRACE_FAILURE(); + _SEH2_TRY + { + /* Get the handle entry */ + HandleEntry = BaseHeapGetEntry(hMem); + BASE_TRACE_HANDLE(HandleEntry, hMem); + + /* Make sure it's valid */ + if (!BaseHeapValidateEntry(HandleEntry)) + { + /* It's not, fail */ + BASE_TRACE_FAILURE(); + SetLastError(ERROR_INVALID_HANDLE); + Ptr = NULL; + } + else + { + /* Otherwise, get the pointer */ + Ptr = HandleEntry->Object; + if (Ptr) + { + /* Increase the lock count, unless we've went too far */ + if (HandleEntry->LockCount++ == GMEM_LOCKCOUNT) + { + /* In which case we simply unlock once */ + HandleEntry->LockCount--; + } + } + else + { + /* The handle is still there but the memory was already freed */ + SetLastError(ERROR_DISCARDED); + } + } + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { SetLastError(ERROR_INVALID_HANDLE); Ptr = NULL; } - else - { - /* Otherwise, get the pointer */ - Ptr = HandleEntry->Object; - if (Ptr) - { - /* Increase the lock count, unless we've went too far */ - if (HandleEntry->LockCount++ == GMEM_LOCKCOUNT) - { - /* In which case we simply unlock once */ - HandleEntry->LockCount--; - } - } - else - { - /* The handle is still there but the memory was already freed */ - SetLastError(ERROR_DISCARDED); - } - } + _SEH2_END
/* All done. Unlock the heap and return the pointer */ RtlUnlockHeap(hProcessHeap); @@ -702,65 +711,74 @@ /* Lock the heap */ RtlLockHeap(hProcessHeap);
- /* Check if this is a simple RTL Heap Managed block */ - if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)) - { - /* Then we'll query RTL Heap */ - RtlGetUserInfoHeap(hProcessHeap, Flags, hMem, &Handle, &Flags); - BASE_TRACE_PTR(Handle, hMem); - - /* - * Check if RTL Heap didn't give us a handle or said that this heap - * isn't movable. - */ - if (!(Handle) || !(Flags & BASE_HEAP_FLAG_MOVABLE)) - { - /* This implies we're not a handle heap, so use the generic call */ - dwSize = RtlSizeHeap(hProcessHeap, HEAP_NO_SERIALIZE, hMem); - } - else - { - /* Otherwise we're a handle heap, so get the internal handle */ - hMem = Handle; - } - } - - /* Make sure that this is an entry in our handle database */ - if ((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY) - { - /* Get the entry */ - HandleEntry = BaseHeapGetEntry(hMem); - BASE_TRACE_HANDLE(HandleEntry, hMem); - - /* Make sure the handle is valid */ - if (!BaseHeapValidateEntry(HandleEntry)) + _SEH2_TRY + { + /* Check if this is a simple RTL Heap Managed block */ + if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)) + { + /* Then we'll query RTL Heap */ + RtlGetUserInfoHeap(hProcessHeap, Flags, hMem, &Handle, &Flags); + BASE_TRACE_PTR(Handle, hMem); + + /* + * Check if RTL Heap didn't give us a handle or said that this heap + * isn't movable. + */ + if (!(Handle) || !(Flags & BASE_HEAP_FLAG_MOVABLE)) + { + /* This implies we're not a handle heap, so use the generic call */ + dwSize = RtlSizeHeap(hProcessHeap, HEAP_NO_SERIALIZE, hMem); + } + else + { + /* Otherwise we're a handle heap, so get the internal handle */ + hMem = Handle; + } + } + + /* Make sure that this is an entry in our handle database */ + if ((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY) + { + /* Get the entry */ + HandleEntry = BaseHeapGetEntry(hMem); + BASE_TRACE_HANDLE(HandleEntry, hMem); + + /* Make sure the handle is valid */ + if (!BaseHeapValidateEntry(HandleEntry)) + { + /* Fail */ + BASE_TRACE_FAILURE(); + SetLastError(ERROR_INVALID_HANDLE); + } + else if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSE) + { + /* We've reused this block, but we've saved the size for you */ + dwSize = HandleEntry->OldSize; + } + else + { + /* Otherwise, query RTL about it */ + dwSize = RtlSizeHeap(hProcessHeap, + HEAP_NO_SERIALIZE, + HandleEntry->Object); + } + } + + /* Check if by now, we still haven't gotten any useful size */ + if (dwSize == MAXULONG_PTR) { /* Fail */ BASE_TRACE_FAILURE(); SetLastError(ERROR_INVALID_HANDLE); - } - else if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSE) - { - /* We've reused this block, but we've saved the size for you */ - dwSize = HandleEntry->OldSize; - } - else - { - /* Otherwise, query RTL about it */ - dwSize = RtlSizeHeap(hProcessHeap, - HEAP_NO_SERIALIZE, - HandleEntry->Object); - } - } - - /* Check if by now, we still haven't gotten any useful size */ - if (dwSize == MAXULONG_PTR) - { - /* Fail */ - BASE_TRACE_FAILURE(); + dwSize = 0; + } + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { SetLastError(ERROR_INVALID_HANDLE); dwSize = 0; } + _SEH2_END
/* All done! Unlock heap and return the size */ RtlUnlockHeap(hProcessHeap); @@ -798,31 +816,40 @@ HandleEntry = BaseHeapGetEntry(hMem); BASE_TRACE_HANDLE(HandleEntry, hMem);
- /* Make sure it's valid */ - if (!BaseHeapValidateEntry(HandleEntry)) - { - /* It's not, fail */ - BASE_TRACE_FAILURE(); - SetLastError(ERROR_INVALID_HANDLE); + _SEH2_TRY + { + /* Make sure it's valid */ + if (!BaseHeapValidateEntry(HandleEntry)) + { + /* It's not, fail */ + BASE_TRACE_FAILURE(); + SetLastError(ERROR_INVALID_HANDLE); + RetVal = FALSE; + } + else + { + /* Otherwise, decrement lock count, unless we're already at 0*/ + if (!HandleEntry->LockCount--) + { + /* In which case we simply lock it back and fail */ + HandleEntry->LockCount++; + SetLastError(ERROR_NOT_LOCKED); + RetVal = FALSE; + } + else if (!HandleEntry->LockCount) + { + /* Nothing to unlock */ + SetLastError(NO_ERROR); + RetVal = FALSE; + } + } + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + SetLastError(ERROR_INVALID_PARAMETER); RetVal = FALSE; } - else - { - /* Otherwise, decrement lock count, unless we're already at 0*/ - if (!HandleEntry->LockCount--) - { - /* In which case we simply lock it back and fail */ - HandleEntry->LockCount++; - SetLastError(ERROR_NOT_LOCKED); - RetVal = FALSE; - } - else if (!HandleEntry->LockCount) - { - /* Nothing to unlock */ - SetLastError(NO_ERROR); - RetVal = FALSE; - } - } + _SEH2_END
/* All done. Unlock the heap and return the pointer */ RtlUnlockHeap(hProcessHeap);