iPXE
efi_shim.c File Reference

UEFI shim special handling. More...

#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <ipxe/image.h>
#include <ipxe/efi/efi.h>
#include <ipxe/efi/efi_strings.h>
#include <ipxe/efi/efi_shim.h>
#include <ipxe/efi/Protocol/PxeBaseCode.h>
#include <ipxe/efi/Protocol/ShimLock.h>

Go to the source code of this file.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
 FILE_SECBOOT (PERMITTED)
static int efi_shim_is_sbatlevel (const CHAR16 *name, const EFI_GUID *guid)
 Check if variable is SbatLevel.
static void efi_shim_unlock (void)
 Unlock UEFI shim.
static EFI_STATUS EFIAPI efi_shim_set_variable (CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN len, VOID *data)
 Wrap SetVariable()
static EFI_STATUS EFIAPI efi_shim_get_variable (CHAR16 *name, EFI_GUID *guid, UINT32 *attrs, UINTN *len, VOID *data)
 Wrap GetVariable()
static EFIAPI EFI_STATUS efi_shim_get_memory_map (UINTN *len, EFI_MEMORY_DESCRIPTOR *map, UINTN *key, UINTN *desclen, UINT32 *descver)
 Wrap GetMemoryMap()
static int efi_shim_inhibit_pxe (EFI_HANDLE handle)
 Inhibit use of PXE base code.
static int efi_shim_cmdline (struct image *shim, wchar_t **cmdline)
 Update command line.
int efi_shim_install (struct image *shim, EFI_HANDLE handle, wchar_t **cmdline)
 Install UEFI shim special handling.
void efi_shim_uninstall (void)
 Uninstall UEFI shim special handling.

Variables

int efi_shim_require_loader = 0
 Require use of a third party loader binary.
int efi_shim_allow_pxe = 0
 Allow use of PXE base code protocol.
int efi_shim_allow_sbat = 0
 Allow SBAT variable access.
struct image_tag efi_shim __image_tag
 UEFI shim image.
static EFI_GET_MEMORY_MAP efi_shim_orig_get_memory_map
 Original GetMemoryMap() function.
static EFI_SET_VARIABLE efi_shim_orig_set_variable
 Original SetVariable() function.
static EFI_GET_VARIABLE efi_shim_orig_get_variable
 Original GetVariable() function.
static int efi_shim_sbatlevel_verify
 Verify read from SbatLevel variable.

Detailed Description

UEFI shim special handling.

Definition in file efi_shim.c.

Function Documentation

◆ FILE_LICENCE()

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )

◆ FILE_SECBOOT()

FILE_SECBOOT ( PERMITTED )

◆ efi_shim_is_sbatlevel()

int efi_shim_is_sbatlevel ( const CHAR16 * name,
const EFI_GUID * guid )
static

Check if variable is SbatLevel.

Parameters
nameVariable name
guidVariable namespace GUID
Return values
is_sbatlevelVariable is SbatLevel

Definition at line 133 of file efi_shim.c.

133 {
134 static CHAR16 sbatlevel[] = L"SbatLevel";
136
137 return ( ( memcmp ( name, sbatlevel, sizeof ( sbatlevel ) ) == 0 ) &&
138 ( memcmp ( guid, shimlock, sizeof ( *shimlock ) ) == 0 ) );
139}
unsigned short CHAR16
2-byte Character.
GUID EFI_GUID
128-bit buffer containing a unique identifier value.
const char * name
Definition ath9k_hw.c:1986
uint64_t guid
GUID.
Definition edd.h:1
EFI_GUID efi_shim_lock_protocol_guid
Shim lock protocol GUID.
Definition efi_guid.c:333
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition string.c:115

References efi_shim_lock_protocol_guid, guid, memcmp(), and name.

Referenced by efi_shim_get_variable(), and efi_shim_set_variable().

◆ efi_shim_unlock()

void efi_shim_unlock ( void )
static

Unlock UEFI shim.

Definition at line 145 of file efi_shim.c.

