mirror of
https://gitlab.com/qemu-project/ipxe.git
synced 2025-11-03 07:59:06 +08:00
WIP - shim unlocker
This commit is contained in:
@ -32,6 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
#include <ipxe/efi/efi_pxe.h>
|
||||
#include <ipxe/efi/efi_driver.h>
|
||||
#include <ipxe/efi/efi_image.h>
|
||||
#include <ipxe/efi/efi_shim.h>
|
||||
#include <ipxe/image.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/features.h>
|
||||
@ -56,16 +57,6 @@ FEATURE ( FEATURE_IMAGE, "EFI", DHCP_EB_FEATURE_EFI, 1 );
|
||||
"Could not start image" )
|
||||
#define EEFI_START( efirc ) EPLATFORM ( EINFO_EEFI_START, efirc )
|
||||
|
||||
/** EFI shim image */
|
||||
struct image_tag efi_shim __image_tag = {
|
||||
.name = "SHIM",
|
||||
};
|
||||
|
||||
/** EIF shim crutch image */
|
||||
struct image_tag efi_shim_crutch __image_tag = {
|
||||
.name = "SHIMCRUTCH",
|
||||
};
|
||||
|
||||
/**
|
||||
* Create device path for image
|
||||
*
|
||||
@ -165,6 +156,7 @@ static int efi_image_exec ( struct image *image ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
struct efi_snp_device *snpdev;
|
||||
EFI_DEVICE_PATH_PROTOCOL *path;
|
||||
struct efi_shim_unlocker unlocker;
|
||||
union {
|
||||
EFI_LOADED_IMAGE_PROTOCOL *image;
|
||||
void *interface;
|
||||
@ -242,6 +234,14 @@ static int efi_image_exec ( struct image *image ) {
|
||||
goto err_cmdline;
|
||||
}
|
||||
|
||||
/* Install shim unlocker (if using a shim) */
|
||||
if ( shim &&
|
||||
( ( rc = efi_shim_install ( &unlocker ) ) != 0 ) ) {
|
||||
DBGC ( image, "EFIIMAGE %s could not install shim unlocker: "
|
||||
"%s\n", image->name, strerror ( rc ) );
|
||||
goto err_shim_install;
|
||||
}
|
||||
|
||||
/* Attempt loading image */
|
||||
handle = NULL;
|
||||
if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, path,
|
||||
@ -336,6 +336,9 @@ static int efi_image_exec ( struct image *image ) {
|
||||
if ( rc != 0 )
|
||||
bs->UnloadImage ( handle );
|
||||
err_load_image:
|
||||
if ( shim )
|
||||
efi_shim_uninstall ( &unlocker );
|
||||
err_shim_install:
|
||||
free ( cmdline );
|
||||
err_cmdline:
|
||||
free ( path );
|
||||
|
||||
29
src/include/ipxe/efi/Protocol/ShimLock.h
Normal file
29
src/include/ipxe/efi/Protocol/ShimLock.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef _IPXE_EFI_SHIM_LOCK_PROTOCOL_H
|
||||
#define _IPXE_EFI_SHIM_LOCK_PROTOCOL_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* EFI "shim lock" protocol
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( BSD3 );
|
||||
|
||||
#define EFI_SHIM_LOCK_PROTOCOL_GUID \
|
||||
{ 0x605dab50, 0xe046, 0x4300, \
|
||||
{ 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 } }
|
||||
|
||||
typedef
|
||||
EFI_STATUS
|
||||
(*EFI_SHIM_LOCK_VERIFY) (
|
||||
IN VOID *buffer,
|
||||
IN UINT32 size
|
||||
);
|
||||
|
||||
typedef struct _EFI_SHIM_LOCK_PROTOCOL {
|
||||
EFI_SHIM_LOCK_VERIFY Verify;
|
||||
VOID *Reserved1;
|
||||
VOID *Reserved2;
|
||||
} EFI_SHIM_LOCK_PROTOCOL;
|
||||
|
||||
#endif /*_IPXE_EFI_SHIM_LOCK_PROTOCOL_H */
|
||||
@ -197,6 +197,7 @@ extern EFI_GUID efi_pci_io_protocol_guid;
|
||||
extern EFI_GUID efi_pci_root_bridge_io_protocol_guid;
|
||||
extern EFI_GUID efi_pxe_base_code_protocol_guid;
|
||||
extern EFI_GUID efi_serial_io_protocol_guid;
|
||||
extern EFI_GUID efi_shim_lock_protocol_guid;
|
||||
extern EFI_GUID efi_simple_file_system_protocol_guid;
|
||||
extern EFI_GUID efi_simple_network_protocol_guid;
|
||||
extern EFI_GUID efi_simple_pointer_protocol_guid;
|
||||
|
||||
@ -11,9 +11,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/image.h>
|
||||
|
||||
extern struct image_tag efi_shim __image_tag;
|
||||
extern struct image_tag efi_shim_crutch __image_tag;
|
||||
|
||||
extern struct image_type efi_image_type[] __image_type ( PROBE_NORMAL );
|
||||
|
||||
/**
|
||||
|
||||
29
src/include/ipxe/efi/efi_shim.h
Normal file
29
src/include/ipxe/efi/efi_shim.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef _IPXE_EFI_SHIM_H
|
||||
#define _IPXE_EFI_SHIM_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* UEFI shim handling
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/image.h>
|
||||
#include <ipxe/efi/efi.h>
|
||||
|
||||
/** A shim unlocker */
|
||||
struct efi_shim_unlocker {
|
||||
/** Protocol installation event */
|
||||
EFI_EVENT event;
|
||||
/** Protocol notification registration token */
|
||||
void *token;
|
||||
};
|
||||
|
||||
extern struct image_tag efi_shim __image_tag;
|
||||
extern struct image_tag efi_shim_crutch __image_tag;
|
||||
|
||||
extern int efi_shim_install ( struct efi_shim_unlocker *unlocker );
|
||||
extern void efi_shim_uninstall ( struct efi_shim_unlocker *unlocker );
|
||||
|
||||
#endif /* _IPXE_EFI_SHIM_H */
|
||||
@ -404,6 +404,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#define ERRFILE_dhe ( ERRFILE_OTHER | 0x005a0000 )
|
||||
#define ERRFILE_efi_cmdline ( ERRFILE_OTHER | 0x005b0000 )
|
||||
#define ERRFILE_efi_rng ( ERRFILE_OTHER | 0x005c0000 )
|
||||
#define ERRFILE_efi_shim ( ERRFILE_OTHER | 0x005d0000 )
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
@ -143,6 +143,8 @@ static struct efi_well_known_guid efi_well_known_guids[] = {
|
||||
"PxeBaseCode" },
|
||||
{ &efi_serial_io_protocol_guid,
|
||||
"SerialIo" },
|
||||
{ &efi_shim_lock_protocol_guid,
|
||||
"ShimLock" },
|
||||
{ &efi_simple_file_system_protocol_guid,
|
||||
"SimpleFileSystem" },
|
||||
{ &efi_simple_network_protocol_guid,
|
||||
|
||||
@ -54,6 +54,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#include <ipxe/efi/Protocol/PciRootBridgeIo.h>
|
||||
#include <ipxe/efi/Protocol/PxeBaseCode.h>
|
||||
#include <ipxe/efi/Protocol/SerialIo.h>
|
||||
#include <ipxe/efi/Protocol/ShimLock.h>
|
||||
#include <ipxe/efi/Protocol/SimpleFileSystem.h>
|
||||
#include <ipxe/efi/Protocol/SimpleNetwork.h>
|
||||
#include <ipxe/efi/Protocol/SimplePointer.h>
|
||||
@ -227,6 +228,10 @@ EFI_GUID efi_pxe_base_code_protocol_guid
|
||||
EFI_GUID efi_serial_io_protocol_guid
|
||||
= EFI_SERIAL_IO_PROTOCOL_GUID;
|
||||
|
||||
/** Shim lock protocol GUID */
|
||||
EFI_GUID efi_shim_lock_protocol_guid
|
||||
= EFI_SHIM_LOCK_PROTOCOL_GUID;
|
||||
|
||||
/** Simple file system protocol GUID */
|
||||
EFI_GUID efi_simple_file_system_protocol_guid
|
||||
= EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
|
||||
|
||||
144
src/interface/efi/efi_shim.c
Normal file
144
src/interface/efi/efi_shim.c
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ipxe/image.h>
|
||||
#include <ipxe/efi/efi.h>
|
||||
#include <ipxe/efi/efi_shim.h>
|
||||
#include <ipxe/efi/Protocol/ShimLock.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* UEFI shim handling
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/** EFI shim image */
|
||||
struct image_tag efi_shim __image_tag = {
|
||||
.name = "SHIM",
|
||||
};
|
||||
|
||||
/** EFI shim crutch image */
|
||||
struct image_tag efi_shim_crutch __image_tag = {
|
||||
.name = "SHIMCRUTCH",
|
||||
};
|
||||
|
||||
/**
|
||||
* Unlock UEFI shim
|
||||
*
|
||||
* @v event Event
|
||||
* @v context Event context
|
||||
*
|
||||
* The UEFI shim is gradually becoming less capable of directly
|
||||
* executing a kernel image, due to an ever increasing list of
|
||||
* assumptions that it will only ever be used in conjunction with a
|
||||
* second stage loader such as GRUB.
|
||||
*
|
||||
* For example: shim will erroneously complain if the image that it
|
||||
* loads and executes does not call in to the "shim lock protocol"
|
||||
* before calling ExitBootServices(), even if there is no valid reason
|
||||
* for it to have done so.
|
||||
*
|
||||
* Reduce the Secure Boot attack surface by removing, where possible,
|
||||
* this spurious requirement for the use of an additional second stage
|
||||
* loader.
|
||||
*/
|
||||
static EFIAPI void efi_shim_unlock ( EFI_EVENT event __unused, void *context ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
EFI_GUID *protocol = &efi_shim_lock_protocol_guid;
|
||||
struct efi_shim_unlocker *unlocker = context;
|
||||
union {
|
||||
EFI_SHIM_LOCK_PROTOCOL *lock;
|
||||
void *interface;
|
||||
} u;
|
||||
uint8_t empty[0];
|
||||
EFI_STATUS efirc;
|
||||
|
||||
/* Process all new instances of the shim lock protocol */
|
||||
while ( 1 ) {
|
||||
|
||||
/* Get next instance */
|
||||
if ( ( efirc = bs->LocateProtocol ( protocol, unlocker->token,
|
||||
&u.interface ) ) != 0 )
|
||||
break;
|
||||
|
||||
/* Call shim lock protocol with empty buffer */
|
||||
u.lock->Verify ( empty, sizeof ( empty ) );
|
||||
DBGC ( unlocker, "SHIM unlocked %p\n", u.interface );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Install UEFI shim unlocker
|
||||
*
|
||||
* @v unlocker Shim unlocker
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int efi_shim_install ( struct efi_shim_unlocker *unlocker ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
EFI_GUID *protocol = &efi_shim_lock_protocol_guid;
|
||||
EFI_STATUS efirc;
|
||||
int rc;
|
||||
|
||||
/* Create event */
|
||||
if ( ( efirc = bs->CreateEvent ( EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
|
||||
efi_shim_unlock, unlocker,
|
||||
&unlocker->event ) ) != 0 ) {
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( unlocker, "SHIM could not create event: %s\n",
|
||||
strerror ( rc ) );
|
||||
goto err_create_event;
|
||||
}
|
||||
|
||||
/* Register for protocol installations */
|
||||
if ( ( efirc = bs->RegisterProtocolNotify ( protocol, unlocker->event,
|
||||
&unlocker->token ) ) != 0){
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( unlocker, "SHIM could not register for protocols: %s\n",
|
||||
strerror ( rc ) );
|
||||
goto err_register_notify;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_register_notify:
|
||||
bs->CloseEvent ( unlocker->event );
|
||||
err_create_event:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall UEFI shim unlocker
|
||||
*
|
||||
* @v unlocker Shim unlocker
|
||||
*/
|
||||
void efi_shim_uninstall ( struct efi_shim_unlocker *unlocker ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
|
||||
bs->CloseEvent ( unlocker->event );
|
||||
}
|
||||
@ -24,7 +24,7 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/efi/efi.h>
|
||||
#include <ipxe/efi/efi_image.h>
|
||||
#include <ipxe/efi/efi_shim.h>
|
||||
#include <usr/shimmgmt.h>
|
||||
|
||||
/** @file
|
||||
|
||||
Reference in New Issue
Block a user