> It would also be interesting to try out a more aggressive form of
> freeunmap for 64-bit where the allocations are purged with MADV_FREE
> and then the virtual memory is kept out of circulation with a similar
> FIFO queue approach. Could potentially do it by default when malloc
> hints are enabled, so it wouldn't need a new option exposed (but it
> would change the MADV_FREE option into something that enhances security
> at the expense of more VM fragmentation rather than a performance vs.
> memory trade-off so that may not make much sense after all).
> 
> It's the same issue as the junk validation feature where there's a need
> for a reliable delay to get the most out of the feature. Randomization
> does help, but it's not as good as knowing that virtual memory doesn't
> go back into circulation until some configured amount of allocator
> throughput has occurred.

Kept out of circulation?  It sounds like it would be incredibly
expensive data-structure wise for the kernel to even attempt such a
gaurantee..

On a 64-bit VA / 48-bit PA system, the address space should be large
enough that this does not occur commonly due to mmap ASLR; or at
least, when it does occur, the reuse cannot be predicted usably.

So what is the purpose of your proposal?  Is it to opportunistically
find bugs?  Or to resist attack in UAF situations by "gauranteeing"
the memory is unallocated at time of reuse?

#include <sys/types.h>
#include <sys/mman.h>
#include <stdio.h>

main()
{
        int max = 100000;

        while (max--) {
                void *p = mmap(NULL, 4096, PROT_READ, MAP_ANON, -1, 0);
                munmap(p, 4096);
                printf("%p\n", p);
        }
}

./test | sort | uniq -c | sort -n | awk '{print $1}' | sort | uniq -c

90880 1      (addresses only used once)
 4314 2
  123 3
    3 4
    1 111    (I wonder what this subtle bias is due to)

These are independent allocations of course, but maybe we can get a trend
out of this.  Except in really large memory programs, I suspect a UAF would
find the memory unallocation, as long as free() has pushed it out via
munmap().  (Curiously, your other proposal is about the part of the cache
which is not munmap()'d...)

Add in the subtle effects of guarding we also do, and it seems we are
in good shape.

Maybe you are on a system with where mmap ASLR isn't as good?  The
OpenBSD one isn't perfect, because we are trying to maintain a small
amount of page-table locality (so that N-level page tables don't have
to be walked fully from root for every access that misses in the TLB).

The result above feels "good enough" to make reliable UAF attack after
free()->munmap() very difficult.  Am I missing something which would
justify what seems like a huge cost?

Reply via email to