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