From 44cee23d139fe8faaca2622cc09041b1d684265b Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Tue, 5 Jun 2012 09:23:25 -0400 Subject: [PATCH] Support secure boot. If SecureBoot is enabled, treat all authentications as failure, and also use shim's verify routine to verify the kernel before loading. --- grub-core/loader/i386/linux.c | 26 +++++++++++++ grub-core/normal/auth.c | 85 +++++++++++++++++++++++++++++++++++++++++ grub-core/normal/main.c | 4 +- grub-core/normal/menu_entry.c | 5 ++- include/grub/auth.h | 3 ++ 5 files changed, 121 insertions(+), 2 deletions(-) diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c index 6e8238e..090484c 100644 --- a/grub-core/loader/i386/linux.c +++ b/grub-core/loader/i386/linux.c @@ -34,6 +34,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -681,6 +682,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), int relocatable; grub_uint64_t preffered_address = GRUB_LINUX_BZIMAGE_ADDR; + void *buffer; + grub_err_t verified; + grub_dl_ref (my_mod); if (argc == 0) @@ -693,6 +697,28 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), if (! file) goto fail; + buffer = grub_malloc(grub_file_size(file)); + if (!buffer) + return grub_errno; + + if (grub_file_read (file, buffer, grub_file_size(file))) + { + if (!grub_errno) + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), + argv[0]); + goto fail; + } + + verified = grub_auth_verify_signature(buffer, grub_file_size(file)); + grub_free(buffer); + if (verified != GRUB_ERR_NONE) + { + grub_errno = verified; + goto fail; + } + + grub_free(buffer); + grub_file_seek(file, 0); if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) { if (!grub_errno) diff --git a/grub-core/normal/auth.c b/grub-core/normal/auth.c index c6bd96e..3e83ee8 100644 --- a/grub-core/normal/auth.c +++ b/grub-core/normal/auth.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include struct grub_auth_user { @@ -198,6 +200,89 @@ grub_username_get (char buf[], unsigned buf_size) } grub_err_t +grub_auth_secure_boot (void) +{ +#ifdef GRUB_MACHINE_EFI + grub_size_t datasize = 0; + grub_uint8_t *data; + grub_efi_guid_t guid = GRUB_EFI_GLOBAL_VARIABLE_GUID; + unsigned int x; + + data = grub_efi_get_variable ("SecureBoot", &guid, &datasize); + if (!data) + return GRUB_ERR_NONE; + + for (x = 0; x < datasize; x++) + if (data[x] == 1) + return GRUB_ACCESS_DENIED; +#endif + + return GRUB_ERR_NONE; +} + +int +grub_is_secure_boot (void) +{ + return grub_auth_secure_boot() == GRUB_ACCESS_DENIED; +} + +#define SHIM_LOCK_GUID \ + { 0x605dab50, 0xe046, 0x4300, {0xab,0xb6,0x3d,0xd8,0x10,0xdd,0x8b,0x23} } + +typedef grub_efi_status_t (*EFI_SHIM_LOCK_VERIFY)(void *buffer, grub_efi_uint32_t size); + +typedef struct _SHIM_LOCK { + EFI_SHIM_LOCK_VERIFY Verify; +} SHIM_LOCK; + +grub_err_t +grub_auth_verify_signature (void *buffer, grub_uint32_t size) +{ +#ifdef GRUB_MACHINE_EFI + grub_efi_guid_t shim_guid = SHIM_LOCK_GUID; + SHIM_LOCK *shim = NULL; + grub_efi_handle_t *handles, shim_handle = NULL; + grub_efi_uintn_t num_handles, i; + grub_efi_status_t status; + + if (!grub_is_secure_boot()) + return GRUB_ERR_NONE; + + handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &shim_guid, NULL, + &num_handles); + if (!handles || num_handles == 0) +no_verify: + return grub_error (GRUB_ACCESS_DENIED, "Could not find signature verification routine"); + + for (i = 0; i < num_handles; i++) + { + shim_handle = handles[i]; + shim = grub_efi_open_protocol (shim_handle, &shim_guid, + GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (shim) + break; + } + + if (!shim) + { + grub_free(handles); + goto no_verify; + } + + status = shim->Verify(buffer, size); + + grub_free(handles); + + if (status == GRUB_EFI_SUCCESS) + return GRUB_ERR_NONE; + + return grub_error (GRUB_ACCESS_DENIED, "Signature verification failed"); +#else + return GRUB_ERR_NONE; +#endif +} + +grub_err_t grub_auth_check_authentication (const char *userlist) { char login[1024]; diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c index 193d7d3..1e321a4 100644 --- a/grub-core/normal/main.c +++ b/grub-core/normal/main.c @@ -455,7 +455,9 @@ grub_cmdline_run (int nested) { grub_err_t err = GRUB_ERR_NONE; - err = grub_auth_check_authentication (NULL); + err = grub_auth_secure_boot (); + if (err == GRUB_ERR_NONE) + err = grub_auth_check_authentication (NULL); if (err) { diff --git a/grub-core/normal/menu_entry.c b/grub-core/normal/menu_entry.c index 7fc890d..4e7a08c 100644 --- a/grub-core/normal/menu_entry.c +++ b/grub-core/normal/menu_entry.c @@ -1287,7 +1287,10 @@ grub_menu_entry_run (grub_menu_entry_t entry) unsigned i; grub_term_output_t term; - err = grub_auth_check_authentication (NULL); + + err = grub_auth_secure_boot (); + if (err == GRUB_ERR_NONE) + err = grub_auth_check_authentication (NULL); if (err) { diff --git a/include/grub/auth.h b/include/grub/auth.h index 7473344..b933fa1 100644 --- a/include/grub/auth.h +++ b/include/grub/auth.h @@ -32,6 +32,9 @@ grub_err_t grub_auth_unregister_authentication (const char *user); grub_err_t grub_auth_authenticate (const char *user); grub_err_t grub_auth_deauthenticate (const char *user); +grub_err_t grub_auth_secure_boot (void); +int grub_is_secure_boot (void); +grub_err_t grub_auth_verify_signature (void *buffer, grub_uint32_t size); grub_err_t grub_auth_check_authentication (const char *userlist); #endif /* ! GRUB_AUTH_HEADER */ -- 1.7.10.2