Year after year, Apple continues to quietly (or not so quietly) tighten the screws, introducing new security mitigations into iOS. Many of these have already been documented by researchers. But today, I'd like to talk about something new: TPRO regions. They were introduced way back in ~22C152, yet somehow managed to stay under the radar all this time.
TPRO (presumably standing for Trusted Path Read-Only) is an SPRR-based data protection mechanism designed to prevent memory overwrites via arbitrary writes. The easiest way to think of it is as a trampoline that temporarily makes memory writable within a critical section. A perfect example to illustrate this is one of the functions in dyld.
The trampoline's first step is to check the commpage at @0xfffffc10c to verify if the target device has hardware support for TPRO. This most likely corresponds to the cp_aprr_shadow_supported field from the open-source headers. Additionally, the commpage at @0xfffffc0d0 stores two values for the S3_6_C15_C1_5 register, which differ by only a single bit in the ninth attribute.
Combining this with our knowledge of SPRR (where S3_6_C15_C1_5 stores a value split into 16 attributes, each dictating page-type permissions for different Exception Levels [EL]), we can deduce that the first value represents RW permissions (3 = 0011), while the second represents RO (2 = 0010).
The next step is to replace the value in S3_6_C15_C1_5 with cp_aprr_shadow_tpro_rw from the commpage. Once the isb instruction is executed, this immediately alters the permissions across all TPRO pages.
From this point on, the memory becomes writable. A callback is then executed, and upon its completion, a similar procedure reverts the permissions to their normal state. If any write attempts are made after this, the kernel will kill the process with OS_REASON_SELF_RESTRICT.
And that's the entire mitigation. On the one hand, it's quite primitive (though it definitely complicates the lives of WebKit pwners), but on the other hand, it's elegant and holds a lot of potential.
PS1: Anticipating questions from the curious: you cannot arbitrarily modify S3_6_C15_C1_5 from EL0. Generally speaking, almost all bits will be locked out for you.
PS2: The logic for toggling permissions on MAP_JIT pages from RW to RX was implemented in a very similar fashion.