1*aca3beaaSApple OSS Distributions# The Read-Only Allocator 2*aca3beaaSApple OSS Distributions 3*aca3beaaSApple OSS Distributions## Introduction 4*aca3beaaSApple OSS Distributions 5*aca3beaaSApple OSS DistributionsThe Read-Only Allocator is an extension of the zone allocator that facilitates 6*aca3beaaSApple OSS Distributions"read-only" allocations. Data allocated from a read-only zone can only be 7*aca3beaaSApple OSS Distributionsmodified programmatically through the `zalloc_ro_mut` function. 8*aca3beaaSApple OSS Distributions 9*aca3beaaSApple OSS DistributionsRead-only zones are intended for very specific use cases where the data being 10*aca3beaaSApple OSS Distributionsmanaged directly affects runtime security decisions. 11*aca3beaaSApple OSS Distributions 12*aca3beaaSApple OSS Distributions## Discussion 13*aca3beaaSApple OSS Distributions 14*aca3beaaSApple OSS DistributionsThe purpose of the Read-Only Allocator is to protect security- 15*aca3beaaSApple OSS Distributionssensitive data from being targeted by memory corruption vulnerabilities. 16*aca3beaaSApple OSS Distributions 17*aca3beaaSApple OSS DistributionsWhile, historically, the modus operandi for an advanced attacker is to seize 18*aca3beaaSApple OSS Distributionscontrol of kernel execution, advances in control flow integrity defenses, such 19*aca3beaaSApple OSS Distributionsas PAC, means that today's attacker favors data-only attacks to achieve 20*aca3beaaSApple OSS Distributionscompromise. Typically this involves using a controlled write primitive to 21*aca3beaaSApple OSS Distributionstarget data structures in the kernel's memory that effectively disables or 22*aca3beaaSApple OSS Distributionsbypasses obstacles standing in the way of the desired data. 23*aca3beaaSApple OSS Distributions 24*aca3beaaSApple OSS DistributionsBy necessity, we store lots of data on the heap that informs the various 25*aca3beaaSApple OSS Distributionssecurity mechanisms on our platforms. The heap traditionally dispenses 26*aca3beaaSApple OSS Distributionsdirectly mutable allocations because this fits what we need the memory for: 27*aca3beaaSApple OSS Distributionsfrequent, fast and easy read/write access to memory. Unfortunately, these are 28*aca3beaaSApple OSS Distributionsalso the requirements for an attacker looking to exploit a controllable write 29*aca3beaaSApple OSS Distributionsinto kernel memory. 30*aca3beaaSApple OSS Distributions 31*aca3beaaSApple OSS DistributionsFor globals, `SECURITY_READ_ONLY_(EARLY|LATE)` provides an elegant protection 32*aca3beaaSApple OSS Distributionsmechanism, but unfortunately that doesn't cater for dynamic runtime 33*aca3beaaSApple OSS Distributionsallocations. 34*aca3beaaSApple OSS Distributions 35*aca3beaaSApple OSS DistributionsThis is where the Read-Only Allocator provides its defense: we observe that 36*aca3beaaSApple OSS Distributionsthe majority of security-sensitive data that we allocate on the heap tends to 37*aca3beaaSApple OSS Distributionsbe written into memory once and seldom changed thereafter. We can therefore 38*aca3beaaSApple OSS Distributionstrade some of this ease of access in exchange for stronger guarantees on the 39*aca3beaaSApple OSS Distributionsintegrity of the data. 40*aca3beaaSApple OSS Distributions 41*aca3beaaSApple OSS DistributionsData under the control of the Read-Only Allocator can be read from just as 42*aca3beaaSApple OSS Distributionscheaply and easily as other data, but writing to it must be done through the 43*aca3beaaSApple OSS Distributionsrelatively expensive `zalloc_ro_mut` function. By insisting that data be 44*aca3beaaSApple OSS Distributionswritten programmatically (i.e. through calling a function), we raise the cost 45*aca3beaaSApple OSS Distributionsof targeting that data towards the cost of seizing control of kernel 46*aca3beaaSApple OSS Distributionsexecution. 47*aca3beaaSApple OSS Distributions 48*aca3beaaSApple OSS Distributions 49*aca3beaaSApple OSS Distributions## Data Structure Strategies 50*aca3beaaSApple OSS Distributions 51*aca3beaaSApple OSS DistributionsTo make best use of the Read-Only Allocator, some simple advice should be 52*aca3beaaSApple OSS Distributionsfollowed: 53*aca3beaaSApple OSS Distributions 54*aca3beaaSApple OSS Distributions1. Pointers to read-only elements should either reside in read-only memory 55*aca3beaaSApple OSS Distributions themselves, or be protected by PAC. 56*aca3beaaSApple OSS Distributions2. Where there is a 1:1 mapping between read/write and read-only elements, the 57*aca3beaaSApple OSS Distributions read-only element should include a pointer back to the read/write side (a 58*aca3beaaSApple OSS Distributions "back reference") that is validated when traversing from read/write to 59*aca3beaaSApple OSS Distributions read-only. 60*aca3beaaSApple OSS Distributions 61*aca3beaaSApple OSS DistributionsOn Point 1: data structures are typically stored through chains of pointers -- 62*aca3beaaSApple OSS Distributionse.g. a thread points to its task, which points to its proc, which points to 63*aca3beaaSApple OSS Distributionsits credential. The principle here is to ensure the integrity of the entire 64*aca3beaaSApple OSS Distributionschain from source pointer (e.g. thread) to destination data (e.g. credential). 65*aca3beaaSApple OSS Distributions 66*aca3beaaSApple OSS DistributionsOn Point 2: by storing a back reference on the read-only side of 1:1 67*aca3beaaSApple OSS Distributionsrelationships, we can validate the ownership invariant that we expect to hold. 68*aca3beaaSApple OSS DistributionsIf this is violated, it suggests that a use-after-free has happened -- perhaps 69*aca3beaaSApple OSS Distributionsthrough a genuine bug, or perhaps by an attacker targeting the zone allocator 70*aca3beaaSApple OSS Distributionsitself. 71*aca3beaaSApple OSS Distributions 72*aca3beaaSApple OSS Distributions## Should I Use the Read-Only Allocator? 73*aca3beaaSApple OSS Distributions 74*aca3beaaSApple OSS DistributionsThe Read-Only Allocator is intended to protect data from very specific 75*aca3beaaSApple OSS Distributionsthreats. This means that for most data, it simply doesn't make sense to use 76*aca3beaaSApple OSS Distributionsit. Its use is primarily geared toward allocations supporting security 77*aca3beaaSApple OSS Distributionsboundaries such as labels, sandboxing, audit tokens, etc. 78*aca3beaaSApple OSS Distributions 79*aca3beaaSApple OSS Distributions 80*aca3beaaSApple OSS Distributions## API 81*aca3beaaSApple OSS Distributions 82*aca3beaaSApple OSS DistributionsRead-only zones cannot be created after lockdown. To create a new read-only 83*aca3beaaSApple OSS Distributionszone, a new identifier must be added to the `zone_reserved_id_t` enumeration 84*aca3beaaSApple OSS Distributionsand it must be created by passing `ZC_READONLY` through either `ZONE_INIT` or 85*aca3beaaSApple OSS Distributions`zone_create_ext`. 86*aca3beaaSApple OSS Distributions 87*aca3beaaSApple OSS DistributionsWe require identifiers for read-only zones for two reasons: firstly to ensure 88*aca3beaaSApple OSS Distributionsthat we're making conscious, considered choices over which zones are made 89*aca3beaaSApple OSS Distributionsread-only, and secondly to allow for more stringent validation at the API 90*aca3beaaSApple OSS Distributionsboundary. 91*aca3beaaSApple OSS Distributions 92*aca3beaaSApple OSS DistributionsOnce a read-only zone is created, the API for using it is small and simple. 93*aca3beaaSApple OSS DistributionsThe key functions are: 94*aca3beaaSApple OSS Distributions 95*aca3beaaSApple OSS Distributions- `zalloc_ro`: Allocate an element from a read-only zone. 96*aca3beaaSApple OSS Distributions- `zfree_ro`: Free an element back to a read-only zone. Note that this is a 97*aca3beaaSApple OSS Distributions macro that automatically zeroes the pointer after freeing. 98*aca3beaaSApple OSS Distributions- `zone_require_ro`: Verify that an element belongs to a given read-only zone 99*aca3beaaSApple OSS Distributions and panic if it doesn't. 100*aca3beaaSApple OSS Distributions- `zalloc_ro_mut`: Modify part of an element allocated from a read-only zone. 101*aca3beaaSApple OSS Distributions Think of this as a special `memcpy` to write into your elements. 102*aca3beaaSApple OSS Distributions- `zalloc_ro_update_elem`: A convenience function for calling `zalloc_ro_mut` 103*aca3beaaSApple OSS Distributions over the entirety of an element: simply passes an offset of zero and size 104*aca3beaaSApple OSS Distributions equal to the size of the elements in the zone. 105*aca3beaaSApple OSS Distributions 106*aca3beaaSApple OSS DistributionsNote that `zfree_ro`, `zalloc_ro_mut` and `zalloc_ro_update_elem` will 107*aca3beaaSApple OSS Distributionsperform a `zone_require_ro` on the element themselves; there's no need to do 108*aca3beaaSApple OSS Distributionsthis manually beforehand. 109