145 {
146 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
149 uint8_t empty[0];
150 EFI_HANDLE *handles;
151 UINTN num_handles;
152 unsigned int i;
153 EFI_STATUS efirc;
154 int rc;
155
156 /* Locate shim lock protocol(s) */
157 if ( ( efirc = bs->LocateHandleBuffer ( ByProtocol, protocol,
158 NULL, &num_handles,
159 &handles ) ) != 0 ) {
160 rc = -EEFI ( efirc );
161 DBGC ( &efi_shim, "SHIM could not locate shim locks: %s\n",
162 strerror ( rc ) );
163 goto err_locate;
164 }
165
166 /* Unlock each shim lock */
167 for ( i = 0 ; i < num_handles ; i++ ) {
168
169 /* Open shim lock protocol */
170 if ( ( rc = efi_open ( handles[i], protocol, &lock ) ) != 0 ) {
171 DBGC ( &efi_shim, "SHIM could not open lock %d (%p): "
172 "%s\n", i, handles[i], strerror ( rc ) );
173 continue;
174 }
175
176 /* Unlock shim lock */
177 lock->Verify ( empty, sizeof ( empty ) );
178 DBGC ( &efi_shim, "SHIM unlocked lock %d (%p) via %p\n",
179 i, handles[i], lock );
180 }
181
182 bs->FreePool ( handles );
183 err_locate:
184 return;
185}
UINT64 UINTN
Unsigned value of native width.
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
struct _EFI_SHIM_LOCK_PROTOCOL EFI_SHIM_LOCK_PROTOCOL
RETURN_STATUS EFI_STATUS
Function return status for EFI API.
@ ByProtocol
Retrieve the set of handles from the handle database that support a specified protocol.
Definition UefiSpec.h:1531
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
unsigned char uint8_t
Definition stdint.h:10
#define DBGC(...)
Definition compiler.h:505
#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 protocol
Protocol ID.
Definition stp.h:7
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
EFI Boot Services Table.
Definition UefiSpec.h:1931
EFI_FREE_POOL FreePool
Definition UefiSpec.h:1950
EFI_LOCATE_HANDLE_BUFFER LocateHandleBuffer
Definition UefiSpec.h:2008
EFI_SHIM_LOCK_VERIFY Verify
Definition ShimLock.h:27

References ByProtocol, DBGC, EEFI, EFI_HANDLE, efi_open, efi_shim_lock_protocol_guid, efi_systab, EFI_BOOT_SERVICES::FreePool, EFI_BOOT_SERVICES::LocateHandleBuffer, NULL, protocol, rc, strerror(), and _EFI_SHIM_LOCK_PROTOCOL::Verify.

Referenced by efi_shim_get_memory_map().

◆ efi_shim_set_variable()

EFI_STATUS EFIAPI efi_shim_set_variable ( CHAR16 * name,
EFI_GUID * guid,
UINT32 attrs,
UINTN len,
VOID * data )
static

Wrap SetVariable()

Parameters
nameVariable name
guidVariable namespace GUID
attrsAttributes
lenBuffer size
dataData buffer
Return values
efircEFI status code

Definition at line 198 of file efi_shim.c.

199 {
200 EFI_STATUS efirc;
201
202 /* Call original SetVariable() */
203 efirc = efi_shim_orig_set_variable ( name, guid, attrs, len, data );
204
205 /* Allow verification of SbatLevel variable content */
206 if ( efi_shim_is_sbatlevel ( name, guid ) && ( efirc == 0 ) ) {
207 DBGC ( &efi_shim, "SHIM detected write to %ls:\n", name );
208 DBGC_HDA ( &efi_shim, 0, data, len );
210 }
211
212 return efirc;
213}
ring len
Length.
Definition dwmac.h:226
static int efi_shim_sbatlevel_verify
Verify read from SbatLevel variable.
Definition efi_shim.c:124
static EFI_SET_VARIABLE efi_shim_orig_set_variable
Original SetVariable() function.
Definition efi_shim.c:118
static int efi_shim_is_sbatlevel(const CHAR16 *name, const EFI_GUID *guid)
Check if variable is SbatLevel.
Definition efi_shim.c:133
uint8_t data[48]
Additional event data.
Definition ena.h:11
#define DBGC_HDA(...)
Definition compiler.h:506

References data, DBGC, DBGC_HDA, efi_shim_is_sbatlevel(), efi_shim_orig_set_variable, efi_shim_sbatlevel_verify, guid, len, name, and VOID.

Referenced by efi_shim_get_memory_map(), and efi_shim_install().

◆ efi_shim_get_variable()

EFI_STATUS EFIAPI efi_shim_get_variable ( CHAR16 * name,
EFI_GUID * guid,
UINT32 * attrs,
UINTN * len,
VOID * data )
static

Wrap GetVariable()

Parameters
nameVariable name
guidVariable namespace GUID
attrsAttributes to fill in
lenBuffer size
dataData buffer
Return values
efircEFI status code

Definition at line 226 of file efi_shim.c.

