Heap overruns

Shachar Shemesh wine-devel at sun.consumer.org.il
Sun Sep 1 16:22:44 CDT 2002

Huw D M Davies wrote:

>On Sun, Sep 01, 2002 at 11:33:55PM +0300, Shachar Shemesh wrote:
>>Marcus Meissner wrote:
>>>On Sun, Sep 01, 2002 at 12:17:38PM +0300, Shachar Shemesh wrote:
>>>>Hi list,
>>>>I am currently having some problems with a change I am working on, that 
>>>>result in heap corruption as a result of buffer overrun. I was wondering 
>>>>whether there was any builtin debug options to detect and help fix these 
>>>>If there aren't, I am perfectly willing to sidetrack a little and write 
>>>>them. Please let me know.
>>>If you run with -debugmsg +heap it will check the heaps at every access
>>>for corruption.
>>>Ciao, Marcus
>>Thanks, but this is not what I meant.
>>Currently, when a buffer overruns, the free pointers right after get 
>>corrupted, and when the next piece of block is allocated, the machine 
>>will crash. This will tell me approximetly where the buffer overrun, but 
>>is, generally speaking, too late. Enabling the debug messages detects 
>>the error at the same place (i.e. - too late).
>>What I am talking about is a compile time (or run time, no reason why 
>>not) option that will add "hot zone" areas before and after each heap 
>>allocated buffer. These zones should be:
>>A. Large enough so that the overrun doesn't reach the heap managment 
>>structures themselves. This means that the program can keep on running 
>>despite having the buffer overflow.
>>B. Identifiable, so that we know if a buffer has overwritten it.
>No, as Marcus says, enabling +heap debugging forces the entire heap to
>be checked for consistency on every HeapAlloc/Free/ReAlloc .  So if
>you overwrite a block you'll get an error the next time you call a
>heap function (on the same heap) and not only when the system tries
>the alloc the next block.  So, if you see heap corruption this way,
>you can assume that it occured somewhere between this point and the
>last time you called a heap function.
I'm sorry, but my experience is totally different.

First, I would like to say that I have found the offending allocation.

The problem was with not allocating enough memory (enough for the single 
width string, not the double width string). Classical mistake. The 
traces proved useless for several reasons:
A. The first place the assertation failed is the same place that wine, 
without the debug option, would crash. This place is far away from the 
actual allocation OR freeing of the offending buffer. Having the error 
point at the actual offending buffer will make life much easier for the 
debugger (IMHO).
B. The current mechanism obviously doesn't work well. By the time the 
crash/assertion happen, both magic and the value before that seem to be 
valid for the offending pointer block, but both previous and next 
pointers were values taken from the middle of my buffer (I could 
recognize the string). This suggests to me that several alloc/free 
operations happened before the problem was spotted, migrating the 
overwritten values to other nodes. The mechanism did not catch that.
C. The code I am working with is code I previously removed from Wine, 
and am now trying to restore. In addition to the serious overrun, it 
also has an "off by one", where a single NULL is written past the end of 
the buffer. Running the code with debug +heap does not reveal that.

Implementing my suggested system will:
A. not hurt the programs operation (despite the overrun), and so the 
relevant buffer can be found as soon as it is "HeapFree"ed. This means 
pointing at the actual buffer.
B. Even if this is a buffer overrun coupled with a memory leak (HeapFree 
is NEVER called), we can verify all the hot zones signatures on each 
heap operation (the same way we do today for the linked list), and give 
the actual pointer to the offending buffer (which now merely becomes a 
game of catching who allocated that, almost trivial with +relay)

I'm afraid I won't do it now, as I have found my curlpit, and have 
bigger itches to scratch. I am suspectful of off by ones creeping up.


Being a security expert as my alter ego, I couldn't help but notice the 
places where we are vulnerable to integer overflow attacks. For the 
uninitiated, these are attacks where the attacker minpulates the sizes 
so that a very big number to be allocated, after being multiplied by the 
element size, overflows to be a very small number. The attacker can then 
overrun this small buffer, point the execution path into attacker 
supplied buffer, and gain control of a program.

In order to solve this we need to supply a function to perform the 
multiplication for us (HeapAllocElement(Heap, flags, num, element_size) 
sort of thing), which will check against this condition and then call 
HeapAlloc. Are there any objections? I know Wine is just Alpha, and 
noone is supposed to trust it, yadda yadda yadda, but I'm thinking 
"better early than late".


More information about the wine-devel mailing list