The scneario -> calling malloc(small value) causes a recursive call to malloc which allocates a 64k buffer (i’ll call it a pool), and returns a pointer, or fragment to inside that pool. In later calls to malloc, it may or may not fragments.
Not much success today.. The only thing I could gather, was that at offset 32 in the malloc chunk header, which is used to hold the reference count, this field is also used to indicate the chunk is a malloc fragment. By fragment, I mean that the chunk is actually contained within the data section of another allocated buffer. The magic number that is used is 0x15a3c78b. If this magic number is set, then offset 44 in the chunk header seems to point to the malloc chunk data that holds the fragment.
There is logic in free() that checks if a chunk is a fragment, but I’ve been unable to decipher what it does (my MIPS asm is not that good). There is also a function that incrememnts a chunks reference count (I found this by searching for immediate values of the magic constant in IDA). If this function identifies the chunk as a fragment, it increments the field at offset 36 in the chunk header using the atomic read modify write instructions. This would seem to indicate it is a reference count. I just couldn’t find logic in free() that decremented the reference count, which stopped me from clearly confirming that it is a reference count. [edit: Later that evening, I found a codepath from free() to decrementing the refcnt in the malloc fragment, so it seems pretty convincing that each fragment has a refcnt associated with it]
Besides that, nothing of interest.. i saw some memory writes of 0x0b0d0b0d in some buffers but couldnt clearly find the logic of when to use this fill value. I’m also at a loss to when malloc should use fragments and when it should not. Perhaps there is a global function that starts/stops using malloc pools. It might be a good idea to implement naive taint propogation so I can see where the references to the malloc pool are going.
Note that this fragment strategy in IOS 12.x uses chunk fields which appear not to exist in 11.x (according to public docs on the chunk layout).