首页
社区
课程
招聘
[转帖]Trustonic’s Kinibi TEE Implementation
发表于: 2020-3-9 12:41 3795

[转帖]Trustonic’s Kinibi TEE Implementation

2020-3-9 12:41
3795

Original link: https://azeria-labs.com/trustonics-kinibi-tee-implementation/

 

In the first part of this series I explained the TrustZone technology and the basic of Trusted Execution environments. I also mentioned that there are various TEE implementations out there. Trustonic’s Kinibi TEE and Qualcomm’s QTEE are the two major TEE implementations used in the Android ecosystem that make use of the Arm TrustZone technology. Trustonic’s Kinibi TEE implementation was primarily designed for devices with the Exynos chipset, mainly used in European and Asian markets. Qualcomm-based Samsung devices run QTEE but also support the execution of Kinibi.

 

In this part, I will use the Kinibi TEE implementation as an example to explain how TEE’s work under the hood and how Trusted Applications (TAs) in the Secure World (SWd) communicate with apps in the Normal World (NWd).

 

Here’s a rough overview of the main Kinibi components: img

 

RTM: The Run-Time Manager (RTM) handles memory management, task loading, and exception handling [ref]. It is also able to pass messages between the two worlds.

 

MTK: The Kinibi Microkernel runs in S-EL1, and provides isolation between tasks, inter-process communication, and performs preemptive scheduling of TAs.

 

Kinibi Client API: “Client Applications” (CA) make use of the Kinibi Mobicore Client API to load and interact with TAs. CA access this API via the libMcClient.so library, which provides APIs to request handles to sessions and relay notifications between the NWd and SWd via a shared memory buffer visible from both worlds [ref]. The MobiCore Client API works by relaying requests from CAs to the MobiCore daemon running with high permissions in the NWd. This Daemon relays the request up to the MobiCore driver in NWd EL1. This driver then communicates with the TEE RTM via the MobiCore Interface (MCI).

 

McLib: The Mobicore Library (McLib) is used by TAs and drivers in the TEE and consists of the a proprietary Internal API and a Global Platform (GP) Internal API. Trusted Applications can use the TLAPI to call McLib functions, while Trusted Drivers have access to a richer set of stubs provided by the DRAPI.

 

Cryptographic operations and algorithms: Kinibi provides a number of cryptographic services to REE, including a secure random number generator, data encryption services, secure key creation and destruction, as well as the provision of basic cryptographic algorithms such as cryptographic hashes, generation and verification of MACs and digital signatures [ref].

 

Secure Objects: Kinibi provides REE applications with the ability to access “Secure Objects”, which contain data in encrypted and integrity-protected form. Once encrypted, the data can be stored in insecure locations, such as on disk in the normal world. The key to decrypt the secure object is derived from the device master key and is uniquely derived for every TA. Additionally, the keys for secure objects never leave the TEE. This means that a secure object can only ever be decrypted on the device that generated it, inside the TA that created it, and when the user has logged in. The services to create and manage secure objects are provided by the Kinibi Trusted Storage API [ref].

 

Trusted Applications and Trusted Drivers

 

img

 

Trusted Applications: Kinibi Trusted Applications and Trusted Drivers are stored on disk using the Mobicore Loadable Format (MCLF) file format. The MCLF files for TAs are typically stored in the “/system/vendor/app/McRegistry”, “/system/app/mcRegistry”, and “/data/app/mcRegistry” folders on Samsung devices.

 

img

 

TA APIs: Trusted Applications (TAs) run in S-EL0. TAs interact with the TEE through the MobiCore Library (McLib). This provides access to both the Kinibi proprietary internal API and a subset of the GlobalPlatform TEE API. Trusted Applications invoke McLib functions via the tlApi interface.

 

Embedded and System TAs: Trusted Applications are subdivided into Embedded TAs and Normal TAs. Trustonic also provides a series of system TAs, such as the Content Management Trusted Application which manages containers, the Android Gatekeeper TA, and the Keymaster system TAs, which are provided by the OEM [ref].

 

Trusted Drivers: On Kinibi, Trusted Drivers execute in the same privilege level as Trusted Applications, S-EL0. However, Trusted Drivers have access to a richer set of functionalities inside McLib, which they can call via drApi stubs. These additional functionalities allow TDs to access additional Supervisor Calls (SVCs), map physical memory, use threads, and make SMC calls. Trusted Drivers allow Trusted Applications to access peripherals on the device, which requires TDs to be able to map physical memory.

 

Embedded TDs: Kinibi is bundled with a crypto driver (drcrypto) and the secure storage service driver (STH2), both running as a separate task with driver privileges. Drcrypto provides cryptographic services, and STH2 provides secure storage services to TAs and TDs. Unlike other TAs, these drivers are directly embedded in Kinibi, rather than being loaded from disk or loaded from the REE. It is possible to extract these drivers from the bootloader sboot.bin using the t-base loader for IDA Pro and Ghidra developed by researchers at Quarkslab.

 

Communicating with Trusted Applications

 

You might be wondering how normal app can communicate with a TA in the Secure World. After all, everything is isolated, right? By design, apps in the NWd need to communicate with TAs in the SWd. For example, Samsung pay is an app in the NWd but also has a TA in the SWd that it uses for sensitive information. The same applies for apps like YouTube, which use Google’s DRM TA for copyright protection.

 

When a normal app, or Client Application (CA), from the Rich Execution Environment (REE) in the NWd wants to communicate with a TA in the SWd, it does so using the Trustlet Application Connector over the Trusted Communication Interface (TCI). Let’s break this process down step by step.

 

