1. Introduction
Every modern SoC that plays DRM-protected video has to solve a problem that has nothing to do with video codecs: how do you let a hardware decoder write a decrypted 1080p frame into DRAM, hand that frame to a display controller, and guarantee that at no point does the CPU — or a compromised kernel, or a debugger, or a rogue driver — get to read the plaintext pixels?
The answer, on essentially every ARM-based SoC shipping today, is a hardware memory-protection firewall: a piece of silicon sitting between the SoC’s bus fabric and DRAM that enforces access-control rules per physical address range, independent of and prior to anything the CPU’s MMU does. Linux’s job is to orchestrate that firewall correctly from a kernel that is, by design, not trusted with the secrets the firewall is protecting.
This article is about the kernel-side plumbing that makes that possible: protected DMA-bufs — dma-buf objects whose backing memory is gated by a hardware firewall rather than ordinary page-table permissions — and the concurrency and correctness hazards that show up when you try to manage that firewall’s state from a multi-threaded, multi-device kernel subsystem.
We’re going to build a working (and then broken, and then fixed) simulation of the attach/detach/firewall-lock state machine that sits underneath this subsystem, run it through ThreadSanitizer, AddressSanitizer, and Valgrind, and look at two real, reproduced bugs: a heap-use-after-free born from a TOCTOU race on the firewall’s unlock path, and a security-relevant alignment bug that no sanitizer can see because it isn’t a memory-safety bug at all — it’s a policy bug that leaves real bytes unprotected.