227 {
228 char *value = data;
229 EFI_STATUS efirc;
230
231 /* Call original GetVariable() */
232 efirc = efi_shim_orig_get_variable ( name, guid, attrs, len, data );
233
234 /* Patch SbatLevel variable if applicable */
235 if ( efi_shim_is_sbatlevel ( name, guid ) && data && ( efirc == 0 ) ) {
236 if ( efi_shim_allow_sbat ) {
237 DBGC ( &efi_shim, "SHIM allowing read from %ls:\n",
238 name );
239 } else if ( efi_shim_sbatlevel_verify ) {
240 DBGC ( &efi_shim, "SHIM allowing one read from %ls:\n",
241 name );
243 } else {
244 DBGC ( &efi_shim, "SHIM patching read from %ls:\n",
245 name );
246 value[0] = '\0';
247 }
248 DBGC_HDA ( &efi_shim, 0, data, *len );
249 }
250
251 return efirc;
252}
pseudo_bit_t value[0x00020]
Definition arbel.h:2
int efi_shim_allow_sbat
Allow SBAT variable access.
Definition efi_shim.c:107
static EFI_GET_VARIABLE efi_shim_orig_get_variable
Original GetVariable() function.
Definition efi_shim.c:121

References data, DBGC, DBGC_HDA, efi_shim_allow_sbat, efi_shim_is_sbatlevel(), efi_shim_orig_get_variable, efi_shim_sbatlevel_verify, guid, len, name, value, and VOID.

Referenced by efi_shim_get_memory_map(), and efi_shim_install().

◆ efi_shim_get_memory_map()

EFIAPI EFI_STATUS efi_shim_get_memory_map ( UINTN * len,
EFI_MEMORY_DESCRIPTOR * map,
UINTN * key,
UINTN * desclen,
UINT32 * descver )
static

Wrap GetMemoryMap()

Parameters
lenMemory map size
mapMemory map
keyMemory map key
desclenDescriptor size
descverDescriptor version
Return values
efircEFI status code

Definition at line 264 of file efi_shim.c.

267 {
268 EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
269
270 /* Unlock shim */
273
274 /* Uninstall runtime services wrappers, if still installed */
275 if ( rs->SetVariable == efi_shim_set_variable ) {
277 DBGC ( &efi_shim, "SHIM uninstalled SetVariable() wrapper\n" );
278 } else if ( rs->SetVariable != efi_shim_orig_set_variable ) {
279 DBGC ( &efi_shim, "SHIM could not uninstall SetVariable() "
280 "wrapper!\n" );
281 }
282 if ( rs->GetVariable == efi_shim_get_variable ) {
284 DBGC ( &efi_shim, "SHIM uninstalled GetVariable() wrapper\n" );
285 } else if ( rs->GetVariable != efi_shim_orig_get_variable ) {
286 DBGC ( &efi_shim, "SHIM could not uninstall GetVariable() "
287 "wrapper!\n" );
288 }
289
290 /* Hand off to original GetMemoryMap() */
291 return efi_shim_orig_get_memory_map ( len, map, key, desclen,
292 descver );
293}
union @162305117151260234136356364136041353210355154177 key
Sense key.
Definition scsi.h:3
static void efi_shim_unlock(void)
Unlock UEFI shim.
Definition efi_shim.c:145
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:226
int efi_shim_require_loader
Require use of a third party loader binary.
Definition efi_shim.c:69
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:198
static __always_inline int struct dma_mapping * map
Definition dma.h:184
EFI Runtime Services Table.
Definition UefiSpec.h:1880
EFI_SET_VARIABLE SetVariable
Definition UefiSpec.h:1905
EFI_GET_VARIABLE GetVariable
Definition UefiSpec.h:1903

References DBGC, efi_shim_get_variable(), efi_shim_orig_get_memory_map, efi_shim_orig_get_variable, efi_shim_orig_set_variable, efi_shim_require_loader, efi_shim_set_variable(), efi_shim_unlock(), efi_systab, EFIAPI, EFI_RUNTIME_SERVICES::GetVariable, key, len, map, and EFI_RUNTIME_SERVICES::SetVariable.

Referenced by efi_shim_install().

◆ efi_shim_inhibit_pxe()

int efi_shim_inhibit_pxe ( EFI_HANDLE handle)
static

Inhibit use of PXE base code.

Parameters
handleEFI handle
Return values
rcReturn status code

Definition at line 301 of file efi_shim.c.

