Hacker News new | ask | show | jobs
by hlandau 702 days ago
My own view on this is that a hardened allocator API should separate the functions of an allocation identifier/cookie and the actual pointer to the allocated memory:

    func alloc(numBytes: usize) -> (ptr: void *, cookie: uword) | Error
    func free(cookie: uword, numBytes: usize) -> void
where free() maybe also should take ptr, strictly for validation purposes.

A design like this encourages segregation of allocator metadata and the allocated memory, though it is possible to achieve such a design with the classic C malloc/free API.

However, a design like this is even more helpful against use-after-free because cookies can be unique for the lifetime of a program, whereas pointers naturally get reused when a block of memory is reallocated. So the traditional API can never be fully resilient against UAF, whereas an API like this can.

The underlying observation here is that malloc/free couples two different things (access to memory and identifying a previously made allocation) in a way that creates an API which is far less able to mitigate misuse in a safe way. IMO, these functions should be separated in new designs.

2 comments

The downside with always-unique cookies would be that you'd necessarily need some lookup data structure on both alloc and free, which is gonna be pretty expensive, both in memory usage (at least 16-byte entries, multiplied by load factor) and performance (essentially guaranteed cache misses on both alloc and free, unless you have generational lookup tables). Or, worse, some tree structure if you don't want some allocations to have to resize the entire hashtable. That's two things from the GC world - generational allocations, and stop-the-world pauses vs even more significant overhead :)

What it solves is double-free, not use-after-free; potential corruption (even if not of the allocator state) is always gonna be a problem with any allocator that ever reuses memory.

Indeed, double-free, not UAF; I should know better than to write comments while sleep-deprived...

I suppose a cookie could be used in a "trust, but verify" approach if the free function takes both a pointer and a cookie. You would have the usual sidecar data next to the allocated region, but verify that the cookie matches. This would avoid the lookup issues you discuss.

How would it help with use-after-free?