Ariane van der Steldt
  ariane@openbsd.org
   
 
  Content
  pmemrange: the physical memory allocator
  vmmap: the virtual memory allocator
  64-bit and jit
 
  Before pmemrange
  Physical memory was a list of pages.
  
  
  This caused high fragmentation.
  
  Fragmentation is bad for devices.
  
 
  Before pmemrange - it gets worse
  ISA and PCI devices could become starved.
  
  
  ISA and PCI device can no longer make progress.
  
  
    - Devices need memory to progress
- Programs block on data access
- System becomes unresponsive
 
  Pmemrange
  A new physical memory allocator:
  Physical
  Memory
  range
  
  
    - must keep device memory available
- must reduce fragmentation
- may not regress: don't be slower!
 
  Memory allocation
  
  
    - Large fragments grow
- Small fragments shrink and vanish
- Faster than best fit O(1) common case
Pmemrange turned out to be faster than the original code!
  
 
  VM map
  VMmap: mapping Virtual Memory
  
    - keeps track of what is allocated where
- manages virtual memory of kernel and userspace
- performs allocation
 
  Original VMmap
  
    - Introduced around 1999
- First fit allocator
- Code hasn't really change since then
Address Space Layout Randomization tacked on without adapting the underlying algorithm.
  
  
 
  Original address selection
  
    - Randomly pick an address.
- Check if that address is free (do you feel lucky?)
- Otherwise, linear search forward.
Problems:
  
    - Complexity grows quadratic with memory use
      
        - double the memory, double number of entries to walk
- increase the memory, reduce the chance of getting lucky
 
- Forward-only search may yield false negative
      
        - select high random address, skipping all that free space below
 
 
  First replacement
  Best-fit allocator.
  
    - Select close to the best allocation (random number).
- Select random address within that allocation.
The good:
  
    - No false negatives
- O(log n) instead of O(n**2)
 
  First replacement failed
  The bad:
  
    - Some architectures stopped working altogether
- Introduced new bugs
The ugly:
  
    - Webbrowsing was impossible
- Java and mono ceased to function
- Touch the code and an architecture dies
- Randomization was too predictable: not random
 
  How did this break random?
  Investigating what went wrong.
  
    - Placement position of each allocation was random.
- Memory layout was not very random at all.
- An attacker does not need to target specific memory, he just attacks everything and sees what sticks.
Implementation bugs made this worse.
  Randomization did add gaps, but was too predictable in which memory was used.
  
 
  Browsers, java & mono breakage
  They all use JIT (Just In Time) compilation.
  
    - To make byte-code or javascript fast
- They all use PIC (Position Independant Code)
 
  PIC - Position Independant Code
  
  
 
  PIC - Position Independant Code
  PIC makes code agnostic to position.
  Offset is a 32-bit value.
  
    - Sufficient for libraries
      
    
- JITs allocate both parts.
      
    
 
  JIT - pointer clipping
  Aw, Snap!
  
  
 
  JIT - workarounds
  
    - Linux: mmap MAP_32BIT
      
        - it's in API, can never be removed
 
- Chrome: allocate 2 GB up front
      
        - use own memory allocator in there
- Hello predictable attack surface
 
 
  Smart and dumb software
  
    - sizeof(void*) != sizeof(int)
- sizeof(array) > MAXINT
- sizeof(ptrdiff_t) != sizeof(int)
Good software is boring:
  
    - use size_t for sizes
- always check for clipping when translating to another type
 
  VMmap additional requirements
  
    - must not add extra options to mmap
- isolate userland and kernel space fixes
      
        - don't want to break architectures
- kernel memory is very special
 
- must not break browsers
      
        - mmap hint requirements allow ports to rig browser workarounds
 
- must allow easy switching of algorithms
      
        - small commit/backout diffs
 
 
  Split mapping and allocation
  
  
    - Address selectors decide where to allocate
      
        - read access on map
- multiple implementations
 
- Map keeps track of what is allocated where
      
        - informs selectors of modifications
 
- VMmap combines the two together
 
  vm_map - allocation in VMmap
  
  
 
  vm_unmap - unmapping in VMmap
  
  
 
  Compatibility for JIT
  mmap(addr, size, ...)
  Posix says: "A non-zero value of addr is taken to be a suggestion of a process address near which the mapping should be placed"
  
    - WTF? What does near mean?
      
        - in the same machine is pretty near...
- we define near as max 1 GB away (sufficiently near for PIC)
 
- First 4 GB is special: we only allocate there if your hint ≤ 4 GB
Allows us to fix browsers.
  Functionality implemented in hint selector.
  
 
  Better random algorithm
  
    - Random placement of memory
      
        - make it hard to guess a good position
 
- Random gaps between memory
      
        - don't make walking the memory easy
 
Introducing pivot allocator
  
 
  Pivot algorithm
  16 active pivots
  
  
    - Pivots leave gaps between allocations
- Pivots expire every 1024 allocations
- Pivots walk either forward or backwards
Common case: O(1)
  Pivot creation: O(log n)
  Low fragmentation, hard to predict
  
 
  Wrapping it up
  
    - Devices and software are pretty similar
      
        - both have assumptions on pointers
- devices often can't help it: PCI spec is 32-bit
 
    - Software hasn't really improved in 40 years
      
        - first 64-bit machine: Cray-1 (1976)
- the world isn't only i386
- software still trips on 64-bits
- designs are copied without understanding them (why else would JITs forget to cope with 64-bit distance?)
 
- ASLR (Address Space Layout Randomization) is difficult
      
        - our initial implementation got it right, we were lucky