Massive Security Update
Pixel 8 Series + Graphene OS
OVERVIEW
The new Pixel 8 Series Phones running Graphene OS have received a massive update to their defences against remote exploitation, yielding an incredible 70% Reduction in Security Vulnerabilities. It significantly widens the security advantage over other Secure Phones, the iPhone or Standard OS Pixel, until they get default enabled memory tagging support. A serious game changer in phone security.
We also flash Pixel 8 Phones with Graphene OS and express post Australia Wide and to NZ UK EU CA.
REPORT September 2023
Pixel 8 and Pixel 8 Pro are ARMv9 devices supporting hardware memory tagging. Stock OS currently has a very primitive experimental implementation available as a developer option. We're going to be deploying a more advanced implementation for hardened_malloc in production soon.
Hardware memory tagging is going to provide a massive increase to protection against remote exploitation for GrapheneOS users. It's the biggest security feature we'll be shipping since we started in 2014. We want to have it enabled by default in async (fast) mode for the base OS.
We can provide a toggle for choosing between asynchronous (fast) and synchronous (more secure).
Many user installed apps have latent memory corruption bugs so we aren't going to enable it for them initially. We'll provide a toggle for setting the default (disabled, async, sync).
There can be a per-app toggle for overriding the global default alongside the toggles we already provide for using the full 48-bit address space (enabled by default) and hardened malloc (enabled by default, requires 48-bit address space). This will be a security game changer.
ARM memory tagging support provides a limited form of memory safety for both memory unsafe languages (C, C++) and the small subset of unsafe code in memory safe languages (Rust, Java, Kotlin). hardened_malloc was designed to use memory tagging and will be making great use of it.
MTE uses 4 bit tags for each 16 bytes of memory. hardened_malloc will be using memory tagging for all small allocations, which means 128k and below by default. hardened_malloc already places random guards around large allocations and quarantines their address space on free.
UPDATE October 2023
We've been making more progress on hardware memory tagging support for Pixel 8 and Pixel 8 Pro. Our initial hardened_malloc integration has no noticeable overhead in fastest asynchronous mode and the asymmetric mode is lower overhead than legacy mitigations like stack canaries.
Asynchronous is very fast but can be bypassed via races. Synchronous is very high overhead and aimed at debugging. It's still much faster than HWAsan (based on Top Byte Ignore) and especially ASan. Asymmetric is nearly as fast as asynchronous and as secure as synchronous.
There isn't any clear way to bypass asynchronous wrote checks for the asymmetric mode since they're checked immediately on reads and system calls. io_uring might be able to bypass it, but it's not relevant since it's only allowed for 2 core SELinux domains (fastbootd, snapuserd).
We plan to enable memory tagging by default in asymmetric mode for the whole base OS including system apps. For user installed apps, our plan is to enable it by default for app processes without their own native code. It will be opt-in for apps with native code for compatibility.
Memory tagging is going to be a huge game changer and GrapheneOS will be on the leading edge deploying it. Stock Pixel OS has it as a developer option which isn't usable in practice since it breaks far too much. The implementation is also much less powerful than hardened_malloc.
Initial hardened_malloc implementation sets random tags for each 128k byte and below allocation. It excludes tags of adjacent allocations and reserves a tag for free allocations. It fully prevents sequential overflows as a vulnerability class and freed memory can't be accessed.
Use-after-free is detected until another allocation is made in the same slot with the same random tag chosen for it. hardened_malloc already defends this by quarantining freed allocations by default. They go through a First-In-First-Out ring buffer and a swap with a random array.
Arbitrary read/write via buffer overflows are caught by the random tags. They're unfortunately currently only 4 bit, but a future architecture revision could raise them to 8 bit. CFI, PAC, etc. only try to defend specific targets and don't work well against arbitrary read/write.
Nearly all remote code execution vulnerabilities in the OS are memory corruption bugs: either use-after-free or buffer overflows. The majority involves the malloc heap and the rest mostly involves the stack which could also use MTE-based defenses to replace SSP + ShadowCallStack.
Most apps are a similar story as the base OS. Chromium has pervasive type confusion bugs which MTE doesn't explicitly protect against, but CFI and PartitionAlloc already do. Vanadium already has CFI enabled unlike Android Chrome, but there are more CFI features we need to enable.
After the initial hardened_malloc memory tagging implementation is shipped and enabled by default for the OS and many user installed apps, we can consider using more selection of tags (see https://github.com/GrapheneOS/hardened_malloc/blob/main/README.md#memory-tagging). We can also consider using MTE beyond inside hardened_malloc — Graphene OS Developers Team