]> code.delx.au - refind/blob - mok/security_policy.c
Shim/MOK fine-tuning & support for building drivers with GNU-EFI
[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 <global.h>
10
11 #include "guid.h"
12 #include "../refind/lib.h"
13 #include "simple_file.h"
14 #include "../include/refit_call_wrapper.h"
15 #include "mok.h"
16
17 #include <security_policy.h>
18
19 /*
20 * See the UEFI Platform Initialization manual (Vol2: DXE) for this
21 */
22 struct _EFI_SECURITY2_PROTOCOL;
23 struct _EFI_SECURITY_PROTOCOL;
24 struct _EFI_DEVICE_PATH_PROTOCOL;
25 typedef struct _EFI_SECURITY2_PROTOCOL EFI_SECURITY2_PROTOCOL;
26 typedef struct _EFI_SECURITY_PROTOCOL EFI_SECURITY_PROTOCOL;
27 #ifdef __MAKEWITH_GNUEFI
28 typedef struct _EFI_DEVICE_PATH_PROTOCOL EFI_DEVICE_PATH_PROTOCOL;
29 #endif
30
31 #if defined(EFIX64)
32 #define MSABI __attribute__((ms_abi))
33 #else
34 #define MSABI
35 #endif
36
37 typedef EFI_STATUS (MSABI *EFI_SECURITY_FILE_AUTHENTICATION_STATE) (
38 const EFI_SECURITY_PROTOCOL *This,
39 UINT32 AuthenticationStatus,
40 const EFI_DEVICE_PATH_PROTOCOL *File
41 );
42 typedef EFI_STATUS (MSABI *EFI_SECURITY2_FILE_AUTHENTICATION) (
43 const EFI_SECURITY2_PROTOCOL *This,
44 const EFI_DEVICE_PATH_PROTOCOL *DevicePath,
45 VOID *FileBuffer,
46 UINTN FileSize,
47 BOOLEAN BootPolicy
48 );
49
50 struct _EFI_SECURITY2_PROTOCOL {
51 EFI_SECURITY2_FILE_AUTHENTICATION FileAuthentication;
52 };
53
54 struct _EFI_SECURITY_PROTOCOL {
55 EFI_SECURITY_FILE_AUTHENTICATION_STATE FileAuthenticationState;
56 };
57
58
59 static EFI_SECURITY_FILE_AUTHENTICATION_STATE esfas = NULL;
60 static EFI_SECURITY2_FILE_AUTHENTICATION es2fa = NULL;
61
62 // Perform shim/MOK and Secure Boot authentication on a binary that's already been
63 // loaded into memory. This function does the platform SB authentication first
64 // but preserves its return value in case of its failure, so that it can be
65 // returned in case of a shim/MOK authentication failure. This is done because
66 // the SB failure code seems to vary from one implementation to another, and I
67 // don't want to interfere with that at this time.
68 static MSABI EFI_STATUS
69 security2_policy_authentication (
70 const EFI_SECURITY2_PROTOCOL *This,
71 const EFI_DEVICE_PATH_PROTOCOL *DevicePath,
72 VOID *FileBuffer,
73 UINTN FileSize,
74 BOOLEAN BootPolicy
75 )
76 {
77 EFI_STATUS Status;
78
79 /* Chain original security policy */
80 Status = uefi_call_wrapper(es2fa, 5, This, DevicePath, FileBuffer, FileSize, BootPolicy);
81
82 /* if OK, don't bother with MOK check */
83 if (Status == EFI_SUCCESS)
84 return Status;
85
86 if (ShimValidate(FileBuffer, FileSize)) {
87 return EFI_SUCCESS;
88 } else {
89 return Status;
90 }
91 } // EFI_STATUS security2_policy_authentication()
92
93 // Perform both shim/MOK and platform Secure Boot authentication. This function loads
94 // the file and performs shim/MOK authentication first simply to avoid double loads
95 // of Linux kernels, which are much more likely to be shim/MOK-signed than platform-signed,
96 // since kernels are big and can take several seconds to load on some computers and
97 // filesystems. This also has the effect of returning whatever the platform code is for
98 // authentication failure, be it EFI_ACCESS_DENIED, EFI_SECURITY_VIOLATION, or something
99 // else. (This seems to vary between implementations.)
100 static MSABI EFI_STATUS
101 security_policy_authentication (
102 const EFI_SECURITY_PROTOCOL *This,
103 UINT32 AuthenticationStatus,
104 const EFI_DEVICE_PATH_PROTOCOL *DevicePathConst
105 )
106 {
107 EFI_STATUS Status;
108 EFI_DEVICE_PATH *DevPath, *OrigDevPath;
109 EFI_HANDLE h;
110 EFI_FILE *f;
111 VOID *FileBuffer;
112 UINTN FileSize;
113 CHAR16 *DevPathStr;
114
115 if (DevicePathConst == NULL) {
116 return EFI_INVALID_PARAMETER;
117 } else {
118 DevPath = OrigDevPath = DuplicateDevicePath((EFI_DEVICE_PATH *)DevicePathConst);
119 }
120
121 Status = refit_call3_wrapper(BS->LocateDevicePath, &SIMPLE_FS_PROTOCOL, &DevPath, &h);
122 if (Status != EFI_SUCCESS)
123 goto out;
124
125 DevPathStr = DevicePathToStr(DevPath);
126
127 Status = simple_file_open_by_handle(h, DevPathStr, &f, EFI_FILE_MODE_READ);
128 MyFreePool(DevPathStr);
129 if (Status != EFI_SUCCESS)
130 goto out;
131
132 Status = simple_file_read_all(f, &FileSize, &FileBuffer);
133 simple_file_close(f);
134 if (Status != EFI_SUCCESS)
135 goto out;
136
137 if (ShimValidate(FileBuffer, FileSize)) {
138 Status = EFI_SUCCESS;
139 } else {
140 // Try using the platform's native policy....
141 Status = uefi_call_wrapper(esfas, 3, This, AuthenticationStatus, DevicePathConst);
142 }
143 FreePool(FileBuffer);
144
145 out:
146 MyFreePool(OrigDevPath);
147 return Status;
148 } // EFI_STATUS security_policy_authentication()
149
150 EFI_STATUS
151 security_policy_install(void)
152 {
153 EFI_SECURITY_PROTOCOL *security_protocol;
154 EFI_SECURITY2_PROTOCOL *security2_protocol = NULL;
155 EFI_STATUS status;
156
157 if (esfas) {
158 /* Already Installed */
159 return EFI_ALREADY_STARTED;
160 }
161
162 /* Don't bother with status here. The call is allowed
163 * to fail, since SECURITY2 was introduced in PI 1.2.1
164 * If it fails, use security2_protocol == NULL as indicator */
165 uefi_call_wrapper(BS->LocateProtocol, 3, &SECURITY2_PROTOCOL_GUID, NULL, (VOID**) &security2_protocol);
166
167 status = uefi_call_wrapper(BS->LocateProtocol, 3, &SECURITY_PROTOCOL_GUID, NULL, (VOID**) &security_protocol);
168 if (status != EFI_SUCCESS)
169 /* This one is mandatory, so there's a serious problem */
170 return status;
171
172 if (security2_protocol) {
173 es2fa = security2_protocol->FileAuthentication;
174 security2_protocol->FileAuthentication = security2_policy_authentication;
175 }
176
177 esfas = security_protocol->FileAuthenticationState;
178 security_protocol->FileAuthenticationState = security_policy_authentication;
179 return EFI_SUCCESS;
180 }
181
182 EFI_STATUS
183 security_policy_uninstall(void)
184 {
185 EFI_STATUS status;
186
187 if (esfas) {
188 EFI_SECURITY_PROTOCOL *security_protocol;
189
190 status = uefi_call_wrapper(BS->LocateProtocol, 3, &SECURITY_PROTOCOL_GUID, NULL, (VOID**) &security_protocol);
191
192 if (status != EFI_SUCCESS)
193 return status;
194
195 security_protocol->FileAuthenticationState = esfas;
196 esfas = NULL;
197 } else {
198 /* nothing installed */
199 return EFI_NOT_STARTED;
200 }
201
202 if (es2fa) {
203 EFI_SECURITY2_PROTOCOL *security2_protocol;
204
205 status = uefi_call_wrapper(BS->LocateProtocol, 3, &SECURITY2_PROTOCOL_GUID, NULL, (VOID**) &security2_protocol);
206
207 if (status != EFI_SUCCESS)
208 return status;
209
210 security2_protocol->FileAuthentication = es2fa;
211 es2fa = NULL;
212 }
213
214 return EFI_SUCCESS;
215 }