APIs with Denial of Service Issues

APIs with Denial of Service Issues

The APIs in the following sections can lead to a denial of service condition, particularly under low memory conditions.

InitializeCriticalSection and EnterCriticalSection

These functions can throw exceptions in low-memory situations and if the exception is not caught, the application will halt. Consider using InitializeCriticalSectionAndSpinCount instead. Note that EnterCriticalSection will not throw exceptions under Windows XP, Windows .NET Server, and later. Also, be careful not to make blocking networking calls from within a critical section or while holding any other type of lock. Finally, any code within a critical section should be examined carefully. Any exceptions thrown should be caught within the critical section, or you'll end up in an exception handler without calling LeaveCriticalSection. Do the absolute minimum required within a critical section. One way around this when dealing with C++ code is to create a lock object that calls LeaveCriticalSection when the stack unwinds.

_alloca and related functions and macros

_alloca allocates memory on the stack and is freed when the function exits, assuming there is enough memory! In many instances, this function will throw an exception, which if unhandled will halt the process. Be careful of macros that wrap _alloca, such as the ATL character-mapping macros, including A2OLE, T2W, W2T, T2COLE, A2W, W2BSTR, and A2BSTR.

The most generic observation with _alloca is that you should wrap the call in an exception handler and you should not allocate memory based on a size determined by the user.

Finally, you should call _resetstkoflw in the exception handler; this function recovers from a stack overflow condition, enabling a program to continue instead of failing with a fatal exception error. The following sample shows the process:

#include "malloc.h" #include "windows.h" ... void main(int argc, char **argv) { try { char *p = (char*)_alloca(0xfffff); } __except(GetExceptionCode() == STATUS_STACK_OVERFLOW) { int result = _resetstkoflw(); } }

TerminateThread and TerminateProcess

Both of these functions should be called only in an emergency situation. This is especially true with TerminateThread. Any memory, handles, and system resources owned by the thread in question will not get cleaned up. To quote from the Platform SDK:

TerminateThread is a dangerous function that should only be used in the most extreme cases. You should call TerminateThread only if you know exactly what the target thread is doing, and you control all of the code that the target thread could possibly be running at the time of the termination.

The only time it is appropriate to call TerminateThread is if the application is shutting down and one or more threads are not responding. TerminateProcess does not clean up global data owned by DLLs, and most applications should call ExitProcess, unless the process being terminated is external. For those of you used to UNIX systems, TerminateProcess does not clean up resources used by child processes of the parent process. The whole notion of parent and child processes is not fully implemented on Win32 systems.



Writing Secure Code
Writing Secure Code, Second Edition
ISBN: 0735617228
EAN: 2147483647
Year: 2001
Pages: 286

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net