Skip to content

Examples

Andrea Barisani edited this page Oct 31, 2024 · 19 revisions

Opportunistic soft lockstep

GoTEE supports lockstep execution of any deterministic execution context, such a Trusted Applet.

The tandem progression of a Trusted Applet executable allows detection of injected or naturally occurred faults.

To achieve this a shadow execution context created with Clone can be paired to the primary one for comparison at each monitor call.

A function to re-configure virtual memory addressing, so that the same applet can be allocated in two separate physical memory areas, is also typically required.

The following example uses TamaGo arm package ConfigureMMU to support such switching:

// load primary context
ta, err := monitor.Load(taEntry, taMemory, true)

// initialize context
...

// load shadow context to enable lockstep
ta.Shadow = ta.Clone()

// define MMU re-configuration functions
flags := arm.MemoryRegion|arm.TTE_AP_011<<10

ta.MMU = func() {
	imx6ul.ConfigureMMU(taVirtualStart, taVirtualEnd, taPrimaryStart, flags)
}

ta.Shadow.MMU = func() {
	imx6ul.ConfigureMMU(taVirtualStart, taVirtualEnd, taShadowPrimaryStart, flags)
}

The lockstep command in GoTEE example, when launched under qemu or on real hardware such as the USB armory Mk II, allows to test lockstep execution with random fault injection.

> lockstep 0.01
SM loading applet in lockstep shadow memory
SM loaded applet addr:0x10000000 entry:0x10082658 size:5002440
SM starting mode:USR sp:0x12000000 pc:0x10082658 ns:false
tamago/arm • TEE user applet
applet obtained 16 random bytes from monitor: 2c4337ed2da3d3570d7120d7d52dbda5
applet requests echo via RPC: hello
applet received echo via RPC: hello
applet will sleep for 5 seconds
applet says 1 mississippi
applet says 2 mississippi
!! injecting register fault !!
SM stopped mode:USR sp:0x11fffdd0 lr:0x101accb4 pc:0x101acbc0 ns:false err:lockstep failure
   r0:00000002  r1:11ff02a0  r2:00000000  r3:00000002
   r4:00000000  r5:00000000  r6:00000000  r7:00000001
   r8:00000001  r9:10365178 r10:10363e00 r11:00000007 cpsr:200001d3 (SVC)
  r12:584875b0  sp:11fffdd0  lr:101accb4  pc:101acbc0 spsr:200001d0 (USR)
shadow context:
   r0:00000003  r1:11ff02a0  r2:00000000  r3:00000002
   r4:00000000  r5:00000000  r6:00000000  r7:00000001
   r8:00000001  r9:10365178 r10:10363e00 r11:00000007 cpsr:200001d3 (SVC)
  r12:584875b0  sp:11fffdd0  lr:101accb4  pc:101acbc0 spsr:200001d0 (USR)
stack trace:
  github.com/usbarmory/GoTEE/syscall/syscall_arm.s:37
  github.com/usbarmory/GoTEE/applet/nanotime_syscall.go:21

>

TamaGo unikernel as Main OS

The GoTEE example, when launched under qemu or on real hardware such as the USB armory Mk II, allows to test the restrictions shown in this tutorial and demonstrates NonSecure operation, also using a TamaGo unikernel as Main OS, before and after TrustZone restrictions are in effect.

The sequence of events triggered by the gotee command through the example SSH console is as follows:

  1. The Trusted OS (S) loads and launches the Trusted Applet (S) and Main OS (NS). The bare minimum set of permissions is configured to allow NonSecure World operation (e.g. insecure configuration).

  2. The Main OS (NS) attempts to use the DCP to derive a key, with success.

  3. The Main OS (NS) yields back to the Trusted OS (S) with a monitor call.

  4. The Trusted Applet (S) issues GoTEE system calls to obtain random numbers and perform an RPC call.

  5. The Trusted Applet (S) attempts to read privileged Trusted OS (S) memory, it fails and triggers a data abort exception

  6. The Trusted OS (S) re-launches the Main OS (NS) with TrustZone restrictions in place, including ones for the DCP.

  7. The Main OS (NS) attempts to use the DCP to derive a key, it fails and triggers a monitor exception.

  8. The Trusted OS (S) attempts to use the DCP to derive a key, with success.

