]> code.delx.au - refind/blob - mok/security_policy.c
086ef6acfa232533a4914ccfdd7542d2f09c5107
[refind] / mok / security_policy.c
1 /*
2 * Copyright 2012 <James.Bottomley@HansenPartnership.com>
3 *
4 * see COPYING file
5 *
6 * Install and remove a platform security2 override policy
7 */
8
9 // #include <efi.h>
10 // #include <efilib.h>
11 #include <global.h>
12
13 #include "guid.h"
14 //#include "sha256.h"
15 //#include "variables.h"
16 #include "simple_file.h"
17 //#include "errors.h"
18 #include "../include/refit_call_wrapper.h"
19 #include "mok.h"
20
21 #include <security_policy.h>
22
23 /*
24 * See the UEFI Platform Initialization manual (Vol2: DXE) for this
25 */
26 struct _EFI_SECURITY2_PROTOCOL;
27 struct _EFI_SECURITY_PROTOCOL;
28 struct _EFI_DEVICE_PATH_PROTOCOL;
29 typedef struct _EFI_SECURITY2_PROTOCOL EFI_SECURITY2_PROTOCOL;
30 typedef struct _EFI_SECURITY_PROTOCOL EFI_SECURITY_PROTOCOL;
31 #ifdef __MAKEWITH_GNUEFI
32 typedef struct _EFI_DEVICE_PATH_PROTOCOL EFI_DEVICE_PATH_PROTOCOL;
33 #endif
34
35 typedef EFI_STATUS (EFIAPI *EFI_SECURITY_FILE_AUTHENTICATION_STATE) (
36 const EFI_SECURITY_PROTOCOL *This,
37 UINT32 AuthenticationStatus,
38 const EFI_DEVICE_PATH_PROTOCOL *File
39 );
40 typedef EFI_STATUS (EFIAPI *EFI_SECURITY2_FILE_AUTHENTICATION) (
41 const EFI_SECURITY2_PROTOCOL *This,
42 const EFI_DEVICE_PATH_PROTOCOL *DevicePath,
43 VOID *FileBuffer,
44 UINTN FileSize,
45 BOOLEAN BootPolicy
46 );
47
48 struct _EFI_SECURITY2_PROTOCOL {
49 EFI_SECURITY2_FILE_AUTHENTICATION FileAuthentication;
50 };
51
52 struct _EFI_SECURITY_PROTOCOL {
53 EFI_SECURITY_FILE_AUTHENTICATION_STATE FileAuthenticationState;
54 };
55
56
57 static UINT8 *security_policy_esl = NULL;
58 static UINTN security_policy_esl_len;
59
60 static EFI_SECURITY_FILE_AUTHENTICATION_STATE esfas = NULL;
61 static EFI_SECURITY2_FILE_AUTHENTICATION es2fa = NULL;
62
63 #ifdef __MAKEWITH_GNUEFI
64 static EFI_STATUS thunk_security_policy_authentication(
65 const EFI_SECURITY_PROTOCOL *This,
66 UINT32 AuthenticationStatus,
67 const EFI_DEVICE_PATH_PROTOCOL *DevicePath
68 )
69 __attribute__((unused));
70
71 static EFI_STATUS thunk_security2_policy_authentication(
72 const EFI_SECURITY2_PROTOCOL *This,
73 const EFI_DEVICE_PATH_PROTOCOL *DevicePath,
74 VOID *FileBuffer,
75 UINTN FileSize,
76 BOOLEAN BootPolicy
77 )
78 __attribute__((unused));
79 #endif
80
81 #ifdef __MAKEWITH_GNUEFI
82 static __attribute__((used)) EFI_STATUS
83 #else
84 static __attribute__((ms_abi)) EFI_STATUS
85 #endif
86 security2_policy_authentication (
87 const EFI_SECURITY2_PROTOCOL *This,
88 const EFI_DEVICE_PATH_PROTOCOL *DevicePath,
89 VOID *FileBuffer,
90 UINTN FileSize,
91 BOOLEAN BootPolicy
92 )
93 {
94 EFI_STATUS status;
95
96 /* Chain original security policy */
97 status = uefi_call_wrapper(es2fa, 5, This, DevicePath, FileBuffer, FileSize, BootPolicy);
98
99 /* if OK, don't bother with MOK check */
100 if (status == EFI_SUCCESS)
101 return status;
102
103 if (ShimValidate(FileBuffer, FileSize)) {
104 status = EFI_SUCCESS;
105 } else {
106 status = EFI_ACCESS_DENIED;
107 }
108
109 // status = security_policy_check_mok(FileBuffer, FileSize);
110
111 return status;
112 }
113
114 #ifdef __MAKEWITH_GNUEFI
115 static __attribute__((used)) EFI_STATUS
116 #else
117 static __attribute__((ms_abi)) EFI_STATUS
118 #endif
119 security_policy_authentication (
120 const EFI_SECURITY_PROTOCOL *This,
121 UINT32 AuthenticationStatus,
122 const EFI_DEVICE_PATH_PROTOCOL *DevicePathConst
123 )
124 {
125 EFI_STATUS status;
126 EFI_DEVICE_PATH *DevPath
127 = DuplicateDevicePath((EFI_DEVICE_PATH *)DevicePathConst),
128 *OrigDevPath = DevPath;
129 EFI_HANDLE h;
130 EFI_FILE *f;
131 VOID *FileBuffer;
132 UINTN FileSize;
133 CHAR16* DevPathStr;
134
135 /* Chain original security policy */
136 status = refit_call3_wrapper(esfas, This, AuthenticationStatus, DevicePathConst);
137
138 /* if OK avoid checking MOK: It's a bit expensive to
139 * read the whole file in again (esfas already did this) */
140 if (status == EFI_SUCCESS)
141 goto out;
142
143 status = refit_call3_wrapper(BS->LocateDevicePath, &SIMPLE_FS_PROTOCOL, &DevPath, &h);
144 if (status != EFI_SUCCESS)
145 goto out;
146
147 DevPathStr = DevicePathToStr(DevPath);
148
149 status = simple_file_open_by_handle(h, DevPathStr, &f, EFI_FILE_MODE_READ);
150 FreePool(DevPathStr);
151 if (status != EFI_SUCCESS)
152 goto out;
153
154 status = simple_file_read_all(f, &FileSize, &FileBuffer);
155 simple_file_close(f);
156 if (status != EFI_SUCCESS)
157 goto out;
158
159 if (ShimValidate(FileBuffer, FileSize)) {
160 status = EFI_SUCCESS;
161 } else {
162 status = EFI_ACCESS_DENIED;
163 }
164 FreePool(FileBuffer);
165
166 out:
167 FreePool(OrigDevPath);
168 return status;
169 }
170
171 #ifdef __MAKEWITH_GNUEFI
172 /* Nasty: ELF and EFI have different calling conventions. Here is the map for
173 * calling ELF -> EFI
174 *
175 * 1) rdi -> rcx (32 saved)
176 * 2) rsi -> rdx (32 saved)
177 * 3) rdx -> r8 ( 32 saved)
178 * 4) rcx -> r9 (32 saved)
179 * 5) r8 -> 32(%rsp) (48 saved)
180 * 6) r9 -> 40(%rsp) (48 saved)
181 * 7) pad+0(%rsp) -> 48(%rsp) (64 saved)
182 * 8) pad+8(%rsp) -> 56(%rsp) (64 saved)
183 * 9) pad+16(%rsp) -> 64(%rsp) (80 saved)
184 * 10) pad+24(%rsp) -> 72(%rsp) (80 saved)
185 * 11) pad+32(%rsp) -> 80(%rsp) (96 saved)
186
187 *
188 * So for a five argument callback, the map is ignore the first two arguments
189 * and then map (EFI -> ELF) assuming pad = 0.
190 *
191 * ARG4 -> ARG1
192 * ARG3 -> ARG2
193 * ARG5 -> ARG3
194 * ARG6 -> ARG4
195 * ARG11 -> ARG5
196 *
197 * Calling conventions also differ over volatile and preserved registers in
198 * MS: RBX, RBP, RDI, RSI, R12, R13, R14, and R15 are considered nonvolatile .
199 * In ELF: Registers %rbp, %rbx and %r12 through %r15 “belong” to the calling
200 * function and the called function is required to preserve their values.
201 *
202 * This means when accepting a function callback from MS -> ELF, we have to do
203 * separate preservation on %rdi, %rsi before swizzling the arguments and
204 * handing off to the ELF function.
205 */
206
207 asm (
208 ".type security2_policy_authentication,@function\n"
209 "thunk_security2_policy_authentication:\n\t"
210 "mov 0x28(%rsp), %r10 # ARG5\n\t"
211 "push %rdi\n\t"
212 "push %rsi\n\t"
213 "mov %r10, %rdi\n\t"
214 "subq $8, %rsp # space for storing stack pad\n\t"
215 "mov $0x08, %rax\n\t"
216 "mov $0x10, %r10\n\t"
217 "and %rsp, %rax\n\t"
218 "cmovnz %rax, %r11\n\t"
219 "cmovz %r10, %r11\n\t"
220 "subq %r11, %rsp\n\t"
221 "addq $8, %r11\n\t"
222 "mov %r11, (%rsp)\n\t"
223 "# five argument swizzle\n\t"
224 "mov %rdi, %r10\n\t"
225 "mov %rcx, %rdi\n\t"
226 "mov %rdx, %rsi\n\t"
227 "mov %r8, %rdx\n\t"
228 "mov %r9, %rcx\n\t"
229 "mov %r10, %r8\n\t"
230 "callq security2_policy_authentication@PLT\n\t"
231 "mov (%rsp), %r11\n\t"
232 "addq %r11, %rsp\n\t"
233 "pop %rsi\n\t"
234 "pop %rdi\n\t"
235 "ret\n"
236 );
237
238 asm (
239 ".type security_policy_authentication,@function\n"
240 "thunk_security_policy_authentication:\n\t"
241 "push %rdi\n\t"
242 "push %rsi\n\t"
243 "subq $8, %rsp # space for storing stack pad\n\t"
244 "mov $0x08, %rax\n\t"
245 "mov $0x10, %r10\n\t"
246 "and %rsp, %rax\n\t"
247 "cmovnz %rax, %r11\n\t"
248 "cmovz %r10, %r11\n\t"
249 "subq %r11, %rsp\n\t"
250 "addq $8, %r11\n\t"
251 "mov %r11, (%rsp)\n\t"
252 "# three argument swizzle\n\t"
253 "mov %rcx, %rdi\n\t"
254 "mov %rdx, %rsi\n\t"
255 "mov %r8, %rdx\n\t"
256 "callq security_policy_authentication@PLT\n\t"
257 "mov (%rsp), %r11\n\t"
258 "addq %r11, %rsp\n\t"
259 "pop %rsi\n\t"
260 "pop %rdi\n\t"
261 "ret\n"
262 );
263 #endif
264
265 EFI_STATUS
266 security_policy_install(void)
267 {
268 EFI_SECURITY_PROTOCOL *security_protocol;
269 EFI_SECURITY2_PROTOCOL *security2_protocol = NULL;
270 EFI_STATUS status;
271
272 if (esfas) {
273 /* Already Installed */
274 return EFI_ALREADY_STARTED;
275 }
276
277 /* Don't bother with status here. The call is allowed
278 * to fail, since SECURITY2 was introduced in PI 1.2.1
279 * If it fails, use security2_protocol == NULL as indicator */
280 uefi_call_wrapper(BS->LocateProtocol, 3, &SECURITY2_PROTOCOL_GUID, NULL, (VOID**) &security2_protocol);
281
282 status = uefi_call_wrapper(BS->LocateProtocol, 3, &SECURITY_PROTOCOL_GUID, NULL, (VOID**) &security_protocol);
283 if (status != EFI_SUCCESS)
284 /* This one is mandatory, so there's a serious problem */
285 return status;
286
287 if (security2_protocol) {
288 es2fa = security2_protocol->FileAuthentication;
289 #ifdef __MAKEWITH_GNUEFI
290 security2_protocol->FileAuthentication = thunk_security2_policy_authentication;
291 #else
292 security2_protocol->FileAuthentication = security2_policy_authentication;
293 #endif
294 }
295
296 esfas = security_protocol->FileAuthenticationState;
297 #ifdef __MAKEWITH_GNUEFI
298 security_protocol->FileAuthenticationState = thunk_security_policy_authentication;
299 #else
300 security_protocol->FileAuthenticationState = security_policy_authentication;
301 #endif
302 return EFI_SUCCESS;
303 }
304
305 EFI_STATUS
306 security_policy_uninstall(void)
307 {
308 EFI_STATUS status;
309
310 if (esfas) {
311 EFI_SECURITY_PROTOCOL *security_protocol;
312
313 status = uefi_call_wrapper(BS->LocateProtocol, 3,
314 &SECURITY_PROTOCOL_GUID, NULL,
315 (VOID**) &security_protocol);
316
317 if (status != EFI_SUCCESS)
318 return status;
319
320 security_protocol->FileAuthenticationState = esfas;
321 esfas = NULL;
322 } else {
323 /* nothing installed */
324 return EFI_NOT_STARTED;
325 }
326
327 if (es2fa) {
328 EFI_SECURITY2_PROTOCOL *security2_protocol;
329
330 status = uefi_call_wrapper(BS->LocateProtocol, 3,
331 &SECURITY2_PROTOCOL_GUID, NULL,
332 (VOID**) &security2_protocol);
333
334 if (status != EFI_SUCCESS)
335 return status;
336
337 security2_protocol->FileAuthentication = es2fa;
338 es2fa = NULL;
339 }
340
341 return EFI_SUCCESS;
342 }
343
344 void
345 security_protocol_set_hashes(unsigned char *esl, int len)
346 {
347 security_policy_esl = esl;
348 security_policy_esl_len = len;
349 }