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