301 {
303 EFI_STATUS efirc;
304 int rc;
305
306 /* Locate PXE base code */
308 &pxe ) ) != 0 ) {
309 DBGC ( &efi_shim, "SHIM could not open PXE base code: %s\n",
310 strerror ( rc ) );
311 return rc;
312 }
313
314 /* Stop PXE base code */
315 if ( ( efirc = pxe->Stop ( pxe ) ) != 0 ) {
316 rc = -EEFI ( efirc );
317 DBGC ( &efi_shim, "SHIM could not stop PXE base code: %s\n",
318 strerror ( rc ) );
319 return rc;
320 }
321
322 DBGC ( &efi_shim, "SHIM stopped PXE base code\n" );
323 return 0;
324}
struct _EFI_PXE_BASE_CODE_PROTOCOL EFI_PXE_BASE_CODE_PROTOCOL
Definition PxeBaseCode.h:30
EFI_GUID efi_pxe_base_code_protocol_guid
PXE base code protocol GUID.
Definition efi_guid.c:321
uint16_t handle
Handle.
Definition smbios.h:5
EFI_PXE_BASE_CODE_STOP Stop

References DBGC, EEFI, EFI_HANDLE, efi_open, efi_pxe_base_code_protocol_guid, handle, rc, _EFI_PXE_BASE_CODE_PROTOCOL::Stop, and strerror().

Referenced by efi_shim_install().

◆ efi_shim_cmdline()

int efi_shim_cmdline ( struct image * shim,
wchar_t ** cmdline )
static

Update command line.

Parameters
shimShim image
cmdlineCommand line to update
Return values
rcReturn status code

Definition at line 333 of file efi_shim.c.

333 {
334 wchar_t *shimcmdline;
335 int len;
336 int rc;
337
338 /* Construct new command line */
339 len = ( shim->cmdline ?
340 efi_asprintf ( &shimcmdline, "%s %s", shim->name,
341 shim->cmdline ) :
342 efi_asprintf ( &shimcmdline, "%s %ls", shim->name,
343 *cmdline ) );
344 if ( len < 0 ) {
345 rc = len;
346 DBGC ( &efi_shim, "SHIM could not construct command line: "
347 "%s\n", strerror ( rc ) );
348 return rc;
349 }
350
351 /* Replace command line */
352 free ( *cmdline );
353 *cmdline = shimcmdline;
354
355 return 0;
356}
int efi_asprintf(wchar_t **wstrp, const char *fmt,...)
Write a formatted string to newly allocated memory.
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

References cmdline, DBGC, efi_asprintf(), free, len, rc, shim(), and strerror().

Referenced by efi_shim_install().

◆ efi_shim_install()

int efi_shim_install ( struct image * shim,
EFI_HANDLE handle,
wchar_t ** cmdline )

Install UEFI shim special handling.

Parameters
shimShim image
handleEFI device handle
cmdlineCommand line to update
Return values
rcReturn status code

Definition at line 366 of file efi_shim.c.

367 {
368 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
369 EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
370 int rc;
371
372 /* Stop PXE base code */
373 if ( ( ! efi_shim_allow_pxe ) &&
374 ( ( rc = efi_shim_inhibit_pxe ( handle ) ) != 0 ) ) {
375 return rc;
376 }
377
378 /* Update command line */
379 if ( ( rc = efi_shim_cmdline ( shim, cmdline ) ) != 0 )
380 return rc;
381
382 /* Record original boot and runtime services functions */
386
387 /* Wrap relevant boot and runtime services functions */
391 DBGC ( &efi_shim, "SHIM installed wrappers\n" );
392
393 return 0;
394}
static int efi_shim_cmdline(struct image *shim, wchar_t **cmdline)
Update command line.
Definition efi_shim.c:333
int efi_shim_allow_pxe
Allow use of PXE base code protocol.
Definition efi_shim.c:87
static int efi_shim_inhibit_pxe(EFI_HANDLE handle)
Inhibit use of PXE base code.
Definition efi_shim.c:301
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:264
EFI_GET_MEMORY_MAP GetMemoryMap
Definition UefiSpec.h:1948

References cmdline, DBGC, EFI_HANDLE, efi_shim_allow_pxe, efi_shim_cmdline(), efi_shim_get_memory_map(), efi_shim_get_variable(), efi_shim_inhibit_pxe(), efi_shim_orig_get_memory_map, efi_shim_orig_get_variable, efi_shim_orig_set_variable, efi_shim_set_variable(), efi_systab, EFI_BOOT_SERVICES::GetMemoryMap, EFI_RUNTIME_SERVICES::GetVariable, handle, rc, EFI_RUNTIME_SERVICES::SetVariable, and shim().

Referenced by efi_image_exec().

◆ efi_shim_uninstall()

void efi_shim_uninstall ( void )

Uninstall UEFI shim special handling.

Definition at line 400 of file efi_shim.c.

