efi: Add EFI shim lock verifier
This module provides shim lock verification for various kernels if UEFI secure boot is enabled on a machine. It is recommended to put this module into GRUB2 standalone image (avoid putting iorw and memrw modules into it; they are disallowed if UEFI secure boot is enabled). However, it is also possible to use it as a normal module. Though such configurations are more fragile and less secure due to various limitations. If the module is loaded and UEFI secure boot is enabled then: - module itself cannot be unloaded (persistent module), - the iorw and memrw modules cannot be loaded, - if the iorw and memrw modules are loaded then machine boot is disabled, - GRUB2 defers modules and ACPI tables verification to other verifiers. Signed-off-by: Daniel Kiper <daniel.kiper@oracle.com> Reviewed-by: Ross Philipson <ross.philipson@oracle.com>
This commit is contained in:
parent
ee7808e219
commit
878398c1a3
3 changed files with 162 additions and 0 deletions
|
@ -5544,6 +5544,7 @@ environment variables and commands are listed in the same order.
|
||||||
@menu
|
@menu
|
||||||
* Authentication and authorisation:: Users and access control
|
* Authentication and authorisation:: Users and access control
|
||||||
* Using digital signatures:: Booting digitally signed code
|
* Using digital signatures:: Booting digitally signed code
|
||||||
|
* UEFI secure boot and shim:: Booting digitally signed PE files
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
@node Authentication and authorisation
|
@node Authentication and authorisation
|
||||||
|
@ -5706,6 +5707,20 @@ or BIOS) configuration to cause the machine to boot from a different
|
||||||
(attacker-controlled) device. GRUB is at best only one link in a
|
(attacker-controlled) device. GRUB is at best only one link in a
|
||||||
secure boot chain.
|
secure boot chain.
|
||||||
|
|
||||||
|
@node UEFI secure boot and shim
|
||||||
|
@section UEFI secure boot and shim support
|
||||||
|
|
||||||
|
The GRUB, except the @command{chainloader} command, works with the UEFI secure
|
||||||
|
boot and the shim. This functionality is provided by the shim_lock module. It
|
||||||
|
is recommend to build in this and other required modules into the @file{core.img}.
|
||||||
|
All modules not stored in the @file{core.img} and the ACPI tables for the
|
||||||
|
@command{acpi} command have to be signed, e.g. using PGP. Additionally, the
|
||||||
|
@command{iorw} and the @command{memrw} commands are prohibited if the UEFI
|
||||||
|
secure boot is enabled. This is done due to security reasons. All above
|
||||||
|
mentioned requirements are enforced by the shim_lock module. And itself it
|
||||||
|
is a persistent module which means that it cannot be unloaded if it was
|
||||||
|
loaded into the memory.
|
||||||
|
|
||||||
@node Platform limitations
|
@node Platform limitations
|
||||||
@chapter Platform limitations
|
@chapter Platform limitations
|
||||||
|
|
||||||
|
|
|
@ -899,6 +899,12 @@ module = {
|
||||||
common = commands/verifiers.c;
|
common = commands/verifiers.c;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module = {
|
||||||
|
name = shim_lock;
|
||||||
|
common = commands/efi/shim_lock.c;
|
||||||
|
enable = x86_64_efi;
|
||||||
|
};
|
||||||
|
|
||||||
module = {
|
module = {
|
||||||
name = hdparm;
|
name = hdparm;
|
||||||
common = commands/hdparm.c;
|
common = commands/hdparm.c;
|
||||||
|
|
141
grub-core/commands/efi/shim_lock.c
Normal file
141
grub-core/commands/efi/shim_lock.c
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
/*
|
||||||
|
* GRUB -- GRand Unified Bootloader
|
||||||
|
* Copyright (C) 2017 Free Software Foundation, Inc.
|
||||||
|
*
|
||||||
|
* GRUB 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 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* EFI shim lock verifier.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <grub/dl.h>
|
||||||
|
#include <grub/efi/efi.h>
|
||||||
|
#include <grub/err.h>
|
||||||
|
#include <grub/file.h>
|
||||||
|
#include <grub/misc.h>
|
||||||
|
#include <grub/verify.h>
|
||||||
|
|
||||||
|
GRUB_MOD_LICENSE ("GPLv3+");
|
||||||
|
|
||||||
|
#define GRUB_EFI_SHIM_LOCK_GUID \
|
||||||
|
{ 0x605dab50, 0xe046, 0x4300, \
|
||||||
|
{ 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 } \
|
||||||
|
}
|
||||||
|
|
||||||
|
struct grub_efi_shim_lock_protocol
|
||||||
|
{
|
||||||
|
grub_efi_status_t
|
||||||
|
(*verify) (void *buffer, grub_uint32_t size);
|
||||||
|
};
|
||||||
|
typedef struct grub_efi_shim_lock_protocol grub_efi_shim_lock_protocol_t;
|
||||||
|
|
||||||
|
static grub_efi_guid_t shim_lock_guid = GRUB_EFI_SHIM_LOCK_GUID;
|
||||||
|
static grub_efi_shim_lock_protocol_t *sl;
|
||||||
|
|
||||||
|
/* List of modules which cannot be loaded if UEFI secure boot mode is enabled. */
|
||||||
|
static const char * const disabled_mods[] = {"iorw", "memrw", NULL};
|
||||||
|
|
||||||
|
static grub_err_t
|
||||||
|
shim_lock_init (grub_file_t io, enum grub_file_type type,
|
||||||
|
void **context __attribute__ ((unused)),
|
||||||
|
enum grub_verify_flags *flags)
|
||||||
|
{
|
||||||
|
const char *b, *e;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
*flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
|
||||||
|
|
||||||
|
if (!sl)
|
||||||
|
return GRUB_ERR_NONE;
|
||||||
|
|
||||||
|
switch (type & GRUB_FILE_TYPE_MASK)
|
||||||
|
{
|
||||||
|
case GRUB_FILE_TYPE_GRUB_MODULE:
|
||||||
|
/* Establish GRUB module name. */
|
||||||
|
b = grub_strrchr (io->name, '/');
|
||||||
|
e = grub_strrchr (io->name, '.');
|
||||||
|
|
||||||
|
b = b ? (b + 1) : io->name;
|
||||||
|
e = e ? e : io->name + grub_strlen (io->name);
|
||||||
|
e = (e > b) ? e : io->name + grub_strlen (io->name);
|
||||||
|
|
||||||
|
for (i = 0; disabled_mods[i]; i++)
|
||||||
|
if (!grub_strncmp (b, disabled_mods[i], grub_strlen (b) - grub_strlen (e)))
|
||||||
|
{
|
||||||
|
grub_error (GRUB_ERR_ACCESS_DENIED,
|
||||||
|
N_("module cannot be loaded in UEFI secure boot mode: %s"),
|
||||||
|
io->name);
|
||||||
|
return GRUB_ERR_ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fall through. */
|
||||||
|
|
||||||
|
case GRUB_FILE_TYPE_ACPI_TABLE:
|
||||||
|
*flags = GRUB_VERIFY_FLAGS_DEFER_AUTH;
|
||||||
|
|
||||||
|
return GRUB_ERR_NONE;
|
||||||
|
|
||||||
|
case GRUB_FILE_TYPE_LINUX_KERNEL:
|
||||||
|
case GRUB_FILE_TYPE_MULTIBOOT_KERNEL:
|
||||||
|
case GRUB_FILE_TYPE_BSD_KERNEL:
|
||||||
|
case GRUB_FILE_TYPE_XNU_KERNEL:
|
||||||
|
case GRUB_FILE_TYPE_PLAN9_KERNEL:
|
||||||
|
for (i = 0; disabled_mods[i]; i++)
|
||||||
|
if (grub_dl_get (disabled_mods[i]))
|
||||||
|
{
|
||||||
|
grub_error (GRUB_ERR_ACCESS_DENIED,
|
||||||
|
N_("cannot boot due to dangerous module in memory: %s"),
|
||||||
|
disabled_mods[i]);
|
||||||
|
return GRUB_ERR_ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
*flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK;
|
||||||
|
|
||||||
|
/* Fall through. */
|
||||||
|
|
||||||
|
default:
|
||||||
|
return GRUB_ERR_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static grub_err_t
|
||||||
|
shim_lock_write (void *context __attribute__ ((unused)), void *buf, grub_size_t size)
|
||||||
|
{
|
||||||
|
if (sl->verify (buf, size) != GRUB_EFI_SUCCESS)
|
||||||
|
return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad shim signature"));
|
||||||
|
|
||||||
|
return GRUB_ERR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct grub_file_verifier shim_lock =
|
||||||
|
{
|
||||||
|
.name = "shim_lock",
|
||||||
|
.init = shim_lock_init,
|
||||||
|
.write = shim_lock_write
|
||||||
|
};
|
||||||
|
|
||||||
|
GRUB_MOD_INIT(shim_lock)
|
||||||
|
{
|
||||||
|
sl = grub_efi_locate_protocol (&shim_lock_guid, 0);
|
||||||
|
grub_verifier_register (&shim_lock);
|
||||||
|
|
||||||
|
if (!sl)
|
||||||
|
return;
|
||||||
|
|
||||||
|
grub_dl_set_persistent (mod);
|
||||||
|
}
|
||||||
|
|
||||||
|
GRUB_MOD_FINI(shim_lock)
|
||||||
|
{
|
||||||
|
grub_verifier_unregister (&shim_lock);
|
||||||
|
}
|
Loading…
Reference in a new issue