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