Beyond Heap Safety: Where MTE Earns Its Cost
ARM MTE is not only a way to detect use-after-free and buffer-overflow bugs. It can also revoke access to a buffer, turn invalid accesses into data-tracing events, and add tags to isolation or control-flow schemes. The question here is which of those jobs match MTE’s primitive well enough to justify its cost. Comparing each design with the mechanism it replaces—rather than with an unprotected run—shows where MTE is a practical advantage and where it is merely a different source of overhead.
When retagging changes a security boundary
The clearest positive case begins with a time-of-check to time-of-use problem in Firefox. Firefox’s XML parser runs inside an in-process software-fault-isolation sandbox. The parser’s output is stored in sandbox memory, checked by trusted code, and then used. Because the parser can be called again while the surrounding operation is still in progress, a compromised parser could modify already checked data before the trusted code consumes it. Copying the parser’s output into a separate trusted buffer prevents that change, but Mozilla engineers measured about a 10% slowdown for the relevant operation—too costly for the intended deployment.
BufLock uses MTE as a lightweight revocation mechanism. Instead of copying the data, the trusted side retags the produced structures. The sandbox continues to use untagged pointers, so those pointers no longer match the newly tagged data and cannot access it under the MTE policy. The checked data has not moved; the authorization represented by the old pointer has become stale. That is a different use of MTE from detecting a random heap error: the tag update is an intentional state transition at an isolation boundary.
The design succeeds only because the surrounding SFI system supplies important conditions. The sandbox compiler used by Firefox ensures that dereferenced pointers have a known prefix, which leaves their MTE tag bits clear. It also excludes instructions that could change tags and system calls that could disable MTE. Without those restrictions, the parser might create a matching tagged pointer or remove the check, defeating the intended boundary. BufLock is therefore not “retag any buffer and trust the result.” It is a compound design in which SFI controls what the untrusted component can carry and execute while MTE revokes the old access state.
The measurements show why the hardware context still matters. In the table, the copy builds range from 1.071× to 1.132× relative runtime. BufLock is close to the insecure baseline on most listed cores: about 1.01× to 1.085×, including 1.051× on AmpereOne. On Pixel Performance cores, however, BufLock reaches roughly 1.381× to 1.415× because the frequent retagging interacts with the store limitation described earlier. The same protection idea that is attractive on AmpereOne and Pixel Big or Little can be much less attractive on that Performance core.
Concurrency narrows the result further. In a single-threaded, re-entrant parser boundary, retagging can establish the intended ordering. In a multithreaded program, another thread could observe or use the data while the tag update is in flight unless the design adds synchronization.