Skip to content

Commit c44b6be

Browse files
Masahisa Kojimaardbiesheuvel
authored andcommitted
efi: Add tee-based EFI variable driver
When the flash is not owned by the non-secure world, accessing the EFI variables is straight-forward and done via EFI Runtime Variable Services. In this case, critical variables for system integrity and security are normally stored in the dedicated secure storage and can only be manipulated directly from the secure world. Usually, small embedded devices don't have the special dedicated secure storage. The eMMC device with an RPMB partition is becoming more common, and we can use this RPMB partition to store the EFI Variables. The eMMC device is typically owned by the non-secure world (Linux in our case). There is an existing solution utilizing eMMC RPMB partition for EFI Variables, it is implemented by interacting with TEE (OP-TEE in this case), StandaloneMM (as EFI Variable Service Pseudo TA), eMMC driver and tee-supplicant. The last piece is the tee-based variable access driver to interact with TEE and StandaloneMM. So let's add the kernel functions needed. This feature is implemented as a kernel module. StMM PTA has TA_FLAG_DEVICE_ENUM_SUPP flag when registered to OP-TEE so that this tee_stmm_efi module is probed after tee-supplicant starts, since "SetVariable" EFI Runtime Variable Service requires to interact with tee-supplicant. Acked-by: Sumit Garg <sumit.garg@linaro.org> Co-developed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org> Signed-off-by: Ilias Apalodimas <ilias.apalodimas@linaro.org> Signed-off-by: Masahisa Kojima <masahisa.kojima@linaro.org> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
1 parent 1f71f37 commit c44b6be

File tree

4 files changed

+868
-0
lines changed

4 files changed

+868
-0
lines changed

drivers/firmware/efi/Kconfig

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,3 +301,18 @@ config UEFI_CPER_X86
301301
bool
302302
depends on UEFI_CPER && X86
303303
default y
304+
305+
config TEE_STMM_EFI
306+
tristate "TEE-based EFI runtime variable service driver"
307+
depends on EFI && OPTEE
308+
help
309+
Select this config option if TEE is compiled to include StandAloneMM
310+
as a separate secure partition. It has the ability to check and store
311+
EFI variables on an RPMB or any other non-volatile medium used by
312+
StandAloneMM.
313+
314+
Enabling this will change the EFI runtime services from the firmware
315+
provided functions to TEE calls.
316+
317+
To compile this driver as a module, choose M here: the module
318+
will be called tee_stmm_efi.

