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