TrustZone: Difference between revisions
No edit summary |
CelesteBlue (talk | contribs) (Thanks to Team Molecule) |
||
(9 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
Secure World, also known as [http://www.arm.com/products/processors/technologies/trustzone/index.php TrustZone], Trusted Execution Environment, and (by Apple) Secure Enclave, is a sandboxed execution environment that has higher privileges that the normal [[Kernel]]. On the Vita, it seems that secure world has only a few tasks, which is facilitating communication with the [[ | Secure World, also known as [http://www.arm.com/products/processors/technologies/trustzone/index.php TrustZone], Trusted Execution Environment, and (by Apple) Secure Enclave, is a sandboxed execution environment that has higher privileges that the normal [[Kernel]]. On the Vita, it seems that secure world has only a few tasks, which is facilitating communication with the [[Cmep]] processor, as well as SceGrab and SceSonyRegbus hardware devices. This provides an additional layer of buffer between the ARM application processor and the CMeP security processor. In addition, since System Software version 2.10, kernel process exceptions invoke a TrustZone call to initiate a kernel memory snapshot and encrypt it for use in a coredump. | ||
== | == Architecture == | ||
TrustZone files are stored in [[Kernel Boot Loader]]. TrustZone consists of secure kernel modules named "Tzs" which are loaded and started by [[SKBL]]. Once that Tzs modules have been started, and that SKBL has finished its work, SKBL starts NSKBL. Tzs modules are actually modules because they just wait for their exported functions to be called. The special thing is that Tzs libraries exports are only accessible to Tzs, so non-secure kernel modules cannot import them. For that reason, Tzs [[SceExcpmgr]] registers [[SMC]]s. | |||
== Security == | == Security == | ||
The main security of | |||
The main security of Secure World is the same security that prevents kernel access from usermode which is that the secure kernel code is completely proprietary and cannot be seen in Non-secure World. Without access to the code, it is hard to develop a targeted attack on Secure World. However, once a Secure World memory dump is achieved through a memory leak exploit, one can see that the ARM secure kernel lacks most of the security features found in the [[Kernel#Security|non-secure kernel]]. This is likely because the ARM secure kernel is only to provide an extra layer of protection to prevent unauthorized access to [[Cmep]] and does not function as it does on other TrustZone enabled devices (the iPhone for example uses it to store fingerprint data). Most of the above-kernel security will be found in that processor. | |||
=== TrustZone Region Protection === | |||
As TrustZone resides in the same DRAM as Non-secure World, it could be read from Non-secure World. To prevent that, TrustZone region is added to the access control list in Xbar->MainXbar->LPDDR0_config just before Secure KBL jumps to Non-secure KBL. After that, accessing TrustZone region from Non-secure World, with memalloc with pbase for example, will cause a DABT. | |||
== Secure Devices == | == Secure Devices == | ||
See [[Physical Memory]] for a list of known devices that can only be accessed in the | |||
See [[Physical Memory]] for a list of known devices that can only be accessed in the Secure World. The DRAM region <code>0x40000000</code> for 2MB (3MB prior to System Software version 3.50) can only be accessed in Secure World. This is where the secure bootloader and kernel are loaded to. [[CMeP]] can only be accessed in Secure World and only Secure World can handle [[Interrupts|interrupts]] from that processor. | |||
== SCR == | == SCR == | ||
After the boot initialization, the SCR is set to 0x00000004 which means FIQs are handled in secure | |||
After the boot initialization, the SCR is set to 0x00000004 which means FIQs are handled in Secure World. | |||
== TrustZone Debugger == | |||
On PS Vita DevKit, TrustZone debugging is enabled. There are whole documentations about it. See also rtems-debugger-arm.c for ARM v7 TrustZone debugger. | |||
=== Unlocking Memory Interface === | |||
<source lang="C"> | |||
volatile unsigned int * unlock_memory_interface(void) { | |||
volatile unsigned int *base = pa2va(0xE3314000); | |||
base[1004] = 0xC5ACCE55; | |||
return base; | |||
} | |||
</source> | |||
=== Executing ARM Instruction in TrustZone === | |||
<source lang="C"> | |||
void NonSecureToSecure(volatile unsigned int *base) { | |||
unsigned int saved_cpsr; | |||
unsigned int new_cpsr; | |||
unsigned int scr; | |||
// Step 0: Save the processor mode | |||
saved_cpsr = ReadCPSR(base); | |||
// Step 1: Change the processor mode to Monitor Mode | |||
new_cpsr = (saved_cpsr & ~0x1F) | 0x16; | |||
WriteCPSR(base, new_cpsr); | |||
// Step 2: Clear the Non-secure bit | |||
scr = ReadCPReg(base, 15, 0, 1, 1, 0); | |||
scr = (scr & ~1); | |||
WriteCPReg(base, 15, 0, 1, 1, 0, scr); | |||
// Step 3: Restore the processor mode | |||
WriteCPSR(base, saved_cpsr); | |||
} | |||
void halt_core_secure(volatile unsigned int *base) { | |||
base[34] = (base[34] & 0xffff7fff) | 0x4000; // unset HDBGen, set MDBGen | |||
//printf("halt req\n"); | |||
base[36] = 1; // halt request | |||
//printf("halt wait\n"); | |||
while (!(base[34] & 1)); // wait for halt | |||
base[34] |= 0x2000; // ITRen | |||
//printf("n2s\n"); | |||
NonSecureToSecure(base); | |||
} | |||
void ExecuteARMInstruction(volatile unsigned int *base, unsigned int instr) { | |||
unsigned int dscr; | |||
// Step 1. Poll DSCR until InstrCompl is set to 1. | |||
do { dscr = base[34]; } while (!(dscr & (1<<24))); | |||
// Step 2. Write the opcode to the ITR. | |||
base[33] = instr; | |||
// Step 3. Poll DSCR until InstrCompl is set to 1. | |||
do { dscr = base[34]; } while (!(dscr & (1<<24))); | |||
} | |||
volatile unsigned int *base = unlock_memory_interface(); | |||
ExecuteARMInstruction(base, armv7_infloop); // execute infinite loop to prove arbitrary code execution in TrustZone | |||
</source> | |||
=== Offsets === | |||
<pre> | |||
DBGOSLAR offset 0x300 | |||
1004 -> 0xFB0 | |||
DBGOSLSR offset 0x304 | |||
status USEFUL | |||
DBGOSSRR offset 0x308 | |||
Save and Restore Register | |||
Read this once to get "num" then read "num" times to save the logic state. | |||
</pre> | |||
=== ARM v7 Debug OS Save sequence === | |||
To preserve the debug logic state over a power-down, this state must be saved to non-volatile storage. This means that the OS Save sequence must: | |||
1. Set the OS Lock by writing the key value, 0xC5ACCE55, to the DBGOSLAR. This also initializes the DBGOSSRR. | |||
2. If using the CP14 interface, execute an ISB instruction. | |||
3. Perform an initial read of DBGOSSRR. This returns the number of reads of the DBGOSSRR that are required to save the entire debug logic state. This number is IMPLEMENTATION DEFINED but must be less than or equal to 128. | |||
[[Category:Kernel]] | [[Category:Kernel]] |
Latest revision as of 00:18, 19 January 2024
Secure World, also known as TrustZone, Trusted Execution Environment, and (by Apple) Secure Enclave, is a sandboxed execution environment that has higher privileges that the normal Kernel. On the Vita, it seems that secure world has only a few tasks, which is facilitating communication with the Cmep processor, as well as SceGrab and SceSonyRegbus hardware devices. This provides an additional layer of buffer between the ARM application processor and the CMeP security processor. In addition, since System Software version 2.10, kernel process exceptions invoke a TrustZone call to initiate a kernel memory snapshot and encrypt it for use in a coredump.
Architecture
TrustZone files are stored in Kernel Boot Loader. TrustZone consists of secure kernel modules named "Tzs" which are loaded and started by SKBL. Once that Tzs modules have been started, and that SKBL has finished its work, SKBL starts NSKBL. Tzs modules are actually modules because they just wait for their exported functions to be called. The special thing is that Tzs libraries exports are only accessible to Tzs, so non-secure kernel modules cannot import them. For that reason, Tzs SceExcpmgr registers SMCs.
Security
The main security of Secure World is the same security that prevents kernel access from usermode which is that the secure kernel code is completely proprietary and cannot be seen in Non-secure World. Without access to the code, it is hard to develop a targeted attack on Secure World. However, once a Secure World memory dump is achieved through a memory leak exploit, one can see that the ARM secure kernel lacks most of the security features found in the non-secure kernel. This is likely because the ARM secure kernel is only to provide an extra layer of protection to prevent unauthorized access to Cmep and does not function as it does on other TrustZone enabled devices (the iPhone for example uses it to store fingerprint data). Most of the above-kernel security will be found in that processor.
TrustZone Region Protection
As TrustZone resides in the same DRAM as Non-secure World, it could be read from Non-secure World. To prevent that, TrustZone region is added to the access control list in Xbar->MainXbar->LPDDR0_config just before Secure KBL jumps to Non-secure KBL. After that, accessing TrustZone region from Non-secure World, with memalloc with pbase for example, will cause a DABT.
Secure Devices
See Physical Memory for a list of known devices that can only be accessed in the Secure World. The DRAM region 0x40000000
for 2MB (3MB prior to System Software version 3.50) can only be accessed in Secure World. This is where the secure bootloader and kernel are loaded to. CMeP can only be accessed in Secure World and only Secure World can handle interrupts from that processor.
SCR
After the boot initialization, the SCR is set to 0x00000004 which means FIQs are handled in Secure World.
TrustZone Debugger
On PS Vita DevKit, TrustZone debugging is enabled. There are whole documentations about it. See also rtems-debugger-arm.c for ARM v7 TrustZone debugger.
Unlocking Memory Interface
volatile unsigned int * unlock_memory_interface(void) { volatile unsigned int *base = pa2va(0xE3314000); base[1004] = 0xC5ACCE55; return base; }
Executing ARM Instruction in TrustZone
void NonSecureToSecure(volatile unsigned int *base) { unsigned int saved_cpsr; unsigned int new_cpsr; unsigned int scr; // Step 0: Save the processor mode saved_cpsr = ReadCPSR(base); // Step 1: Change the processor mode to Monitor Mode new_cpsr = (saved_cpsr & ~0x1F) | 0x16; WriteCPSR(base, new_cpsr); // Step 2: Clear the Non-secure bit scr = ReadCPReg(base, 15, 0, 1, 1, 0); scr = (scr & ~1); WriteCPReg(base, 15, 0, 1, 1, 0, scr); // Step 3: Restore the processor mode WriteCPSR(base, saved_cpsr); } void halt_core_secure(volatile unsigned int *base) { base[34] = (base[34] & 0xffff7fff) | 0x4000; // unset HDBGen, set MDBGen //printf("halt req\n"); base[36] = 1; // halt request //printf("halt wait\n"); while (!(base[34] & 1)); // wait for halt base[34] |= 0x2000; // ITRen //printf("n2s\n"); NonSecureToSecure(base); } void ExecuteARMInstruction(volatile unsigned int *base, unsigned int instr) { unsigned int dscr; // Step 1. Poll DSCR until InstrCompl is set to 1. do { dscr = base[34]; } while (!(dscr & (1<<24))); // Step 2. Write the opcode to the ITR. base[33] = instr; // Step 3. Poll DSCR until InstrCompl is set to 1. do { dscr = base[34]; } while (!(dscr & (1<<24))); } volatile unsigned int *base = unlock_memory_interface(); ExecuteARMInstruction(base, armv7_infloop); // execute infinite loop to prove arbitrary code execution in TrustZone
Offsets
DBGOSLAR offset 0x300 1004 -> 0xFB0 DBGOSLSR offset 0x304 status USEFUL DBGOSSRR offset 0x308 Save and Restore Register Read this once to get "num" then read "num" times to save the logic state.
ARM v7 Debug OS Save sequence
To preserve the debug logic state over a power-down, this state must be saved to non-volatile storage. This means that the OS Save sequence must:
1. Set the OS Lock by writing the key value, 0xC5ACCE55, to the DBGOSLAR. This also initializes the DBGOSSRR. 2. If using the CP14 interface, execute an ISB instruction. 3. Perform an initial read of DBGOSSRR. This returns the number of reads of the DBGOSSRR that are required to save the entire debug logic state. This number is IMPLEMENTATION DEFINED but must be less than or equal to 128.