/* * 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 . * * EFI shim lock verifier. */ #include #include #include #include #include #include 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); }