How to Introspect Normal World from Secure World Using Trustzone

How to Introspect normal world from secure world using TrustZone?

Trust-zone is not by itself a security system. You have to engineer that. Also, there are many different types of security. For instance, you are assuming a software attack yet there are many physical attacks against a system (like I guess you describe). Something must be a trusted computing base (TCB); Ie, some code that you assume can not be compromised. A normal world kernel is probably too large to be part of the TCB, yet it can be a good first line of defence. An exploit against it is only a priveledge elevation from user to supervisor. Your TrustZone API should expect untrusted data (Ie, the normal world kernel trying buffer overflows and API mis-use, etc).

The key point here is that TZASC and other bus peripherals can grant access for the secure world to read/write normal world memory. You would have to verify MMU tables, and other data structures for the case of a full blown OS like Linux. Module loading, processes running, etc. all need verification. However, if you have a much simpler system in the normal world it may be possible to verify it. Most likely you have to settle for a portion of it. Random sampling of the PC might be a deterrent; but nothing will be fool-proof unless the normal world is proof carrying code.

  1. Suppose I want to see what processes are running in the normal world, do I have to use a kernel module in the normal world to help me do this? If so, how do I make sure that it has passed the right result to the secure world? To be precise, how do I check that whether the kernel has been comprimised?

Your secure world can contain an OS (or primitive scheduler) which will periodically check the normal world code integrity. There are hardware modules like an RTIC, etc. You can also use the TZASC to lock the kernel code to normal user (no access) and normal supervisor as read-only. comprimised is an overloaded word. At some point you must trust something. Can the private key be replicated if the normal super is compromised? You have to define your security goals. In the any sense/meaning, of course the normal world kernel can be compromised. You don't have a complete specification of its behaviour to verify from the secure world.


  1. Suppose I have a RSA key pair and I keep the private key in the secure world. When a process request to decrypt some data, how does secure world get to know whether the request is from a legislative process? A whitelist mechanism might help, but what if the kernel in normal world has been compromised and the adversary pretend to be legislative? The secure world seems to know nothing about what is happening in the normal world.

Your secure world probably has to have some co-operation from the encrypting entity. You could limit the amount of decrypts without some from of verification for instance. It seems that the most valuable thing is the private RSA key. If you allow the normal world to request decryption, then that is your issue and not Trustzone's? You have to handle this using normal mechanisms with cryptography and unknown/untrusted hosts. Is the RSA key pair global or per device? Do you support revocation, etc. It is in your system and TrustZone is only part of it.

Use ARM TrustZone to prevent access to memory region from Non-Secure world

The untrusted code is running in non-secure state, therefore any bus transactions generated by the CPU will be marked as non-secure, thus it's the inherent functionality of the interconnect that keeps things separate. The secure memory map and the non-secure memory map are actually entirely separate things, it's just that in most systems they are wired up to be more or less identical.

Now, that "secure world memory" is either going to be some dedicated block (usually on-chip SRAM) that is hard-wired to the secure memory map, or a chunk of general DRAM carved out and made secure-only via a TZPC/TZASC. Either way, it simply doesn't exist in the non-secure memory map, therefore there's nothing non-secure software can do to access it.

Easiest way to access secure (TrustZone) instructions from privileged context on Cortex A8/DM3730

The DM3730 on the Gumstix is a GP (general purpose) device, which means it has TrustZone disabled. There's no way you can get in to it.

See https://stackoverflow.com/a/8028948/6839

What is cost of context switching to secure mode (arm trustzone)

What exactly needs to happen when moving from non-secure to secure world?

TL-DR; the minimum is to save/restore all CPU registers that are needed by the secure world and change the NS bits. Normally, R0-R14 as well as current mode, and banked LR and SP (aborts, interrupts, etc) are in this register group. Everything else depends on your security model.


First off, there are many different models that can be used in TrustZone; TrustZone is a tool not a solution. The most basic model is a library with API where some secure data is stored (ie decryption keys) to process by an external source (some DRM download from the 'normal world' space). I assume you don't mean this.

An OS can be pre-emptible and non-premptible. If you have two OSes in both worlds, then how control is relinquished, resources shared and security assets protected will all come into play on a world switch.

In many cases, the caches and TLB are world aware. Devices may also be world aware and designed with the intent that context is built into the device. This is not to say that some system might have information leaked in some way.

  • Meltdown (2017)
  • Specter (2017)
  • Hyperthreading exploit (2004)

If you are really concerned about this type of attack, it may be appropriate to mark the secure world memory as non-cached that needs to be protected. In many ARM systems, the L1/L2 and TLB cache are unified between worlds and can provide a side channel attack.

TrustZone as implmented on many ARM devices comes with a GIC which can run FIQ in the secure world and masking of FIQ can be prevented in the normal world. Many GIC features are banked between worlds allowing both OSes to use it without 'context switch' information. Ie, the NS bit will automatically change the accessed GIC features based on the state of the NS bit (so it has the context stored in the device). Many other vendor specific devices are designed to behave this way.

If both worlds use NEON/VFP, then you need to save/restore these registers on a world switch as well. For pre-emption you may need to hook into the OS secure scheduler to allow and normal world interrupt to pre-empt the secure world main line (obviously this depends on assets you are trying to protect; if you allow this the secure mainline has a DOS vector).

