iPXE
efi_shim.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2022 Michael Brown <mbrown@fensystems.co.uk>.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25FILE_SECBOOT ( PERMITTED );
26
27#include <string.h>
28#include <stdlib.h>
29#include <errno.h>
30#include <ipxe/image.h>
31#include <ipxe/efi/efi.h>
33#include <ipxe/efi/efi_shim.h>
36
37/** @file
38 *
39 * UEFI shim special handling
40 *
41 */
42
43FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
44FILE_SECBOOT ( PERMITTED );
45
46/**
47 * Require use of a third party loader binary
48 *
49 * The UEFI shim is gradually becoming less capable of directly
50 * executing a Linux kernel image, due to an ever increasing list of
51 * assumptions that it will only ever be used in conjunction with a
52 * second stage loader binary such as GRUB.
53 *
54 * For example: shim will erroneously complain if the image that it
55 * loads and executes does not in turn call in to the "shim lock
56 * protocol" to verify a separate newly loaded binary before calling
57 * ExitBootServices(), even if no such separate binary is used or
58 * required.
59 *
60 * Experience shows that there is unfortunately no point in trying to
61 * get a fix for this upstreamed into shim. We therefore default to
62 * reducing the Secure Boot attack surface by removing, where
63 * possible, this spurious requirement for the use of an additional
64 * second stage loader.
65 *
66 * This option may be used to require the use of an additional second
67 * stage loader binary, in case this behaviour is ever desirable.
68 */
70
71/**
72 * Allow use of PXE base code protocol
73 *
74 * We provide shim with access to all of the relevant downloaded files
75 * via our EFI_SIMPLE_FILE_SYSTEM_PROTOCOL interface. However, shim
76 * will instead try to redownload the files via TFTP since it prefers
77 * to use the EFI_PXE_BASE_CODE_PROTOCOL installed on the same handle.
78 *
79 * Experience shows that there is unfortunately no point in trying to
80 * get a fix for this upstreamed into shim. We therefore default to
81 * working around this undesirable behaviour by stopping the PXE base
82 * code protocol before invoking shim.
83 *
84 * This option may be used to allow shim to use the PXE base code
85 * protocol, in case this behaviour is ever desirable.
86 */
88
89/**
90 * Allow SBAT variable access
91 *
92 * The UEFI shim implements a fairly nicely designed revocation
93 * mechanism designed around the concept of security generations.
94 * Unfortunately nobody in the shim community has thus far added the
95 * relevant metadata to the Linux kernel, with the result that current
96 * versions of shim are incapable of booting current versions of the
97 * Linux kernel.
98 *
99 * Experience shows that there is unfortunately no point in trying to
100 * get a fix for this upstreamed into shim. We therefore default to
101 * working around this undesirable behaviour by patching data read
102 * from the "SbatLevel" variable used to hold SBAT configuration.
103 *
104 * This option may be used to allow shim unpatched access to the
105 * "SbatLevel" variable, in case this behaviour is ever desirable.
106 */
108
109/** UEFI shim image */
110struct image_tag efi_shim __image_tag = {
111 .name = "SHIM",
112};
113
114/** Original GetMemoryMap() function */
116
117/** Original SetVariable() function */
119
120/** Original GetVariable() function */
122
123/** Verify read from SbatLevel variable */
125
126/**
127 * Check if variable is SbatLevel
128 *
129 * @v name Variable name
130 * @v guid Variable namespace GUID
131 * @ret is_sbatlevel Variable is SbatLevel
132 */
133static int efi_shim_is_sbatlevel ( const CHAR16 *name, const EFI_GUID *guid ) {
134 static CHAR16 sbatlevel[] = L"SbatLevel";
136
137 return ( ( memcmp ( name, sbatlevel, sizeof ( sbatlevel ) ) == 0 ) &&
138 ( memcmp ( guid, shimlock, sizeof ( *shimlock ) ) == 0 ) );
139}
140
141/**
142 * Unlock UEFI shim
143 *
144 */
145static void efi_shim_unlock ( void ) {
146 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
147 uint8_t empty[0];
148 union {
150 void *interface;
151 } u;
152 EFI_STATUS efirc;
153
154 /* Locate shim lock protocol */
155 if ( ( efirc = bs->LocateProtocol ( &efi_shim_lock_protocol_guid,
156 NULL, &u.interface ) ) == 0 ) {
157 u.lock->Verify ( empty, sizeof ( empty ) );
158 DBGC ( &efi_shim, "SHIM unlocked via %p\n", u.lock );
159 }
160}
161
162/**
163 * Wrap SetVariable()
164 *
165 * @v name Variable name
166 * @v guid Variable namespace GUID
167 * @v attrs Attributes
168 * @v len Buffer size
169 * @v data Data buffer
170 * @ret efirc EFI status code
171 */
172static EFI_STATUS EFIAPI
174 UINTN len, VOID *data ) {
175 EFI_STATUS efirc;
176
177 /* Call original SetVariable() */
178 efirc = efi_shim_orig_set_variable ( name, guid, attrs, len, data );
179
180 /* Allow verification of SbatLevel variable content */
181 if ( efi_shim_is_sbatlevel ( name, guid ) && ( efirc == 0 ) ) {
182 DBGC ( &efi_shim, "SHIM detected write to %ls:\n", name );
183 DBGC_HDA ( &efi_shim, 0, data, len );
185 }
186
187 return efirc;
188}
189
190/**
191 * Wrap GetVariable()
192 *
193 * @v name Variable name
194 * @v guid Variable namespace GUID
195 * @v attrs Attributes to fill in
196 * @v len Buffer size
197 * @v data Data buffer
198 * @ret efirc EFI status code
199 */
200static EFI_STATUS EFIAPI
202 UINTN *len, VOID *data ) {
203 char *value = data;
204 EFI_STATUS efirc;
205
206 /* Call original GetVariable() */
207 efirc = efi_shim_orig_get_variable ( name, guid, attrs, len, data );
208
209 /* Patch SbatLevel variable if applicable */
210 if ( efi_shim_is_sbatlevel ( name, guid ) && data && ( efirc == 0 ) ) {
211 if ( efi_shim_allow_sbat ) {
212 DBGC ( &efi_shim, "SHIM allowing read from %ls:\n",
213 name );
214 } else if ( efi_shim_sbatlevel_verify ) {
215 DBGC ( &efi_shim, "SHIM allowing one read from %ls:\n",
216 name );
218 } else {
219 DBGC ( &efi_shim, "SHIM patching read from %ls:\n",
220 name );
221 value[0] = '\0';
222 }
223 DBGC_HDA ( &efi_shim, 0, data, *len );
224 }
225
226 return efirc;
227}
228
229/**
230 * Wrap GetMemoryMap()
231 *
232 * @v len Memory map size
233 * @v map Memory map
234 * @v key Memory map key
235 * @v desclen Descriptor size
236 * @v descver Descriptor version
237 * @ret efirc EFI status code
238 */
241 UINTN *key, UINTN *desclen,
242 UINT32 *descver ) {
243 EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
244
245 /* Unlock shim */
248
249 /* Uninstall runtime services wrappers, if still installed */
250 if ( rs->SetVariable == efi_shim_set_variable ) {
252 DBGC ( &efi_shim, "SHIM uninstalled SetVariable() wrapper\n" );
253 } else if ( rs->SetVariable != efi_shim_orig_set_variable ) {
254 DBGC ( &efi_shim, "SHIM could not uninstall SetVariable() "
255 "wrapper!\n" );
256 }
257 if ( rs->GetVariable == efi_shim_get_variable ) {
259 DBGC ( &efi_shim, "SHIM uninstalled GetVariable() wrapper\n" );
260 } else if ( rs->GetVariable != efi_shim_orig_get_variable ) {
261 DBGC ( &efi_shim, "SHIM could not uninstall GetVariable() "
262 "wrapper!\n" );
263 }
264
265 /* Hand off to original GetMemoryMap() */
266 return efi_shim_orig_get_memory_map ( len, map, key, desclen,
267 descver );
268}
269
270/**
271 * Inhibit use of PXE base code
272 *
273 * @v handle EFI handle
274 * @ret rc Return status code
275 */
278 EFI_STATUS efirc;
279 int rc;
280
281 /* Locate PXE base code */
283 &pxe ) ) != 0 ) {
284 DBGC ( &efi_shim, "SHIM could not open PXE base code: %s\n",
285 strerror ( rc ) );
286 return rc;
287 }
288
289 /* Stop PXE base code */
290 if ( ( efirc = pxe->Stop ( pxe ) ) != 0 ) {
291 rc = -EEFI ( efirc );
292 DBGC ( &efi_shim, "SHIM could not stop PXE base code: %s\n",
293 strerror ( rc ) );
294 return rc;
295 }
296
297 DBGC ( &efi_shim, "SHIM stopped PXE base code\n" );
298 return 0;
299}
300
301/**
302 * Update command line
303 *
304 * @v shim Shim image
305 * @v cmdline Command line to update
306 * @ret rc Return status code
307 */
308static int efi_shim_cmdline ( struct image *shim, wchar_t **cmdline ) {
309 wchar_t *shimcmdline;
310 int len;
311 int rc;
312
313 /* Construct new command line */
314 len = ( shim->cmdline ?
315 efi_asprintf ( &shimcmdline, "%s %s", shim->name,
316 shim->cmdline ) :
317 efi_asprintf ( &shimcmdline, "%s %ls", shim->name,
318 *cmdline ) );
319 if ( len < 0 ) {
320 rc = len;
321 DBGC ( &efi_shim, "SHIM could not construct command line: "
322 "%s\n", strerror ( rc ) );
323 return rc;
324 }
325
326 /* Replace command line */
327 free ( *cmdline );
328 *cmdline = shimcmdline;
329
330 return 0;
331}
332
333/**
334 * Install UEFI shim special handling
335 *
336 * @v shim Shim image
337 * @v handle EFI device handle
338 * @v cmdline Command line to update
339 * @ret rc Return status code
340 */
342 wchar_t **cmdline ) {
343 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
344 EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
345 int rc;
346
347 /* Stop PXE base code */
348 if ( ( ! efi_shim_allow_pxe ) &&
349 ( ( rc = efi_shim_inhibit_pxe ( handle ) ) != 0 ) ) {
350 return rc;
351 }
352
353 /* Update command line */
354 if ( ( rc = efi_shim_cmdline ( shim, cmdline ) ) != 0 )
355 return rc;
356
357 /* Record original boot and runtime services functions */
361
362 /* Wrap relevant boot and runtime services functions */
366 DBGC ( &efi_shim, "SHIM installed wrappers\n" );
367
368 return 0;
369}
370
371/**
372 * Uninstall UEFI shim special handling
373 *
374 */
375void efi_shim_uninstall ( void ) {
376 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
377 EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
378
379 /* Restore original boot and runtime services functions */
383 DBGC ( &efi_shim, "SHIM uninstalled wrappers\n" );
384}
UINT64 UINTN
Unsigned value of native width.
unsigned short CHAR16
2-byte Character.
#define EFIAPI
unsigned int UINT32
4-byte unsigned value.
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
#define VOID
Undeclared type.
Definition Base.h:272
union @162305117151260234136356364136041353210355154177 key
Sense key.
Definition scsi.h:3
EFI PXE Base Code Protocol definitions, which is used to access PXE-compatible devices for network ac...
struct _EFI_PXE_BASE_CODE_PROTOCOL EFI_PXE_BASE_CODE_PROTOCOL
Definition PxeBaseCode.h:30
EFI "shim lock" protocol.
struct _EFI_SHIM_LOCK_PROTOCOL EFI_SHIM_LOCK_PROTOCOL
RETURN_STATUS EFI_STATUS
Function return status for EFI API.
GUID EFI_GUID
128-bit buffer containing a unique identifier value.
EFI_STATUS(EFIAPI * EFI_GET_VARIABLE)(IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, OUT UINT32 *Attributes OPTIONAL, IN OUT UINTN *DataSize, OUT VOID *Data OPTIONAL)
Returns the value of a variable.
Definition UefiSpec.h:709
EFI_STATUS(EFIAPI * EFI_GET_MEMORY_MAP)(IN OUT UINTN *MemoryMapSize, OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, OUT UINTN *MapKey, OUT UINTN *DescriptorSize, OUT UINT32 *DescriptorVersion)
Returns the current memory map.
Definition UefiSpec.h:269
EFI_STATUS(EFIAPI * EFI_SET_VARIABLE)(IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, IN UINT32 Attributes, IN UINTN DataSize, IN VOID *Data)
Sets the value of a variable.
Definition UefiSpec.h:794
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
pseudo_bit_t value[0x00020]
Definition arbel.h:2
unsigned char uint8_t
Definition stdint.h:10
const char * name
Definition ath9k_hw.c:1986
union @104331263140136355135267063077374276003064103115 u
ring len
Length.
Definition dwmac.h:226
uint64_t guid
GUID.
Definition edd.h:1
EFI_GUID efi_shim_lock_protocol_guid
Shim lock protocol GUID.
Definition efi_guid.c:333
EFI_GUID efi_pxe_base_code_protocol_guid
PXE base code protocol GUID.
Definition efi_guid.c:321
static int efi_shim_sbatlevel_verify
Verify read from SbatLevel variable.
Definition efi_shim.c:124
static void efi_shim_unlock(void)
Unlock UEFI shim.
Definition efi_shim.c:145
static int efi_shim_cmdline(struct image *shim, wchar_t **cmdline)
Update command line.
Definition efi_shim.c:308
static EFI_SET_VARIABLE efi_shim_orig_set_variable
Original SetVariable() function.
Definition efi_shim.c:118
int efi_shim_allow_pxe
Allow use of PXE base code protocol.
Definition efi_shim.c:87
static EFI_GET_MEMORY_MAP efi_shim_orig_get_memory_map
Original GetMemoryMap() function.
Definition efi_shim.c:115
static EFI_STATUS EFIAPI efi_shim_get_variable(CHAR16 *name, EFI_GUID *guid, UINT32 *attrs, UINTN *len, VOID *data)
Wrap GetVariable()
Definition efi_shim.c:201
int efi_shim_require_loader
Require use of a third party loader binary.
Definition efi_shim.c:69
void efi_shim_uninstall(void)
Uninstall UEFI shim special handling.
Definition efi_shim.c:375
int efi_shim_allow_sbat
Allow SBAT variable access.
Definition efi_shim.c:107
int efi_shim_install(struct image *shim, EFI_HANDLE handle, wchar_t **cmdline)
Install UEFI shim special handling.
Definition efi_shim.c:341
static int efi_shim_inhibit_pxe(EFI_HANDLE handle)
Inhibit use of PXE base code.
Definition efi_shim.c:276
static EFIAPI EFI_STATUS efi_shim_get_memory_map(UINTN *len, EFI_MEMORY_DESCRIPTOR *map, UINTN *key, UINTN *desclen, UINT32 *descver)
Wrap GetMemoryMap()
Definition efi_shim.c:239
static EFI_STATUS EFIAPI efi_shim_set_variable(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN len, VOID *data)
Wrap SetVariable()
Definition efi_shim.c:173
static EFI_GET_VARIABLE efi_shim_orig_get_variable
Original GetVariable() function.
Definition efi_shim.c:121
static int efi_shim_is_sbatlevel(const CHAR16 *name, const EFI_GUID *guid)
Check if variable is SbatLevel.
Definition efi_shim.c:133
UEFI shim special handling.
int efi_asprintf(wchar_t **wstrp, const char *fmt,...)
Write a formatted string to newly allocated memory.
EFI strings.
uint8_t data[48]
Additional event data.
Definition ena.h:11
Error codes.
#define DBGC(...)
Definition compiler.h:505
#define DBGC_HDA(...)
Definition compiler.h:506
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
Executable images.
#define __image_tag
An image tag.
Definition image.h:184
EFI API.
#define efi_open(handle, protocol, interface)
Open protocol for ephemeral use.
Definition efi.h:444
#define EFI_HANDLE
Definition efi.h:53
#define EEFI(efirc)
Convert an EFI status code to an iPXE status code.
Definition efi.h:175
EFI_SYSTEM_TABLE * efi_systab
uint16_t handle
Handle.
Definition smbios.h:5
String functions.
static __always_inline int struct dma_mapping * map
Definition dma.h:184
uint32_t cmdline
Definition multiboot.h:4
static void(* free)(struct refcnt *refcnt))
Definition refcnt.h:55
int shim(struct image *image, int require_loader, int allow_pxe, int allow_sbat)
Set shim image.
Definition shimmgmt.c:46
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition string.c:115
EFI Boot Services Table.
Definition UefiSpec.h:1931
EFI_LOCATE_PROTOCOL LocateProtocol
Definition UefiSpec.h:2009
EFI_GET_MEMORY_MAP GetMemoryMap
Definition UefiSpec.h:1948
Definition of an EFI memory descriptor.
Definition UefiSpec.h:156
EFI Runtime Services Table.
Definition UefiSpec.h:1880
EFI_SET_VARIABLE SetVariable
Definition UefiSpec.h:1905
EFI_GET_VARIABLE GetVariable
Definition UefiSpec.h:1903
EFI_PXE_BASE_CODE_STOP Stop
An image tag.
Definition image.h:173
An executable image.
Definition image.h:24
An object interface.
Definition interface.h:125