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:
>>>>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
>>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
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