1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * UEFI runtime variable services
4 *
5 * Copyright (c) 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
6 * Copyright (c) 2020 Linaro Limited, Author: AKASHI Takahiro
7 */
8
9 #include <common.h>
10 #include <efi_loader.h>
11 #include <efi_variable.h>
12
13 enum efi_secure_mode {
14 EFI_MODE_SETUP,
15 EFI_MODE_USER,
16 EFI_MODE_AUDIT,
17 EFI_MODE_DEPLOYED,
18 };
19
20 struct efi_auth_var_name_type {
21 const u16 *name;
22 const efi_guid_t *guid;
23 const enum efi_auth_var_type type;
24 };
25
26 static const struct efi_auth_var_name_type name_type[] = {
27 {u"PK", &efi_global_variable_guid, EFI_AUTH_VAR_PK},
28 {u"KEK", &efi_global_variable_guid, EFI_AUTH_VAR_KEK},
29 {u"db", &efi_guid_image_security_database, EFI_AUTH_VAR_DB},
30 {u"dbx", &efi_guid_image_security_database, EFI_AUTH_VAR_DBX},
31 /* not used yet
32 {u"dbt", &efi_guid_image_security_database, EFI_AUTH_VAR_DBT},
33 {u"dbr", &efi_guid_image_security_database, EFI_AUTH_VAR_DBR},
34 */
35 };
36
37 static bool efi_secure_boot;
38 static enum efi_secure_mode efi_secure_mode;
39
40 /**
41 * efi_efi_get_variable() - retrieve value of a UEFI variable
42 *
43 * This function implements the GetVariable runtime service.
44 *
45 * See the Unified Extensible Firmware Interface (UEFI) specification for
46 * details.
47 *
48 * @variable_name: name of the variable
49 * @vendor: vendor GUID
50 * @attributes: attributes of the variable
51 * @data_size: size of the buffer to which the variable value is copied
52 * @data: buffer to which the variable value is copied
53 * Return: status code
54 */
efi_get_variable(u16 * variable_name,const efi_guid_t * vendor,u32 * attributes,efi_uintn_t * data_size,void * data)55 efi_status_t EFIAPI efi_get_variable(u16 *variable_name,
56 const efi_guid_t *vendor, u32 *attributes,
57 efi_uintn_t *data_size, void *data)
58 {
59 efi_status_t ret;
60
61 EFI_ENTRY("\"%ls\" %pUl %p %p %p", variable_name, vendor, attributes,
62 data_size, data);
63
64 ret = efi_get_variable_int(variable_name, vendor, attributes,
65 data_size, data, NULL);
66
67 /* Remove EFI_VARIABLE_READ_ONLY flag */
68 if (attributes)
69 *attributes &= EFI_VARIABLE_MASK;
70
71 return EFI_EXIT(ret);
72 }
73
74 /**
75 * efi_set_variable() - set value of a UEFI variable
76 *
77 * This function implements the SetVariable runtime service.
78 *
79 * See the Unified Extensible Firmware Interface (UEFI) specification for
80 * details.
81 *
82 * @variable_name: name of the variable
83 * @vendor: vendor GUID
84 * @attributes: attributes of the variable
85 * @data_size: size of the buffer with the variable value
86 * @data: buffer with the variable value
87 * Return: status code
88 */
efi_set_variable(u16 * variable_name,const efi_guid_t * vendor,u32 attributes,efi_uintn_t data_size,const void * data)89 efi_status_t EFIAPI efi_set_variable(u16 *variable_name,
90 const efi_guid_t *vendor, u32 attributes,
91 efi_uintn_t data_size, const void *data)
92 {
93 efi_status_t ret;
94
95 EFI_ENTRY("\"%ls\" %pUl %x %zu %p", variable_name, vendor, attributes,
96 data_size, data);
97
98 /* Make sure that the EFI_VARIABLE_READ_ONLY flag is not set */
99 if (attributes & ~(u32)EFI_VARIABLE_MASK)
100 ret = EFI_INVALID_PARAMETER;
101 else
102 ret = efi_set_variable_int(variable_name, vendor, attributes,
103 data_size, data, true);
104
105 return EFI_EXIT(ret);
106 }
107
108 /**
109 * efi_get_next_variable_name() - enumerate the current variable names
110 *
111 * @variable_name_size: size of variable_name buffer in byte
112 * @variable_name: name of uefi variable's name in u16
113 * @vendor: vendor's guid
114 *
115 * See the Unified Extensible Firmware Interface (UEFI) specification for
116 * details.
117 *
118 * Return: status code
119 */
efi_get_next_variable_name(efi_uintn_t * variable_name_size,u16 * variable_name,efi_guid_t * vendor)120 efi_status_t EFIAPI efi_get_next_variable_name(efi_uintn_t *variable_name_size,
121 u16 *variable_name,
122 efi_guid_t *vendor)
123 {
124 efi_status_t ret;
125
126 EFI_ENTRY("%p \"%ls\" %pUl", variable_name_size, variable_name, vendor);
127
128 ret = efi_get_next_variable_name_int(variable_name_size, variable_name,
129 vendor);
130
131 return EFI_EXIT(ret);
132 }
133
134 /**
135 * efi_query_variable_info() - get information about EFI variables
136 *
137 * This function implements the QueryVariableInfo() runtime service.
138 *
139 * See the Unified Extensible Firmware Interface (UEFI) specification for
140 * details.
141 *
142 * @attributes: bitmask to select variables to be
143 * queried
144 * @maximum_variable_storage_size: maximum size of storage area for the
145 * selected variable types
146 * @remaining_variable_storage_size: remaining size of storage are for the
147 * selected variable types
148 * @maximum_variable_size: maximum size of a variable of the
149 * selected type
150 * Returns: status code
151 */
efi_query_variable_info(u32 attributes,u64 * maximum_variable_storage_size,u64 * remaining_variable_storage_size,u64 * maximum_variable_size)152 efi_status_t EFIAPI efi_query_variable_info(
153 u32 attributes, u64 *maximum_variable_storage_size,
154 u64 *remaining_variable_storage_size,
155 u64 *maximum_variable_size)
156 {
157 efi_status_t ret;
158
159 EFI_ENTRY("%x %p %p %p", attributes, maximum_variable_storage_size,
160 remaining_variable_storage_size, maximum_variable_size);
161
162 ret = efi_query_variable_info_int(attributes,
163 maximum_variable_storage_size,
164 remaining_variable_storage_size,
165 maximum_variable_size);
166
167 return EFI_EXIT(ret);
168 }
169
170 efi_status_t __efi_runtime EFIAPI
efi_get_variable_runtime(u16 * variable_name,const efi_guid_t * guid,u32 * attributes,efi_uintn_t * data_size,void * data)171 efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
172 u32 *attributes, efi_uintn_t *data_size, void *data)
173 {
174 efi_status_t ret;
175
176 ret = efi_get_variable_mem(variable_name, guid, attributes, data_size, data, NULL);
177
178 /* Remove EFI_VARIABLE_READ_ONLY flag */
179 if (attributes)
180 *attributes &= EFI_VARIABLE_MASK;
181
182 return ret;
183 }
184
185 efi_status_t __efi_runtime EFIAPI
efi_get_next_variable_name_runtime(efi_uintn_t * variable_name_size,u16 * variable_name,efi_guid_t * guid)186 efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
187 u16 *variable_name, efi_guid_t *guid)
188 {
189 return efi_get_next_variable_name_mem(variable_name_size, variable_name, guid);
190 }
191
192 /**
193 * efi_set_secure_state - modify secure boot state variables
194 * @secure_boot: value of SecureBoot
195 * @setup_mode: value of SetupMode
196 * @audit_mode: value of AuditMode
197 * @deployed_mode: value of DeployedMode
198 *
199 * Modify secure boot status related variables as indicated.
200 *
201 * Return: status code
202 */
efi_set_secure_state(u8 secure_boot,u8 setup_mode,u8 audit_mode,u8 deployed_mode)203 static efi_status_t efi_set_secure_state(u8 secure_boot, u8 setup_mode,
204 u8 audit_mode, u8 deployed_mode)
205 {
206 efi_status_t ret;
207 const u32 attributes_ro = EFI_VARIABLE_BOOTSERVICE_ACCESS |
208 EFI_VARIABLE_RUNTIME_ACCESS |
209 EFI_VARIABLE_READ_ONLY;
210 const u32 attributes_rw = EFI_VARIABLE_BOOTSERVICE_ACCESS |
211 EFI_VARIABLE_RUNTIME_ACCESS;
212
213 efi_secure_boot = secure_boot;
214
215 ret = efi_set_variable_int(L"SecureBoot", &efi_global_variable_guid,
216 attributes_ro, sizeof(secure_boot),
217 &secure_boot, false);
218 if (ret != EFI_SUCCESS)
219 goto err;
220
221 ret = efi_set_variable_int(L"SetupMode", &efi_global_variable_guid,
222 attributes_ro, sizeof(setup_mode),
223 &setup_mode, false);
224 if (ret != EFI_SUCCESS)
225 goto err;
226
227 ret = efi_set_variable_int(L"AuditMode", &efi_global_variable_guid,
228 audit_mode || setup_mode ?
229 attributes_ro : attributes_rw,
230 sizeof(audit_mode), &audit_mode, false);
231 if (ret != EFI_SUCCESS)
232 goto err;
233
234 ret = efi_set_variable_int(L"DeployedMode",
235 &efi_global_variable_guid,
236 audit_mode || deployed_mode || setup_mode ?
237 attributes_ro : attributes_rw,
238 sizeof(deployed_mode), &deployed_mode,
239 false);
240 err:
241 return ret;
242 }
243
244 /**
245 * efi_transfer_secure_state - handle a secure boot state transition
246 * @mode: new state
247 *
248 * Depending on @mode, secure boot related variables are updated.
249 * Those variables are *read-only* for users, efi_set_variable_int()
250 * is called here.
251 *
252 * Return: status code
253 */
efi_transfer_secure_state(enum efi_secure_mode mode)254 static efi_status_t efi_transfer_secure_state(enum efi_secure_mode mode)
255 {
256 efi_status_t ret;
257
258 EFI_PRINT("Switching secure state from %d to %d\n", efi_secure_mode,
259 mode);
260
261 if (mode == EFI_MODE_DEPLOYED) {
262 ret = efi_set_secure_state(1, 0, 0, 1);
263 if (ret != EFI_SUCCESS)
264 goto err;
265 } else if (mode == EFI_MODE_AUDIT) {
266 ret = efi_set_variable_int(L"PK", &efi_global_variable_guid,
267 EFI_VARIABLE_BOOTSERVICE_ACCESS |
268 EFI_VARIABLE_RUNTIME_ACCESS,
269 0, NULL, false);
270 if (ret != EFI_SUCCESS)
271 goto err;
272
273 ret = efi_set_secure_state(0, 1, 1, 0);
274 if (ret != EFI_SUCCESS)
275 goto err;
276 } else if (mode == EFI_MODE_USER) {
277 ret = efi_set_secure_state(1, 0, 0, 0);
278 if (ret != EFI_SUCCESS)
279 goto err;
280 } else if (mode == EFI_MODE_SETUP) {
281 ret = efi_set_secure_state(0, 1, 0, 0);
282 if (ret != EFI_SUCCESS)
283 goto err;
284 } else {
285 return EFI_INVALID_PARAMETER;
286 }
287
288 efi_secure_mode = mode;
289
290 return EFI_SUCCESS;
291
292 err:
293 /* TODO: What action should be taken here? */
294 printf("ERROR: Secure state transition failed\n");
295 return ret;
296 }
297
efi_init_secure_state(void)298 efi_status_t efi_init_secure_state(void)
299 {
300 enum efi_secure_mode mode = EFI_MODE_SETUP;
301 u8 efi_vendor_keys = 0;
302 efi_uintn_t size = 0;
303 efi_status_t ret;
304
305 ret = efi_get_variable_int(L"PK", &efi_global_variable_guid,
306 NULL, &size, NULL, NULL);
307 if (ret == EFI_BUFFER_TOO_SMALL) {
308 if (IS_ENABLED(CONFIG_EFI_SECURE_BOOT))
309 mode = EFI_MODE_USER;
310 }
311
312 ret = efi_transfer_secure_state(mode);
313 if (ret != EFI_SUCCESS)
314 return ret;
315
316 /* As we do not provide vendor keys this variable is always 0. */
317 ret = efi_set_variable_int(L"VendorKeys",
318 &efi_global_variable_guid,
319 EFI_VARIABLE_BOOTSERVICE_ACCESS |
320 EFI_VARIABLE_RUNTIME_ACCESS |
321 EFI_VARIABLE_READ_ONLY,
322 sizeof(efi_vendor_keys),
323 &efi_vendor_keys, false);
324 return ret;
325 }
326
327 /**
328 * efi_secure_boot_enabled - return if secure boot is enabled or not
329 *
330 * Return: true if enabled, false if disabled
331 */
efi_secure_boot_enabled(void)332 bool efi_secure_boot_enabled(void)
333 {
334 return efi_secure_boot;
335 }
336
efi_auth_var_get_type(u16 * name,const efi_guid_t * guid)337 enum efi_auth_var_type efi_auth_var_get_type(u16 *name, const efi_guid_t *guid)
338 {
339 for (size_t i = 0; i < ARRAY_SIZE(name_type); ++i) {
340 if (!u16_strcmp(name, name_type[i].name) &&
341 !guidcmp(guid, name_type[i].guid))
342 return name_type[i].type;
343 }
344 return EFI_AUTH_VAR_NONE;
345 }
346