> gotee

SM loaded applet addr:0x9c000000 entry:0x9c072820 size:4942277
SM loaded kernel addr:0x80000000 entry:0x800710ec size:4616813
SM waiting for applet and kernel
SM starting mode:SYS sp:0x00000000 pc:0x800710ec ns:true
SM starting mode:USR sp:0x9e000000 pc:0x9c072820 ns:false
tamago/arm • system/supervisor (Non-secure)
supervisor is about to perform DCP key derivation
supervisor successfully used DCP (aaf81241bc59b59a2652cc1f7a55a181)
supervisor is about to yield back
SM stopped mode:SYS sp:0x8146bf54 lr:0x801959c8 pc:0x80195aa8 ns:true err:exit
tamago/arm (go1.19.4) • TEE user applet
applet obtained 16 random bytes from monitor: cbf4d3c519492024336e85dda0e96bd5
applet requests echo via RPC: hello
applet received echo via RPC: hello
...
applet is about to read secure memory at 0x98010000
   r0:98010000  r1:9c8240c0  r2:98010000  r3:00000000
   r4:00000000  r5:00000000  r6:00000000  r7:9c86bec8
   r8:00000007  r9:0000003d r10:9c8020f0 r11:9c342f71 cpsr:600001d7 (ABT)
  r12:00000061  sp:9c86bf08  lr:9c1b1e24  pc:9c011330 spsr:600001d0 (USR)
SM stopped mode:USR sp:0x9c86bf08 lr:0x9c1b1e24 pc:0x9c011330 ns:false err:ABT
SM re-launching kernel with TrustZone restrictions
SM loaded kernel addr:0x80000000 entry:0x800710ec size:4616813
SM starting mode:SYS sp:0x00000000 pc:0x800710ec ns:true
tamago/arm (go1.19.4) • system/supervisor (Non-secure)
supervisor is about to perform DCP key derivation
SM trapped Non-secure data abort pc:0x80011328
supervisor failed to use DCP (co-processor is not initialized)
supervisor is about to yield back
SM stopped mode:SYS sp:0x8146bf54 lr:0x801959c8 pc:0x80195aa8 ns:true err:exit
SM in Secure World is about to perform DCP key derivation
SM in Secure World successfully used DCP (aaf81241bc59b59a2652cc1f7a55a181)

Linux as Main OS

The GoTEE example also allows execution of the USB armory Debian base image Linux kernel as Main OS in NonSecure World, also only when launched on the USB armory Mk II and through the linux command.

Note

Only USB armory Debian base image releases >= 20211129 are supported for NonSecure World operation.

Example for Debian image on external microSD card:

> linux uSD
armory-boot: loading configuration at /boot/armory-boot-nonsecure.conf

Example for Debian image on internal eMMC flash:

> linux eMMC
armory-boot: loading configuration at /boot/armory-boot-nonsecure.conf

This spawns Linux in NonSecure World, yielding USB access back to it. For this reason the GoTEE output remains visible only on the USB armory serial console, accessible through the debug accessory, which remains shared with Linux.

It is possible to yield back to the GoTEE monitor, which keeps running in Secure World, by re-loading the optee kernel module:

root@usbarmory:~# modprobe -r optee
root@usbarmory:~# modprobe optee
optee: probing for conduit method.
  NonSeureHandler: unimplemented
optee: api uid mismatch
optee: probe of firmware:optee failed with error -22

To probe the OP-TEE API version the module issues an SMC call, the GoTEE monitor activity can be seen in its log issued from Secure World.

Using devmem2 TrustZone restrictions for Secure World memory can be verified:

# devmem2 0x98000000
/dev/mem opened
   r0:00000000  r1:00000000  r2:b6f08000  r3:b6f08000
   r4:00431000  r5:00000000  r6:00000000  r7:beac1cc0
   r8:00000000  r9:00000000 r10:00431000 r11:00000000 cpsr:600701d6 (MON)
  r12:00431014  sp:beac1cb8  lr:b6e2e47f  pc:004208e4 spsr:60070030 (USR)
SM stopped mode:SVC ns:true sp:0xbeac1cb8 lr:0xb6e2e47f pc:0x004208e4 err:DATA_ABORT