Open Device First, the CA creates a “device session” via the mcOpenDevice function call. This function initiates a new connection to a MobiCore device and device-specific resources required to communicate with the MobiCore instance. This function issues a request to the Kinibi Mobicore Daemon. This, in turn, opens a handle to the virtual device /d**ev/mobicore-user. This virtual device is used to then communicate with the Mobicore Driver, running in the NWd kernel.

 

img

 

Allocate World Shared Memory Having obtained a handle to a device session, the NWd CA now asks the Trustlet Connector to create a world-shared shared memory (WSM) region via the mcMallocWSM function. The MobiCore Driver allocates this WSM block, which can then be used as the communication channel between the CA and the SWd TA. In current Kinibi implementations, this shared buffer is mapped into memory at the fixed address 0x00100000 for TAs and address 0x00300000 for Trusted Drivers (TDs).

 

img

 

Trustlet Session The Trustlet Connector in the NWd next attempts to establish a session to a TA using the mcOpenTrustlet call, providing the device’s session ID, pointer to a memory address containing the TA to be loaded, and the pointer and length of a Trustlet Connector Interface (TCI) world-shared-memory buffer. The length of the TCI buffer is currently capped to 1MiB (0x100000). This mcOpenTrustlet request is relayed to the MobiCore Driver in the NWd, which then issues a request to MobiCore in the SWd. MobiCore then brokers the creation of a new session via the MobiCore Control Interface (MCI) and returns the corresponding session ID.

 

img

 

TCI Buffer Communication

 

The communication channel between the CA and the TA is established. Now what?

 

Once a session has been established, the TA is loaded in the TEE and the CA can communicate with it directly via the TCI buffer mapped into both address spaces. The exact protocol for communication between the two is application-specific, but a typical approach would be to use the first 4 bytes of the TCI buffer to send a command ID, and the rest of the buffer to hold the parameters of the corresponding command. Once the command has been placed in the TCI buffer, the CA must notify the TA that the command is ready to be processed using the mcNotify function. This function relays the notification to the MobiCore Driver, which, in turn, notifies Mobicore via mc_notify.

 

Mobicore then wakes the corresponding session end-point, which can then process the incoming command. The NWd waits for the TA to respond by calling the mcWaitNotification function. A loaded TA can wait for incoming commands using the tlApiWaitNotification call, accessible through the TEE’s McLib tlApi. This pauses execution until the CA invokes mcNotify.

 

img

 

TA notifies CA Having been notified of an incoming command, the TA reads the TCI buffer to see which command ID it should run, and processes the corresponding command using the parameters it was given over the TCI buffer. Having completed the request, the TA writes any output back to the TCI buffer and then calls tlApiNotify function. This is relayed back to the NWd causing the mcWaitNotification call to complete. The CA can then inspect the TCI buffer to view the result of its call to the TA.

 

img

 

Communicating with Trusted Drivers

 

In the Trustonic TEE design, Trusted Drivers run in S-EL0, rather than S-EL1. This means that exploiting a TD does not automatically lead to a privilege-escalation to S-EL1. TDs can, however, communicate with the microkernel (MTK) through the drApi provided by McLib. These APIs provide a powerful set of functionalities for mapping physical memory, creating threads, and making requests to the Secure Monitor. In the Trustonic design, TDs can access privileged system services in the TEE-OS via the SVC interface, such as the syscall to map physical memory. Less privileged TAs do not have access to such powerful capabilities, and must therefore communicate with privileged TDs to perform actions such as interacting with peripherals. This TA-TD communication channel is not exposed to the REE. However, an attacker residing in REE who compromises a TA may be able to send malicious data across this interface to try and take control of the TD, thereby gaining access to the privileged APIs that are normally only available to TDs. For this reason, the TA-TD communication channel should also be considered a security-critical boundary.

 

Hard-coded Whitelist: In order to prevent any TA to communicate with any TD, Trustonic uses a whitelist hard-coded into the respective TD with TA UUIDs that are permitted to communicate with that driver. For example, the Trustonic driver with the ID 0x40002 limits its attack surface only to the 10 different TAs. This means an attacker in the REE must compromise not just any TA, but one of these specific TAs in order to interact with this TD.

 

Attacking TDs: To demonstrate how an attacker can load a vulnerable TA via a CA and leverage it to increase its attack surface by communicating with a TD, one can use a memory corruption vulnerability inside a TA with the ID 0x1B000000 to make a call to a TD with the ID 0x40002 which allows communication from that TA [ref]. The ID of a TD can be derived from the TD binary header information.

 

TA interaction with a TD: When a TA wants to communicate with a TD, it needs to call the tlApi_CallDriver or tlApi_CallDriverEx function (depending on the API level the TEE-OS is running) that is part of the tlApi and supply the TD ID and the parameters to that function via registers.

 

img

 

The TD can then map this buffer from the TA address space into the address space of the TD via the IPC Handler using the drApiMapClientAndParams call. Data from the mapped buffer is then being processed to extract the arguments and the command for the handler to be called by the TD.

 

img

 

In order to call the TD, the vulnerable TA has to be loaded and exploited in order to hijack control of the Program Counter inside the TA. The argument registers can then be filled using a ROP chain. Once the registers are filled with the appropriate arguments, the tlApi_callDriver call can be invoked by branching to the tlApi entry.

 

In the next part of the series I will cover the process of reverse engineering TEE components. Stay tuned!


[课程]FART 脱壳王!加量不加价!FART作者讲授!

最后于 2020-3-9 12:41 被crownless编辑 ,原因:
收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//