Skip to content

Commit 283480f

Browse files
committed
Merge tag 'optee-load-for-v6.4' of https://git.linaro.org/people/jens.wiklander/linux-tee into soc/drivers
Add SMC for OP-TEE image loading Adds an SMC call for loading OP-TEE by the kernel. * tag 'optee-load-for-v6.4' of https://git.linaro.org/people/jens.wiklander/linux-tee: tee: optee: Add SMC for loading OP-TEE image Link: https://lore.kernel.org/r/20230405062701.GA3391925@rayden Signed-off-by: Arnd Bergmann <arnd@arndb.de>
2 parents 748d3c3 + f3040da commit 283480f

5 files changed

Lines changed: 243 additions & 0 deletions

File tree

Documentation/staging/tee.rst

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,57 @@ call is done from the thread assisting the interrupt handler. This is a
214214
building block for OP-TEE OS in secure world to implement the top half and
215215
bottom half style of device drivers.
216216

217+
OPTEE_INSECURE_LOAD_IMAGE Kconfig option
218+
----------------------------------------
219+
220+
The OPTEE_INSECURE_LOAD_IMAGE Kconfig option enables the ability to load the
221+
BL32 OP-TEE image from the kernel after the kernel boots, rather than loading
222+
it from the firmware before the kernel boots. This also requires enabling the
223+
corresponding option in Trusted Firmware for Arm. The Trusted Firmware for Arm
224+
documentation [8] explains the security threat associated with enabling this as
225+
well as mitigations at the firmware and platform level.
226+
227+
There are additional attack vectors/mitigations for the kernel that should be
228+
addressed when using this option.
229+
230+
1. Boot chain security.
231+
232+
* Attack vector: Replace the OP-TEE OS image in the rootfs to gain control of
233+
the system.
234+
235+
* Mitigation: There must be boot chain security that verifies the kernel and
236+
rootfs, otherwise an attacker can modify the loaded OP-TEE binary by
237+
modifying it in the rootfs.
238+
239+
2. Alternate boot modes.
240+
241+
* Attack vector: Using an alternate boot mode (i.e. recovery mode), the
242+
OP-TEE driver isn't loaded, leaving the SMC hole open.
243+
244+
* Mitigation: If there are alternate methods of booting the device, such as a
245+
recovery mode, it should be ensured that the same mitigations are applied
246+
in that mode.
247+
248+
3. Attacks prior to SMC invocation.
249+
250+
* Attack vector: Code that is executed prior to issuing the SMC call to load
251+
OP-TEE can be exploited to then load an alternate OS image.
252+
253+
* Mitigation: The OP-TEE driver must be loaded before any potential attack
254+
vectors are opened up. This should include mounting of any modifiable
255+
filesystems, opening of network ports or communicating with external
256+
devices (e.g. USB).
257+
258+
4. Blocking SMC call to load OP-TEE.
259+
260+
* Attack vector: Prevent the driver from being probed, so the SMC call to
261+
load OP-TEE isn't executed when desired, leaving it open to being executed
262+
later and loading a modified OS.
263+
264+
* Mitigation: It is recommended to build the OP-TEE driver as builtin driver
265+
rather than as a module to prevent exploits that may cause the module to
266+
not be loaded.
267+
217268
AMD-TEE driver
218269
==============
219270

@@ -309,3 +360,5 @@ References
309360
[6] include/linux/psp-tee.h
310361

311362
[7] drivers/tee/amdtee/amdtee_if.h
363+
364+
[8] https://trustedfirmware-a.readthedocs.io/en/latest/threat_model/threat_model.html

drivers/tee/optee/Kconfig

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,20 @@ config OPTEE
77
help
88
This implements the OP-TEE Trusted Execution Environment (TEE)
99
driver.
10+
11+
config OPTEE_INSECURE_LOAD_IMAGE
12+
bool "Load OP-TEE image as firmware"
13+
default n
14+
depends on OPTEE && ARM64
15+
help
16+
This loads the BL32 image for OP-TEE as firmware when the driver is
17+
probed. This returns -EPROBE_DEFER until the firmware is loadable from
18+
the filesystem which is determined by checking the system_state until
19+
it is in SYSTEM_RUNNING. This also requires enabling the corresponding
20+
option in Trusted Firmware for Arm. The documentation there explains
21+
the security threat associated with enabling this as well as
22+
mitigations at the firmware and platform level.
23+
https://trustedfirmware-a.readthedocs.io/en/latest/threat_model/threat_model.html
24+
25+
Additional documentation on kernel security risks are at
26+
Documentation/staging/tee.rst.

