TrustZone Intermezzo: Broken OP-Tee Memory Isolation on I.mx 8M

Deeg9rie9usi1 pts0 comments

TrustZone Intermezzo: Broken OP-TEE Memory Isolation on i.MX 8M

Trainings<br>Customized Trainings<br>About<br>Blog<br>DE

security

11.06.2026

TrustZone Intermezzo: Broken OP-TEE Memory Isolation on i.MX 8M<br>TL;DR: If you don&rsquo;t run upstream OP-TEE newer than v4.10.0 with CFG_TZASC_REGION0_SECURE=y or i.MX downstream OP-TEE newer than lf-6.12.49_2.2.0, OP-TEE&rsquo;s memory is not properly protected and can<br>be compromised from the normal world.<br>Recently, a commit from 2024 in the OP-TEE OS git repository caught our attention.<br>It makes sure the TrustZone Address Space Controller (TZASC) is enabled on all i.MX 8M SoCs.<br>Our first reaction was mixed. Can it really be that prior to this commit OP-TEE forgot to protect<br>its own memory region? Or does the commit just add another safeguard against certain misconfigurations?<br>And if so, why was no CVE filed?<br>Remember how the two worlds are split. OP-TEE runs in the so-called secure world of the SoC, while an<br>operating system such as Linux runs in the normal world (AKA non-secure world).<br>Arm TrustZone enforces this split using the TZASC.<br>So it is crucial that the normal world cannot directly access secure world memory.<br>OP-TEE often implements a software TPM or holds other secret keys.<br>Linux must not touch it, neither the kernel nor root in userspace.<br>That commit nagged at us, so we decided to dig in and give it a try.<br>Many of our customers run i.MX 8M based systems and strongly emphasize security.<br>We had a lot of fun along the way, so this blog post documents our journey.<br>Confirming the Bug<br>We booted one of our i.MX 8M boards, to be precise the NXP i.MX 8M Mini EVK, with OP-TEE version 4.1.0,<br>which does not contain that commit.<br>On this system, OP-TEE places its main memory at address 0xbe000000, so we tried to dump that region from Linux.<br>The attempt should fail, because Linux runs in the normal world and OP-TEE in the secure world.<br>On Linux, root can reach all system memory through /dev/mem, so we attempted to read from 0xbe000000 that way.<br>Tools such as devmem2 exist, but we wrote a few lines of Python to stay flexible.<br>Access failed right away. Good. Right?<br>Not so fast. The kernel on this system was built with CONFIG_STRICT_DEVMEM.<br>That option limits /dev/mem to device memory only, so it blocked our read before TrustZone ever came<br>into play.<br>Time to rebuild the kernel with CONFIG_STRICT_DEVMEM disabled.<br>On the freshly built kernel, the read still failed. Good, but were we sure?<br>Thinking harder, we turned to the kernel log and found this line:<br>OF: reserved mem: 0x00000000be000000..0x00000000bfbfffff (28672 KiB) nomap non-reusable optee_core@be000000<br>OP-TEE adds reserved-memory nodes to the device tree passed to Linux, so Linux ignores this memory<br>region completely.<br>The nomap property in particular makes sure the region is never mapped.<br>So our test could not work: Linux itself keeps the OP-TEE region out of reach.<br>But that is not what we wanted to test. We wanted to know whether the access is possible at all.<br>Linux runs in the normal world, and it must not reach that memory even when it really wants to.<br>After changing a few lines of code, we had a kernel that ignored the nomap hint from OP-TEE.<br>In a real-world scenario, an attacker who has taken over the kernel can bypass this restriction too,<br>most simply by loading a custom kernel module.<br>Time to check again.<br># dump memory<br>$ python3 devmem.py 0xbe000000 0x100000 > optee_core.bin

# check for a well known string<br>$ strings optee_core.bin | grep "OP-TEE version"<br>OP-TEE version: %s

Indeed, we could read OP-TEE&rsquo;s memory from Linux!<br>The bug is real and serious. It renders the whole security purpose of OP-TEE void.<br>A compromised Linux system can reach the secure world and extract or even alter key material.<br>It&rsquo;s Not Over Yet: The Mysterious region0 and Memory Aliases<br>This story could have ended here. OP-TEE forgot to enforce the memory restriction on a certain platform, a single commit fixed<br>it, and we&rsquo;re good. Not nice, but bugs happen. That&rsquo;s life.<br>While further investigating, we found other commits related to the TZASC:<br>arm-trusted-firmware: fix(imx8m): don&rsquo;t reconfigure default region0<br>optee: drivers: imx: tzc380: add support to verify region0<br>These commit messages hinted at a deeper problem.<br>Protecting the secure world from the normal world takes more than enabling the TZASC correctly.<br>The root cause is that the TZASC is not memory alias aware.<br>With the right fix, OP-TEE makes sure its memory region cannot be reached from the<br>normal world.<br>But that protection rests on the address alone, in our case 0xbe000000.<br>Because the controller is not memory alias aware, another address can point to the very same memory location and slip past the access check.<br>This is where region0 becomes relevant. The TZASC allows configuring access permissions for<br>certain memory address ranges. If a requested address has no configured range in the TZASC, it falls back to region0.<br>region0 is a memory range configuration...

memory world linux from kernel rsquo

Related Articles