IOS malloc appears to be reference counted. I’ve been trying to get my memcheck code to work, and have been trying to fix up the reports of double frees that have been generated.
I modified memcheck to keep track of any buffers which were reported as being freed twice, and then monitored memory loads and stores to the chunk header. I noticed that at offset 32 in the chunk header, a field holding 2 was being changed to 1. Also being written to the chunk at offset 36 [edit: i did this from memory, but i should probably check this again] was the address of a free() call (well, the address + 8 to skip the jump and link instruction, and the delay slot. aka, the return address).
I suspected this field holding 2 was the reference count. It is documented partly by people who have written heap exploits for IOS, though the offsets are not the same as publicly documented (It appears IOS changed the chunk header in recent versions).
The goal is to find a function that incremements the reference count. I built a runtime call trace, and kept track of functions which wrote to allocated buffers at the offset of the reference count field. A small list of functions wrote to this field, including free(), which makes sense. Loading the functions in IDA, it appeared one was obviously incrementing the field using MIPS atomic read write modify instruction. This was the function I was after.
I tried plugging the new information into memcheck, but now appear to be getting frees without any associated malloc. I track this down to the fact that malloc calls itself recursively, and I was only identifying its return value on its outer most call. Free doesnt appear to call itself recursively, I will fix up my last post which mistakenly said free and not malloc called itself recursively. But a recursive malloc is tricky, and doesn’t work nicely..
It appears that on some occasions, malloc is called, say with a requested buffer size of 44. Then a recursive call is made with a size of 64k. This buffer of 64k is reference counted and freed at a later time. BUT.. while the inner malloc returns this buffer of 64k, the outer malloc returns a pointer, offset in the buffer. It appears that these offseted pointers are also explicitly freed. And it also appears, that there are multiple occurances when mallocing a small size returns more offsets into the already allocated 64k buffer.
It appears that some kind of memory pooling is going on.. But this is something to tackle another day..
Lets just hope I’m not going on a wild goose chase with all these ‘additional’ cases to handle with malloc.