drivers/tee/optee/optee_msg.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,11 +241,23 @@ struct optee_msg_arg {
241241
* 384fb3e0-e7f8-11e3-af63-0002a5d5c51b.
242242
* Represented in 4 32-bit words in OPTEE_MSG_UID_0, OPTEE_MSG_UID_1,
243243
* OPTEE_MSG_UID_2, OPTEE_MSG_UID_3.
244+
*
245+
* In the case where the OP-TEE image is loaded by the kernel, this will
246+
* initially return an alternate UID to reflect that we are communicating with
247+
* the TF-A image loading service at that time instead of OP-TEE. That UID is:
248+
* a3fbeab1-1246-315d-c7c4-06b9c03cbea4.
249+
* Represented in 4 32-bit words in OPTEE_MSG_IMAGE_LOAD_UID_0,
250+
* OPTEE_MSG_IMAGE_LOAD_UID_1, OPTEE_MSG_IMAGE_LOAD_UID_2,
251+
* OPTEE_MSG_IMAGE_LOAD_UID_3.
244252
*/
245253
#define OPTEE_MSG_UID_0 0x384fb3e0
246254
#define OPTEE_MSG_UID_1 0xe7f811e3
247255
#define OPTEE_MSG_UID_2 0xaf630002
248256
#define OPTEE_MSG_UID_3 0xa5d5c51b
257+
#define OPTEE_MSG_IMAGE_LOAD_UID_0 0xa3fbeab1
258+
#define OPTEE_MSG_IMAGE_LOAD_UID_1 0x1246315d
259+
#define OPTEE_MSG_IMAGE_LOAD_UID_2 0xc7c406b9
260+
#define OPTEE_MSG_IMAGE_LOAD_UID_3 0xc03cbea4
249261
#define OPTEE_MSG_FUNCID_CALLS_UID 0xFF01
250262

251263
/*

drivers/tee/optee/optee_smc.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,30 @@ struct optee_smc_call_get_os_revision_result {
104104
unsigned long reserved1;
105105
};
106106

107+
/*
108+
* Load Trusted OS from optee/tee.bin in the Linux firmware.
109+
*
110+
* WARNING: Use this cautiously as it could lead to insecure loading of the
111+
* Trusted OS.
112+
* This SMC instructs EL3 to load a binary and execute it as the Trusted OS.
113+
*
114+
* Call register usage:
115+
* a0 SMC Function ID, OPTEE_SMC_CALL_LOAD_IMAGE
116+
* a1 Upper 32bit of a 64bit size for the payload
117+
* a2 Lower 32bit of a 64bit size for the payload
118+
* a3 Upper 32bit of the physical address for the payload
119+
* a4 Lower 32bit of the physical address for the payload
120+
*
121+
* The payload is in the OP-TEE image format.
122+
*
123+
* Returns result in a0, 0 on success and an error code otherwise.
124+
*/
125+
#define OPTEE_SMC_FUNCID_LOAD_IMAGE 2
126+
#define OPTEE_SMC_CALL_LOAD_IMAGE \
127+
ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, \
128+
ARM_SMCCC_OWNER_TRUSTED_OS_END, \
129+
OPTEE_SMC_FUNCID_LOAD_IMAGE)
130+
107131
/*
108132
* Call with struct optee_msg_arg as argument
109133
*

drivers/tee/optee/smc_abi.c

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@
77
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
88

99
#include <linux/arm-smccc.h>
10+
#include <linux/cpuhotplug.h>
1011
#include <linux/errno.h>
12+
#include <linux/firmware.h>
1113
#include <linux/interrupt.h>
1214
#include <linux/io.h>
1315
#include <linux/irqdomain.h>
16+
#include <linux/kernel.h>
1417
#include <linux/mm.h>
1518
#include <linux/module.h>
1619
#include <linux/of.h>
@@ -1263,6 +1266,22 @@ static bool optee_msg_api_uid_is_optee_api(optee_invoke_fn *invoke_fn)
12631266
return false;
12641267
}
12651268

1269+
#ifdef CONFIG_OPTEE_INSECURE_LOAD_IMAGE
1270+
static bool optee_msg_api_uid_is_optee_image_load(optee_invoke_fn *invoke_fn)
1271+
{
1272+
struct arm_smccc_res res;
1273+
1274+
invoke_fn(OPTEE_SMC_CALLS_UID, 0, 0, 0, 0, 0, 0, 0, &res);
1275+
1276+
if (res.a0 == OPTEE_MSG_IMAGE_LOAD_UID_0 &&
1277+
res.a1 == OPTEE_MSG_IMAGE_LOAD_UID_1 &&
1278+
res.a2 == OPTEE_MSG_IMAGE_LOAD_UID_2 &&
1279+
res.a3 == OPTEE_MSG_IMAGE_LOAD_UID_3)
1280+
return true;
1281+
return false;
1282+
}
1283+
#endif
1284+
12661285
static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
12671286
{
12681287
union {
@@ -1468,6 +1487,120 @@ static void optee_shutdown(struct platform_device *pdev)
14681487
optee_disable_shm_cache(optee);
14691488
}
14701489

1490+
#ifdef CONFIG_OPTEE_INSECURE_LOAD_IMAGE
1491+
1492+
#define OPTEE_FW_IMAGE "optee/tee.bin"
1493+
1494+
static optee_invoke_fn *cpuhp_invoke_fn;
1495+
1496+
static int optee_cpuhp_probe(unsigned int cpu)
1497+
{
1498+
/*
1499+
* Invoking a call on a CPU will cause OP-TEE to perform the required
1500+
* setup for that CPU. Just invoke the call to get the UID since that
1501+
* has no side effects.
1502+
*/
1503+
if (optee_msg_api_uid_is_optee_api(cpuhp_invoke_fn))
1504+
return 0;
1505+
else
1506+
return -EINVAL;
1507+
}
1508+
1509+
static int optee_load_fw(struct platform_device *pdev,
1510+
optee_invoke_fn *invoke_fn)
1511+
{
1512+
const struct firmware *fw = NULL;
1513+
struct arm_smccc_res res;
1514+
phys_addr_t data_pa;
1515+
u8 *data_buf = NULL;
1516+
u64 data_size;
1517+
u32 data_pa_high, data_pa_low;
1518+
u32 data_size_high, data_size_low;
1519+
int rc;
1520+
int hp_state;
1521+
1522+
if (!optee_msg_api_uid_is_optee_image_load(invoke_fn))
1523+
return 0;
1524+
1525+
rc = request_firmware(&fw, OPTEE_FW_IMAGE, &pdev->dev);
1526+
if (rc) {
1527+
/*
1528+
* The firmware in the rootfs will not be accessible until we
1529+
* are in the SYSTEM_RUNNING state, so return EPROBE_DEFER until
1530+
* that point.
1531+
*/
1532+
if (system_state < SYSTEM_RUNNING)
1533+
return -EPROBE_DEFER;
1534+
goto fw_err;
1535+
}
1536+
1537+
data_size = fw->size;
1538+
/*
1539+
* This uses the GFP_DMA flag to ensure we are allocated memory in the
1540+
* 32-bit space since TF-A cannot map memory beyond the 32-bit boundary.
1541+
*/
1542+
data_buf = kmalloc(fw->size, GFP_KERNEL | GFP_DMA);
1543+
if (!data_buf) {
1544+
rc = -ENOMEM;
1545+
goto fw_err;
1546+
}
1547+
memcpy(data_buf, fw->data, fw->size);
1548+
data_pa = virt_to_phys(data_buf);
1549+
reg_pair_from_64(&data_pa_high, &data_pa_low, data_pa);
1550+
reg_pair_from_64(&data_size_high, &data_size_low, data_size);
1551+
goto fw_load;
1552+
1553+
fw_err:
1554+
pr_warn("image loading failed\n");
1555+
data_pa_high = 0;
1556+
data_pa_low = 0;
1557+
data_size_high = 0;
1558+
data_size_low = 0;
1559+
1560+
fw_load:
1561+
/*
1562+
* Always invoke the SMC, even if loading the image fails, to indicate
1563+
* to EL3 that we have passed the point where it should allow invoking
1564+
* this SMC.
1565+
*/
1566+
pr_warn("OP-TEE image loaded from kernel, this can be insecure");
1567+
invoke_fn(OPTEE_SMC_CALL_LOAD_IMAGE, data_size_high, data_size_low,
1568+
data_pa_high, data_pa_low, 0, 0, 0, &res);
1569+
if (!rc)
1570+
rc = res.a0;
1571+
if (fw)
1572+
release_firmware(fw);
1573+
kfree(data_buf);
1574+
1575+
if (!rc) {
1576+
/*
1577+
* We need to initialize OP-TEE on all other running cores as
1578+
* well. Any cores that aren't running yet will get initialized
1579+
* when they are brought up by the power management functions in
1580+
* TF-A which are registered by the OP-TEE SPD. Due to that we
1581+
* can un-register the callback right after registering it.
1582+
*/
1583+
cpuhp_invoke_fn = invoke_fn;
1584+
hp_state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "optee:probe",
1585+
optee_cpuhp_probe, NULL);
1586+
if (hp_state < 0) {
1587+
pr_warn("Failed with CPU hotplug setup for OP-TEE");
1588+
return -EINVAL;
1589+
}
1590+
cpuhp_remove_state(hp_state);
1591+
cpuhp_invoke_fn = NULL;
1592+
}
1593+
1594+
return rc;
1595+
}
1596+
#else
1597+
static inline int optee_load_fw(struct platform_device *pdev,
1598+
optee_invoke_fn *invoke_fn)
1599+
{
1600+
return 0;
1601+
}
1602+
#endif
1603+
14711604
static int optee_probe(struct platform_device *pdev)
14721605
{
14731606
optee_invoke_fn *invoke_fn;
@@ -1486,6 +1619,10 @@ static int optee_probe(struct platform_device *pdev)
14861619
if (IS_ERR(invoke_fn))
14871620
return PTR_ERR(invoke_fn);
14881621

1622+
rc = optee_load_fw(pdev, invoke_fn);
1623+
if (rc)
1624+
return rc;
1625+
14891626
if (!optee_msg_api_uid_is_optee_api(invoke_fn)) {
14901627
pr_warn("api uid mismatch\n");
14911628
return -EINVAL;

0 commit comments

Comments
 (0)