400 {
401 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
402 EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
403
404 /* Restore original boot and runtime services functions */
408 DBGC ( &efi_shim, "SHIM uninstalled wrappers\n" );
409}

References DBGC, efi_shim_orig_get_memory_map, efi_shim_orig_get_variable, efi_shim_orig_set_variable, efi_systab, EFI_BOOT_SERVICES::GetMemoryMap, EFI_RUNTIME_SERVICES::GetVariable, and EFI_RUNTIME_SERVICES::SetVariable.

Referenced by efi_image_exec().

Variable Documentation

◆ efi_shim_require_loader

int efi_shim_require_loader = 0

Require use of a third party loader binary.

The UEFI shim is gradually becoming less capable of directly executing a Linux kernel image, due to an ever increasing list of assumptions that it will only ever be used in conjunction with a second stage loader binary such as GRUB.

For example: shim will erroneously complain if the image that it loads and executes does not in turn call in to the "shim lock protocol" to verify a separate newly loaded binary before calling ExitBootServices(), even if no such separate binary is used or required.

Experience shows that there is unfortunately no point in trying to get a fix for this upstreamed into shim. We therefore default to reducing the Secure Boot attack surface by removing, where possible, this spurious requirement for the use of an additional second stage loader.

This option may be used to require the use of an additional second stage loader binary, in case this behaviour is ever desirable.

Definition at line 69 of file efi_shim.c.

Referenced by efi_shim_get_memory_map(), FILE_SECBOOT(), and shim().

◆ efi_shim_allow_pxe

int efi_shim_allow_pxe = 0

Allow use of PXE base code protocol.

We provide shim with access to all of the relevant downloaded files via our EFI_SIMPLE_FILE_SYSTEM_PROTOCOL interface. However, shim will instead try to redownload the files via TFTP since it prefers to use the EFI_PXE_BASE_CODE_PROTOCOL installed on the same handle.

Experience shows that there is unfortunately no point in trying to get a fix for this upstreamed into shim. We therefore default to working around this undesirable behaviour by stopping the PXE base code protocol before invoking shim.

This option may be used to allow shim to use the PXE base code protocol, in case this behaviour is ever desirable.

Definition at line 87 of file efi_shim.c.

Referenced by efi_shim_install(), FILE_SECBOOT(), and shim().

◆ efi_shim_allow_sbat

int efi_shim_allow_sbat = 0

Allow SBAT variable access.

The UEFI shim implements a fairly nicely designed revocation mechanism designed around the concept of security generations. Unfortunately nobody in the shim community has thus far added the relevant metadata to the Linux kernel, with the result that current versions of shim are incapable of booting current versions of the Linux kernel.

Experience shows that there is unfortunately no point in trying to get a fix for this upstreamed into shim. We therefore default to working around this undesirable behaviour by patching data read from the "SbatLevel" variable used to hold SBAT configuration.

This option may be used to allow shim unpatched access to the "SbatLevel" variable, in case this behaviour is ever desirable.

Definition at line 107 of file efi_shim.c.

Referenced by efi_shim_get_variable(), FILE_SECBOOT(), and shim().

◆ __image_tag

struct image_tag efi_shim __image_tag
Initial value:
= {
.name = "SHIM",
}

UEFI shim image.

The downloaded flattened device tree tag.

Definition at line 110 of file efi_shim.c.

110 {
111 .name = "SHIM",
112};

◆ efi_shim_orig_get_memory_map

EFI_GET_MEMORY_MAP efi_shim_orig_get_memory_map
static

Original GetMemoryMap() function.

Definition at line 115 of file efi_shim.c.

Referenced by efi_shim_get_memory_map(), efi_shim_install(), and efi_shim_uninstall().

◆ efi_shim_orig_set_variable

EFI_SET_VARIABLE efi_shim_orig_set_variable
static

Original SetVariable() function.

Definition at line 118 of file efi_shim.c.

Referenced by efi_shim_get_memory_map(), efi_shim_install(), efi_shim_set_variable(), and efi_shim_uninstall().

◆ efi_shim_orig_get_variable

EFI_GET_VARIABLE efi_shim_orig_get_variable
static

Original GetVariable() function.

Definition at line 121 of file efi_shim.c.

Referenced by efi_shim_get_memory_map(), efi_shim_get_variable(), efi_shim_install(), and efi_shim_uninstall().

◆ efi_shim_sbatlevel_verify

int efi_shim_sbatlevel_verify
static

Verify read from SbatLevel variable.

Definition at line 124 of file efi_shim.c.

Referenced by efi_shim_get_variable(), and efi_shim_set_variable().