FAQ about HeapSetInformation in Windows Vista and Heap Based Buffer Overruns

2/19 - Added some Minor Tweaks

Perhaps it's the phase of the moon or something, but over the last few weeks I have received more email about correctly using the HeapSetInformation function than any other topic. I really don't know why! This was added last year as an SDL requirement.

So here's a quick FAQ:

Q: What does the HeapSetInformation function do?
A: It lets your application configure the Windows heap manager with a small number of options. The only security-related setting kills your application in case of heap corruption.

Q: What do you mean by "heap corruption"?
A: Anything that messes with data in the Windows heap, for example damaged caused by a buffer overrun, writing to a stray pointer or a double-free are examples.

Q: How do I use the function?
A: Like this:

BOOL f=HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);

Q: What should my code do if the function fails?
A: I think it's really up to you as this is not a critical failure, the call should only fail on a platform that does not support termination-on-corruption. This function offers a defense in depth, and is not required for successful operation of an application. So personally, I would just keep on running.

Q: What does this buy me?
A: Assume you code has a heap-based buffer overrun that you do not know about (because if you knew about it, you'd remove it!) If an attacker attempts to exploit it, there is a reasonable chance the attack might make the application crash rather than running exploit code.

Q: What if my code is Windows Vista and later only, can I use a linker option?
A: Yes, link with /SUBSYSTEM:WINDOWS,6.0

Q: Is this a "slam dunk" defense?
A: No. There is a no replacement for secure code, this is just a speed bump designed to make it harder for attackers to exploit heap-based vulnerabilities.

Q: When and where should I use this?
A: All the time - just add the code to your main() function.

Q: Which versions of Windows support termination on heap corruption?
A: Windows Vista and Windows Server 2008

Q: So what happens if I call HeapSetInformation with this option on a down-level version of Windows?
A: It's a no-op. you can call HeapSetInformation, but you simply won't get the defense.

Q: What about 64-bit Windows?
A: There is no need to call this API, the operating system enables termination-on-corruption by default. But you should call it anyway, because your code might run on 32-bit Windows.
A: By default, all 64-bit applications running on 64-bit Windows Vista or Windows Server 2008 get this defense by default, there is no need to call the function. A 32-bit application running on 64-bit Windows does not get the defense for free, the code must call the function.

Q: So if this is available on Windows Vista and Windows Server 2008 and later, do I need to use the Windows Vista (or later) SDKs?
A: No. The termination-on-corruption option is just a flag, so you could use code like the following if you're using an older SDK:

#ifndef HeapEnableTerminationOnCorruption
# define HeapEnableTerminationOnCorruption (HEAP_INFORMATION_CLASS)1

Q: Is there a performance hit.
A: No.

Q: Is there an application compatibility hit?
A: Possibly, but in my analysis of real world code: no. If your application crashes because of this API, and it never happened in the past without this API, then I suppose technically, that's a compatibility issue. However, you just hit some form of heap corruption which you need to fix, so fix the bug and remove the application compatibility issue!

Q: Is this still of use if grab a hunk of heap, and then perform my own sub-allocations? In other words, I have my own memory allocation system, and only use the operating system to give me the first chunk.
A: Since this API activates extra checking in the Windows heap manager, your sub-allocator won’t necessarily get much benefit. If you want to harden your implementation, make sure your allocator doesn’t include complex control structures or pointers in each block header. While we’re on the subject, is it crucial for you to have a sub-allocator anyway?