1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 /*
3  * Port to systemd-boot
4  * Copyright © 2017 Max Resch <resch.max@gmail.com>
5  *
6  * Security Policy Handling
7  * Copyright © 2012 <James.Bottomley@HansenPartnership.com>
8  * https://github.com/mjg59/efitools
9  */
10 
11 #include <efi.h>
12 #include <efilib.h>
13 
14 #include "missing_efi.h"
15 #include "util.h"
16 #include "shim.h"
17 
18 #if defined(__x86_64__) || defined(__i386__)
19 #define __sysv_abi__ __attribute__((sysv_abi))
20 #else
21 #define __sysv_abi__
22 #endif
23 
24 struct ShimLock {
25         EFI_STATUS __sysv_abi__ (*shim_verify) (void *buffer, UINT32 size);
26 
27         /* context is actually a struct for the PE header, but it isn't needed so void is sufficient just do define the interface
28          * see shim.c/shim.h and PeHeader.h in the github shim repo */
29         EFI_STATUS __sysv_abi__ (*generate_hash) (void *data, UINT32 datasize, void *context, UINT8 *sha256hash, UINT8 *sha1hash);
30 
31         EFI_STATUS __sysv_abi__ (*read_header) (void *data, UINT32 datasize, void *context);
32 };
33 
34 #define SHIM_LOCK_GUID \
35         &(const EFI_GUID) { 0x605dab50, 0xe046, 0x4300, { 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 } }
36 
shim_loaded(void)37 BOOLEAN shim_loaded(void) {
38         struct ShimLock *shim_lock;
39 
40         return !EFI_ERROR(BS->LocateProtocol((EFI_GUID*) SHIM_LOCK_GUID, NULL, (void**) &shim_lock));
41 }
42 
shim_validate(void * data,UINT32 size)43 static BOOLEAN shim_validate(void *data, UINT32 size) {
44         struct ShimLock *shim_lock;
45 
46         if (!data)
47                 return FALSE;
48 
49         if (EFI_ERROR(BS->LocateProtocol((EFI_GUID*) SHIM_LOCK_GUID, NULL, (void**) &shim_lock)))
50                 return FALSE;
51 
52         if (!shim_lock)
53                 return FALSE;
54 
55         return !EFI_ERROR(shim_lock->shim_verify(data, size));
56 }
57 
58 /* Handle to the original authenticator for security1 protocol */
59 static EFI_SECURITY_FILE_AUTHENTICATION_STATE esfas = NULL;
60 
61 /* Handle to the original authenticator for security2 protocol */
62 static EFI_SECURITY2_FILE_AUTHENTICATION es2fa = NULL;
63 
64 /*
65  * Perform shim/MOK and Secure Boot authentication on a binary that's already been
66  * loaded into memory. This function does the platform SB authentication first
67  * but preserves its return value in case of its failure, so that it can be
68  * returned in case of a shim/MOK authentication failure. This is done because
69  * the SB failure code seems to vary from one implementation to another, and I
70  * don't want to interfere with that at this time.
71  */
security2_policy_authentication(const EFI_SECURITY2_PROTOCOL * this,const EFI_DEVICE_PATH_PROTOCOL * device_path,void * file_buffer,UINTN file_size,BOOLEAN boot_policy)72 static EFIAPI EFI_STATUS security2_policy_authentication (const EFI_SECURITY2_PROTOCOL *this,
73                                                           const EFI_DEVICE_PATH_PROTOCOL *device_path,
74                                                           void *file_buffer, UINTN file_size, BOOLEAN boot_policy) {
75         EFI_STATUS status;
76 
77         assert(this);
78         /* device_path and file_buffer may be NULL */
79 
80         /* Chain original security policy */
81         status = es2fa(this, device_path, file_buffer, file_size, boot_policy);
82 
83         /* if OK, don't bother with MOK check */
84         if (!EFI_ERROR(status))
85                 return status;
86 
87         if (shim_validate(file_buffer, file_size))
88                 return EFI_SUCCESS;
89 
90         return status;
91 }
92 
93 /*
94  * Perform both shim/MOK and platform Secure Boot authentication. This function loads
95  * the file and performs shim/MOK authentication first simply to avoid double loads
96  * of Linux kernels, which are much more likely to be shim/MOK-signed than platform-signed,
97  * since kernels are big and can take several seconds to load on some computers and
98  * filesystems. This also has the effect of returning whatever the platform code is for
99  * authentication failure, be it EFI_ACCESS_DENIED, EFI_SECURITY_VIOLATION, or something
100  * else. (This seems to vary between implementations.)
101  */
security_policy_authentication(const EFI_SECURITY_PROTOCOL * this,UINT32 authentication_status,const EFI_DEVICE_PATH_PROTOCOL * device_path_const)102 static EFIAPI EFI_STATUS security_policy_authentication (const EFI_SECURITY_PROTOCOL *this, UINT32 authentication_status,
103                                                          const EFI_DEVICE_PATH_PROTOCOL *device_path_const) {
104         EFI_STATUS status;
105         _cleanup_freepool_ EFI_DEVICE_PATH *dev_path = NULL;
106         _cleanup_freepool_ CHAR16 *dev_path_str = NULL;
107         EFI_HANDLE h;
108         _cleanup_freepool_ CHAR8 *file_buffer = NULL;
109         UINTN file_size;
110 
111         assert(this);
112 
113         if (!device_path_const)
114                 return EFI_INVALID_PARAMETER;
115 
116         dev_path = DuplicateDevicePath((EFI_DEVICE_PATH*) device_path_const);
117         if (!dev_path)
118                 return EFI_OUT_OF_RESOURCES;
119 
120         EFI_DEVICE_PATH *dp = dev_path;
121         status = BS->LocateDevicePath(&FileSystemProtocol, &dp, &h);
122         if (EFI_ERROR(status))
123                 return status;
124 
125         _cleanup_(file_closep) EFI_FILE *root = LibOpenRoot(h);
126         if (!root)
127                 return EFI_NOT_FOUND;
128 
129         dev_path_str = DevicePathToStr(dp);
130         if (!dev_path_str)
131                 return EFI_OUT_OF_RESOURCES;
132 
133         status = file_read(root, dev_path_str, 0, 0, &file_buffer, &file_size);
134         if (EFI_ERROR(status))
135                 return status;
136 
137         if (shim_validate(file_buffer, file_size))
138                 return EFI_SUCCESS;
139 
140         /* Try using the platform's native policy.... */
141         return esfas(this, authentication_status, device_path_const);
142 }
143 
security_policy_install(void)144 EFI_STATUS security_policy_install(void) {
145         EFI_SECURITY_PROTOCOL *security_protocol;
146         EFI_SECURITY2_PROTOCOL *security2_protocol = NULL;
147         EFI_STATUS status;
148 
149         /* Already Installed */
150         if (esfas)
151                 return EFI_ALREADY_STARTED;
152 
153         /*
154          * Don't bother with status here. The call is allowed
155          * to fail, since SECURITY2 was introduced in PI 1.2.1.
156          * Use security2_protocol == NULL as indicator.
157          */
158         BS->LocateProtocol((EFI_GUID*) SECURITY_PROTOCOL2_GUID, NULL, (void**) &security2_protocol);
159 
160         status = BS->LocateProtocol((EFI_GUID*) SECURITY_PROTOCOL_GUID, NULL, (void**) &security_protocol);
161          /* This one is mandatory, so there's a serious problem */
162         if (EFI_ERROR(status))
163                 return status;
164 
165         esfas = security_protocol->FileAuthenticationState;
166         security_protocol->FileAuthenticationState = security_policy_authentication;
167 
168         if (security2_protocol) {
169                 es2fa = security2_protocol->FileAuthentication;
170                 security2_protocol->FileAuthentication = security2_policy_authentication;
171         }
172 
173         return EFI_SUCCESS;
174 }
175