drivers/firmware/efi/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,4 @@ obj-$(CONFIG_EFI_EARLYCON) += earlycon.o
4242
obj-$(CONFIG_UEFI_CPER_ARM) += cper-arm.o
4343
obj-$(CONFIG_UEFI_CPER_X86) += cper-x86.o
4444
obj-$(CONFIG_UNACCEPTED_MEMORY) += unaccepted_memory.o
45+
obj-$(CONFIG_TEE_STMM_EFI) += stmm/tee_stmm_efi.o
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
/* SPDX-License-Identifier: GPL-2.0+ */
2+
/*
3+
* Headers for EFI variable service via StandAloneMM, EDK2 application running
4+
* in OP-TEE. Most of the structs and defines resemble the EDK2 naming.
5+
*
6+
* Copyright (c) 2017, Intel Corporation. All rights reserved.
7+
* Copyright (C) 2020 Linaro Ltd.
8+
*/
9+
10+
#ifndef _MM_COMMUNICATION_H_
11+
#define _MM_COMMUNICATION_H_
12+
13+
/*
14+
* Interface to the pseudo Trusted Application (TA), which provides a
15+
* communication channel with the Standalone MM (Management Mode)
16+
* Secure Partition running at Secure-EL0
17+
*/
18+
19+
#define PTA_STMM_CMD_COMMUNICATE 0
20+
21+
/*
22+
* Defined in OP-TEE, this UUID is used to identify the pseudo-TA.
23+
* OP-TEE is using big endian GUIDs while UEFI uses little endian ones
24+
*/
25+
#define PTA_STMM_UUID \
26+
UUID_INIT(0xed32d533, 0x99e6, 0x4209, \
27+
0x9c, 0xc0, 0x2d, 0x72, 0xcd, 0xd9, 0x98, 0xa7)
28+
29+
#define EFI_MM_VARIABLE_GUID \
30+
EFI_GUID(0xed32d533, 0x99e6, 0x4209, \
31+
0x9c, 0xc0, 0x2d, 0x72, 0xcd, 0xd9, 0x98, 0xa7)
32+
33+
/**
34+
* struct efi_mm_communicate_header - Header used for SMM variable communication
35+
36+
* @header_guid: header use for disambiguation of content
37+
* @message_len: length of the message. Does not include the size of the
38+
* header
39+
* @data: payload of the message
40+
*
41+
* Defined in the PI spec as EFI_MM_COMMUNICATE_HEADER.
42+
* To avoid confusion in interpreting frames, the communication buffer should
43+
* always begin with efi_mm_communicate_header.
44+
*/
45+
struct efi_mm_communicate_header {
46+
efi_guid_t header_guid;
47+
size_t message_len;
48+
u8 data[];
49+
} __packed;
50+
51+
#define MM_COMMUNICATE_HEADER_SIZE \
52+
(sizeof(struct efi_mm_communicate_header))
53+
54+
/* SPM return error codes */
55+
#define ARM_SVC_SPM_RET_SUCCESS 0
56+
#define ARM_SVC_SPM_RET_NOT_SUPPORTED -1
57+
#define ARM_SVC_SPM_RET_INVALID_PARAMS -2
58+
#define ARM_SVC_SPM_RET_DENIED -3
59+
#define ARM_SVC_SPM_RET_NO_MEMORY -5
60+
61+
#define SMM_VARIABLE_FUNCTION_GET_VARIABLE 1
62+
/*
63+
* The payload for this function is
64+
* SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME.
65+
*/
66+
#define SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME 2
67+
/*
68+
* The payload for this function is SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE.
69+
*/
70+
#define SMM_VARIABLE_FUNCTION_SET_VARIABLE 3
71+
/*
72+
* The payload for this function is
73+
* SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO.
74+
*/
75+
#define SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO 4
76+
/*
77+
* It is a notify event, no extra payload for this function.
78+
*/
79+
#define SMM_VARIABLE_FUNCTION_READY_TO_BOOT 5
80+
/*
81+
* It is a notify event, no extra payload for this function.
82+
*/
83+
#define SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE 6
84+
/*
85+
* The payload for this function is VARIABLE_INFO_ENTRY.
86+
* The GUID in EFI_SMM_COMMUNICATE_HEADER is gEfiSmmVariableProtocolGuid.
87+
*/
88+
#define SMM_VARIABLE_FUNCTION_GET_STATISTICS 7
89+
/*
90+
* The payload for this function is SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
91+
*/
92+
#define SMM_VARIABLE_FUNCTION_LOCK_VARIABLE 8
93+
94+
#define SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET 9
95+
96+
#define SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET 10
97+
98+
#define SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE 11
99+
/*
100+
* The payload for this function is
101+
* SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT
102+
*/
103+
#define SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT 12
104+
105+
#define SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE 13
106+
/*
107+
* The payload for this function is
108+
* SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO
109+
*/
110+
#define SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO 14
111+
112+
/**
113+
* struct smm_variable_communicate_header - Used for SMM variable communication
114+
115+
* @function: function to call in Smm.
116+
* @ret_status: return status
117+
* @data: payload
118+
*/
119+
struct smm_variable_communicate_header {
120+
size_t function;
121+
efi_status_t ret_status;
122+
u8 data[];
123+
};
124+
125+
#define MM_VARIABLE_COMMUNICATE_SIZE \
126+
(sizeof(struct smm_variable_communicate_header))
127+
128+
/**
129+
* struct smm_variable_access - Used to communicate with StMM by
130+
* SetVariable and GetVariable.
131+
132+
* @guid: vendor GUID
133+
* @data_size: size of EFI variable data
134+
* @name_size: size of EFI name
135+
* @attr: attributes
136+
* @name: variable name
137+
*
138+
*/
139+
struct smm_variable_access {
140+
efi_guid_t guid;
141+
size_t data_size;
142+
size_t name_size;
143+
u32 attr;
144+
u16 name[];
145+
};
146+
147+
#define MM_VARIABLE_ACCESS_HEADER_SIZE \
148+
(sizeof(struct smm_variable_access))
149+
/**
150+
* struct smm_variable_payload_size - Used to get the max allowed
151+
* payload used in StMM.
152+
*
153+
* @size: size to fill in
154+
*
155+
*/
156+
struct smm_variable_payload_size {
157+
size_t size;
158+
};
159+
160+
/**
161+
* struct smm_variable_getnext - Used to communicate with StMM for
162+
* GetNextVariableName.
163+
*
164+
* @guid: vendor GUID
165+
* @name_size: size of the name of the variable
166+
* @name: variable name
167+
*
168+
*/
169+
struct smm_variable_getnext {
170+
efi_guid_t guid;
171+
size_t name_size;
172+
u16 name[];
173+
};
174+
175+
#define MM_VARIABLE_GET_NEXT_HEADER_SIZE \
176+
(sizeof(struct smm_variable_getnext))
177+
178+
/**
179+
* struct smm_variable_query_info - Used to communicate with StMM for
180+
* QueryVariableInfo.
181+
*
182+
* @max_variable_storage: max available storage
183+
* @remaining_variable_storage: remaining available storage
184+
* @max_variable_size: max variable supported size
185+
* @attr: attributes to query storage for
186+
*
187+
*/
188+
struct smm_variable_query_info {
189+
u64 max_variable_storage;
190+
u64 remaining_variable_storage;
191+
u64 max_variable_size;
192+
u32 attr;
193+
};
194+
195+
#define VAR_CHECK_VARIABLE_PROPERTY_REVISION 0x0001
196+
#define VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY BIT(0)
197+
/**
198+
* struct var_check_property - Used to store variable properties in StMM
199+
*
200+
* @revision: magic revision number for variable property checking
201+
* @property: properties mask for the variable used in StMM.
202+
* Currently RO flag is supported
203+
* @attributes: variable attributes used in StMM checking when properties
204+
* for a variable are enabled
205+
* @minsize: minimum allowed size for variable payload checked against
206+
* smm_variable_access->datasize in StMM
207+
* @maxsize: maximum allowed size for variable payload checked against
208+
* smm_variable_access->datasize in StMM
209+
*
210+
*/
211+
struct var_check_property {
212+
u16 revision;
213+
u16 property;
214+
u32 attributes;
215+
size_t minsize;
216+
size_t maxsize;
217+
};
218+
219+
/**
220+
* struct smm_variable_var_check_property - Used to communicate variable
221+
* properties with StMM
222+
*
223+
* @guid: vendor GUID
224+
* @name_size: size of EFI name
225+
* @property: variable properties struct
226+
* @name: variable name
227+
*
228+
*/
229+
struct smm_variable_var_check_property {
230+
efi_guid_t guid;
231+
size_t name_size;
232+
struct var_check_property property;
233+
u16 name[];
234+
};
235+
236+
#endif /* _MM_COMMUNICATION_H_ */

0 commit comments

Comments
 (0)