If there are glitches in devices, then you may need to save/restore device state. If the normal world is restricted from using FIQ mode, it is still needed to at least clear the SP_fiq and LR_fiq when going to the normal world (and restore the secure value the other way). Some of these registers are difficult to save/restore as you must switch modes which can itself be a security risk if care is not taken.

RAM: This must be 'partitioned' and used by both modes. So addressing is just an offset into the 'partition'. Is this right?

Secure boot will partition memory based on the 'NS bit'. The physical memory will be visible or not based on the partition manager device logic which can often be locked at boot. Ie, if non-visible it is a bus error like any non-existent memory. There is no 'switch' beside the NS bit.

Is there anything in moving from non-secure to secure modes that would make it more expensive than the regular process context switch?

Yes a normal switch is only for a 'mode'. A world is for all ARM modes and so all banked registers must be switched. Depending on the system the TLB and cache would not normally need to be switched.


Related:

  • How to introspect normal world
  • TrustZone monitor mode switch design
  • Preventing memory access from the normal world
  • How is a TrustZone OS secure?
  • TrustZone scheduler in secure/non-secure OS
  • IMX53 and TrustZone
  • ARM Trusted firmware on github
  • TrustZone Whitepaper

TrustZone Memory Partitioning

TrustZone partitioning happens at the physical memory level, so the process-level parts of your question don't really apply. Note that Linux as the non-secure OS can't even see secure memory, so having virtual mappings for inaccessible addresses would be of little use; however the secure OS does have the ability to map both secure and non-secure physical addresses by virtue of the NS bit in its page table entries.

As for how that physical partitioning goes, it depends on the implementation. The TZC-380 your link refers to supports 2-16 regions with a minimum 32KB granularity; its successor the TZC-400 has 9 regions, and goes all the way down to 4KB granularity. Other implementations may be different still, although granularity below 4KB is unlikely since that would be pretty much unusable for the CPU with its MMU on. Also, there are usually some things in a system which are going to be hardwired to the secure memory map only (the TZC's programming interface, for one), and that often includes some dedicated secure SRAM.

i.MX53 QSB and ARM TrustZone

.. when should I share the memory and the interrupts between the secure and normal world ?

Memory sharing depends on your system requirements/design. It is possible to use the smc to only use registers to share information. No one can give a generic answer on memory sharing.

It rarely makes sense to share interrupts. You would need a driver in both worlds. The whole point of trustzone is to partition hardware.

Some hardware is trustzone aware. Ie, it can change it's register set/view based on what world is executing. Generally, this hardware only has an interrupt for one world or a separate interrupt number. If you do not have a device that is trustzone aware, this is probably a foolish thing to try.

..how can I move to the normal world in order to run a Rich OS on it?

Well, this is fairly simple when you have a monitor mode. So, from the secure boot (maybe a secure OS task/thread),

  1. Load the normal world OS to memory.
  2. Setup monitor mode stack and other contexts; monitor mode will need a memory buffer to store world contexts.
  3. Switch to monitor mode.
  4. Setup memory partitioning (intially allow everything for the normal world).
  5. Change the NS bit to set normal world CP15.
  6. Configure CP15 registers as per boot default. Many OSs will expect that they are booting as per normal. Most trustzone CPUs do not setup the normal world CP15 registers by default.
  7. Mask interrupts, turn off cache, etc as required to boot normal OS.
  8. With NS bit still set, do a world switch.

The world switch is dependent on your system design. If the secure world OS only used registers R0-R12 the instructions might be like,

    # NS bit is set.
msr spsr_fsxc, lr # mon_lr contains normal world mode, etc.
ldm sp, {r0 - r12, pc}^ # monitor 'sp' is a context pointer.

The ldm rX, {xxx, pc}^ will do a mode switch. The monitor 'sp' could have 13 zeros (for r0-r12) and then a normal world entry point for the 'PC'. The monitor 'lr' would have the starting mode (interrupt masked, etc) for the normal world.

NOTE: This is a simple example and it not meant for your particular OS. It is only conceptual. Specifics depend on specific normal/secure world OS requirements. Typically, you need to do all the things a boot loader would do for that platform/OS without TrustZone. As well, you need to initialize all registers in all modes. You may not care about registers the secure world doesn't use (NEON/VFP) and leave them as per boot defaults; this is more true for actual 'world switch' code.

...concerning the monitor mode code, where should I write it? Is it a kernel module in the secure world?

Monitor mode will always USE the CP15 registers of the secure world. This implies monitor mode has the MMU view, cache, etc of the secure OS. When the 'NS' bit is set and monitor mode does a mcr or mrc, it is setting the normal world registers. Well, technically it could be 'separate' there will probably be a lot of interaction between the secure OS and the monitor. Again, it depends on specifics. There are many types of OSs (or world contexts),

  1. Polling mode
  2. Non-preemptive
  3. Pre-emptive

You have permutations of the above for both the secure and normal world and the world switch handling will depend on the requirement of both. For the most complex case (Pre-emptive secure/normal), you need integration of schedulers which is OS dependent.

How does Linaro schedule OPTEE?

I'm one of the Linaro developers working directly with OP-TEE and OP-TEE as such has no scheduler, instead it's being entirely scheduled by Linux kernel. It's not tied to a single core either, after being in Linux kernel and you're about to re-enter secure world it could be any of the cores where you continue running your ongoing job. So in short, there is no scheduler in OP-TEE.



Related Topics



Leave a reply



Submit