As far as I understand there are currently two possibilities to setup an RPMB with an appropriate key.
1. Use a specialized OP-TEE with CFG_RPMB_WRITE_KEY=y during production in an environment were leaking the key is ok.
2. Get the HUK, get the CID from the MMC, then use scripts/derive_rpmb_key.py to calculate the RPMB key and set e.g. via mmc tool.
I've the impression when I read through some message on https://github.com/OP-TEE/optee_os/issues, that 1 is not considered the best idea.
Currently I'm working on a iMX8M platform and using CFG_RPMB_WRITE_KEY also has the drawback to use the legacy RPMB interface, which makes tee-supplicant still necessary, which otherwise would not be needed.
The problem at least on iMX8M is that its not easy possible to get the HUK, and the HUK also is different, depending if a device is in a closed state or not. To extract the whole HUK, even in a sensible environment during production, seems unnecessary.
What I did now, something very simple. I extended tee_rpmb_fs.c a little bit and made a function which allows to retrieve the RPMB key, I added also a tiny PTA, and a corresponding user space application to get the RPMB key, only as long CFG_INSECURE is set, therefore also only a specialized OP-TEE build can provide this functionality.
Someone can now decide to get the RPMB key either before the device is closed (for testing devices), or afterwards. Write then the RPMB key manually (e.g. via mmc tool) and/or also store it securly in a production data database.
What would be the advantages, compared to CFG_RPMB_WRITE_KEY=y
- HUK is still not leaked, as it may be used to derive other secrets
- derive_rpmb_key.py is not necessary
- It is guaranteed that the correct RPMB key is retrieved, 100% matches how OP-TEE was configured (e.g. with compat mode enabled or not)
- Because the RPMB key is known, one can manually still delete the RPMB and see how OP-TEE handles this situation, at least during development
- Testing this functionality also on an open device (which is currently not possible at least on iMX8M, due to plat_rpmb_key_is_ready)
My question is, if there would be any interest to open a PR, so other people also can use this?
Hi,
We are using OP-TEE together with a library that provides its own "fallthrough" define, similar to what OP-TEE does in lib/libutils/ext/include/compiler.h:
#define fallthrough __attribute__((__fallthrough__))
However, this other library checks for fallthrough attribute support by first doing:
#if __has_cpp_attribute(fallthrough)
...
#endif
which fails to compile due to the OP-TEE define.
Would OP-TEE accept a patch to rename the "fallthrough" define to something like "optee_fallthrough", "FALLTHROUGH", <other suggestion> ?
Or should we upstream a patch to the library to do:
#if __has_cpp_attribute(__fallthrough__)
...
#endif
(which is what OP-TEE currently does)
Regards
Jacob
A KVM guest running on an arm64 machine will not be able to interact with a trusted execution environment
(which supports non-secure guests) like OP-TEE in the secure world. This is because, instructions provided
by the architecture (such as, SMC) which switch control to the firmware, are trapped in EL2 when the guest
is executes them.
This series adds a feature into the kernel called the TEE mediator abstraction layer, which lets
a guest interact with the secure world. Additionally, a OP-TEE specific mediator is also implemented, which
hooks itself to the TEE mediator layer and intercepts guest SMCs targetted at OP-TEE.
Overview
=========
Essentially, if the kernel wants to interact with OP-TEE, it makes an "smc - secure monitor call instruction",
after loading in arguments into CPU registers. What these arguments consists of and how both these entities
communicate can vary. If a guest wants to establish a connection with the secure world, its not possible.
This is because of the fact that "smc" by the guest are trapped by the hypervisor in EL2. This is done by setting
the HCR_EL2.TSC bit before entering the guest.
Hence, this feature which I we may call TEE mediator, acts as an intermediary between the guest and OP-TEE.
Instead of denying the guest SMC and jumping back into the guest, the mediator forwards the request to
OP-TEE.
OP-TEE supports virtualization in the normal world and expects 6 things from the NS-hypervisor:
1. Notify OP-TEE when a VM is created.
2. Notify OP-TEE when a VM is destroyed.
3. Any SMC to OP-TEE has to contain the VMID in x7. If its the hypervisor sending, then VMID is 0.
4. Hypervisor has to perform IPA->PA translations of the memory addresses sent by guest.
5. Memory shared by the VM to OP-TEE has to remain pinned.
6. The hypervisor has to follow the OP-TEE protocol, so the guest thinks it is directly speaking to OP-TEE.
Its important to note that, if OP-TEE is built with NS-virtualization support, it can only function if there is
a hypervisor with a mediator in normal world.
This implementation has been heavily inspired by Xen's OP-TEE mediator.
Design
======
The unique design of KVM makes it quite challenging to implement such a mediator. OP-TEE is not aware of the host-guest
paradigm. Hence, the mediator treats the host as a VM with VMID 1. The guests are assigned VMIDs starting from 2 (note,
these are not the VMIDs tagged in TLB, rather we implement our own simple indexing mechanism).
When the host's OP-TEE driver is initialised or released, OP-TEE is notified about VM 1 being created/destroyed.
When a VMM (such as, QEMU) created a guest through KVM ioctls, a call to the TEE mediator layer is made, which in-turn
calls OP-TEE mediator which eventually assigns a VM context, VMID, etc. and notifies OP-TEE about guest creation. The
opposite happens on guest destruction.
When the guest makes an SMC targetting OP-TEE, it is trapped by the hypervisor and the register state (kvm_vcpu) is sent to
the OP-TEE mediator through the TEE layer. Here there are two possibilities.
The guest may make an SMC with arguments which are simple numeric values, exchanging UUID, version information, etc.
In this case, the mediator has much less work. It has to attach VMID into X7 and pass the register state to OP-TEE.
But, when guest passes memory addresses as arguments, the mediator has to translate these into physical addresses from
intermediate physical addresses (IPA). According to the OP-TEE protocol (as documented in optee_smc.h and optee_msg.h),
the guest OP-TEE driver would share a buffer filled with pointers, which the mediator translates.
The OP-TEE mediator also keeps track of active calls between each guest and OP-TEE, and pins pages which are already shared.
This is to avoid swapping of shared pages by the host under memory pressure. These pages are unpinned as soon as guest's
transaction completes with OP-TEE.
Testing
=======
The feature has been tested on QEMU virt platform using "xtest" as the test suite. As of now, all of 35000+ tests pass.
The mediator has also been stressed under memory pressure and all tests pass too. Any suggestions on further testing the
feature are welcome.
Call for review
===============
Any insights/suggestions regarding the implementation are appreciated.
Yuvraj Sakshith (7):
firmware: smccc: Add macros for Trusted OS/App owner check on SMC
value
tee: Add TEE Mediator module which aims to expose TEE to a KVM guest.
KVM: Notify TEE Mediator when KVM creates and destroys guests
KVM: arm64: Forward guest CPU state to TEE mediator on SMC trap
tee: optee: Add OPTEE_SMC_VM_CREATED and OPTEE_SMC_VM_DESTROYED
tee: optee: Add OP-TEE Mediator
tee: optee: Notify TEE Mediator on OP-TEE driver initialization and
release
arch/arm64/kvm/hypercalls.c | 15 +-
drivers/tee/Kconfig | 5 +
drivers/tee/Makefile | 1 +
drivers/tee/optee/Kconfig | 7 +
drivers/tee/optee/Makefile | 1 +
drivers/tee/optee/core.c | 13 +-
drivers/tee/optee/optee_mediator.c | 1319 ++++++++++++++++++++++++++++
drivers/tee/optee/optee_mediator.h | 103 +++
drivers/tee/optee/optee_smc.h | 53 ++
drivers/tee/optee/smc_abi.c | 6 +
drivers/tee/tee_mediator.c | 145 +++
include/linux/arm-smccc.h | 8 +
include/linux/tee_mediator.h | 39 +
virt/kvm/kvm_main.c | 11 +-
14 files changed, 1721 insertions(+), 5 deletions(-)
create mode 100644 drivers/tee/optee/optee_mediator.c
create mode 100644 drivers/tee/optee/optee_mediator.h
create mode 100644 drivers/tee/tee_mediator.c
create mode 100644 include/linux/tee_mediator.h
--
2.43.0