aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2023-05-19 14:03:12 +0100
committerMichael Brown <mcb30@ipxe.org>2023-05-19 14:03:12 +0100
commit6e85f25ca66f806ed6d87e503b09fe01df4f7831 (patch)
tree5c55c739fcacbdb0feebcf3ddc0a9bdc5605fda7
parentbacfb468216ad6a139e63510cb28d4044dd121de (diff)
downloadipxe-6e85f25ca66f806ed6d87e503b09fe01df4f7831.tar.gz
WIP - shim unlocker
-rw-r--r--src/image/efi_image.c23
-rw-r--r--src/include/ipxe/efi/Protocol/ShimLock.h29
-rw-r--r--src/include/ipxe/efi/efi.h1
-rw-r--r--src/include/ipxe/efi/efi_image.h3
-rw-r--r--src/include/ipxe/efi/efi_shim.h29
-rw-r--r--src/include/ipxe/errfile.h1
-rw-r--r--src/interface/efi/efi_debug.c2
-rw-r--r--src/interface/efi/efi_guid.c5
-rw-r--r--src/interface/efi/efi_shim.c144
-rw-r--r--src/usr/shimmgmt.c2
10 files changed, 225 insertions, 14 deletions
diff --git a/src/image/efi_image.c b/src/image/efi_image.c
index 42a724ee0..13f08de28 100644
--- a/src/image/efi_image.c
+++ b/src/image/efi_image.c
@@ -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 );
diff --git a/src/include/ipxe/efi/Protocol/ShimLock.h b/src/include/ipxe/efi/Protocol/ShimLock.h
new file mode 100644
index 000000000..726081949
--- /dev/null
+++ b/src/include/ipxe/efi/Protocol/ShimLock.h
@@ -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 */
diff --git a/src/include/ipxe/efi/efi.h b/src/include/ipxe/efi/efi.h
index 1dd0d4453..e0e2db608 100644
--- a/src/include/ipxe/efi/efi.h
+++ b/src/include/ipxe/efi/efi.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;
diff --git a/src/include/ipxe/efi/efi_image.h b/src/include/ipxe/efi/efi_image.h
index c9766b924..0fc0402b1 100644
--- a/src/include/ipxe/efi/efi_image.h
+++ b/src/include/ipxe/efi/efi_image.h
@@ -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 );
/**
diff --git a/src/include/ipxe/efi/efi_shim.h b/src/include/ipxe/efi/efi_shim.h
new file mode 100644
index 000000000..ec7803d66
--- /dev/null
+++ b/src/include/ipxe/efi/efi_shim.h
@@ -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 */
diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h
index e6fd8524e..021f6a72e 100644
--- a/src/include/ipxe/errfile.h
+++ b/src/include/ipxe/errfile.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 )
/** @} */
diff --git a/src/interface/efi/efi_debug.c b/src/interface/efi/efi_debug.c
index 967bb6182..02cbf9fa4 100644
--- a/src/interface/efi/efi_debug.c
+++ b/src/interface/efi/efi_debug.c
@@ -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,
diff --git a/src/interface/efi/efi_guid.c b/src/interface/efi/efi_guid.c
index 663585dc2..25c342ffb 100644
--- a/src/interface/efi/efi_guid.c
+++ b/src/interface/efi/efi_guid.c
@@ -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;
diff --git a/src/interface/efi/efi_shim.c b/src/interface/efi/efi_shim.c
new file mode 100644
index 000000000..b0caf227d
--- /dev/null
+++ b/src/interface/efi/efi_shim.c
@@ -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 );
+}
diff --git a/src/usr/shimmgmt.c b/src/usr/shimmgmt.c
index 4a5966deb..ecffd01d9 100644
--- a/src/usr/shimmgmt.c
+++ b/src/usr/shimmgmt.c
@@ -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