|
|
Subscribe / Log in / New account

A kernel TEE party

By Jonathan Corbet
March 15, 2017
The operating system kernel is normally thought of as having power over the entire system, but there are reasons, both good and bad, for wanting to isolate some functionality even from the kernel. One example is the trusted platform module (TPM) found on many x86 systems; it can provide various cryptographic services to the kernel, but its internals are not accessible to kernel code. In the ARM world, this kind of functionality is often provided via the TrustZone mechanism, but the kernel has no standardized way of working with TrustZone code. The generic TEE subsystem patches from Jens Wiklander aim to change that state of affairs.

A processor with TrustZone support can run in two modes, often termed the secure and non-secure worlds. The secure world can be given exclusive access to memory, devices, and more; those resources are inaccessible when running in the non-secure mode. A hardware trap mechanism is used to transition between the two worlds. The secure-world code, thus, looks a lot like an innermost kernel, protected from the Linux kernel, that has a limited set of security-relevant tasks to perform.

The secure world gains control first at boot time, allowing it to set up access to the rest of its resources and configure the environment for the non-secure kernel. This would also be the time to implement a secure-boot mechanism, if desired, ensuring that the non-secure kernel carries an acceptable signature. A number of functions can be implemented in the secure-world code. For example, cryptographic keys can be stored there, inaccessible to the rest of the system, but usable by the secure world to generate signatures. Naturally, there is interest in using the secure world to implement digital rights management mechanisms and other unpleasant things. Like most of these technologies, TrustZone can be used to ensure a user's control over their computer or to take it away.

The code running in the secure world is often called the "trusted execution environment", or TEE (as opposed to the non-secure "rich execution environment" or REE). As befits the ARM world, there are a lot of TEEs out there, each with its own interface to the kernel. The purpose of the generic TEE subsystem is to settle on one kernel-side interface for TEEs, with a standard communication mechanism for talking to them. To that end, it creates two sets of devices: /dev/teeN, and /dev/teeprivN. The former set allows user space to make requests of the TEE, while the latter is there for "supplicant" processes that provide services to the TEE.

A process needing a TEE service opens the appropriate device, then issues a series of ioctl() calls. The available commands include TEE_IOC_SHM_ALLOC to allocate a range of memory shared between the process and the TEE, TEE_IOC_INVOKE to call a function inside the TEE, and more. For each call, the TEE generates some sort of results which are passed back to the calling process. For the /dev/teepriv interfaces, the calls go the other way; when the TEE needs a user-space service (the contents of a file on disk, say), it will send a request to the waiting supplicant process via this interface.

The generic TEE code is, for the most part, a wrapper layer that turns user-space ioctl() calls into calls to the low-level driver. That driver will have registered itself, providing a tee_driver_ops structure with its operations. The biggest exception relates to the handling of shared-memory segments, which involves a certain amount of complexity. There is a fairly elaborate reference-counting mechanism that, for example, tracks the references created by every parameter passed into a TEE operation; that ensures that the memory is not freed while references still exist.

The low-level driver code is charged with communicating between the generic TEE layer and the actual TEE implementation. Much of this code is concerned with formatting requests as expected by the TEE and low-level communications. Shared memory is also an issue at this level, since mapping memory that the TEE can access requires cooperation with the TEE itself.

The generic TEE subsystem patches come with a driver for one TEE, an open-source implementation called OP-TEE. This system, developed by STMicroelectronics and Linaro, provides a simple operating-system kernel meant to run in the secure world. OP-TEE is meant to be the substrate on which TEEs are created; those wanting to learn more can have a look at this design document. There is also an OP-TEE "hello world" application giving an idea of what secure-world code looks like.

All of this structure is intended to build things like the OP-TEE secure data path (recently presented at Linaro Connect), the purpose of which is to enable Android devices to play protected content without letting the end users actually get their hands on it. But a free TEE environment should also make it easy to develop less user-hostile secure services as free software. Once the generic TEE patches are merged (something that seems like it should happen sometime this year), we'll have a standard interface for providing and using such services.

Index entries for this article
SecurityHardware


to post comments


Copyright © 2017, Eklektix, Inc.
This article may be redistributed under the terms of the Creative Commons CC BY-SA 4.0 license
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds