diff --git a/docs/grub.texi b/docs/grub.texi
index 2adfa97be..471d97c95 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -5544,6 +5544,7 @@ environment variables and commands are listed in the same order.
@menu
* Authentication and authorisation:: Users and access control
* Using digital signatures:: Booting digitally signed code
+* UEFI secure boot and shim:: Booting digitally signed PE files
@end menu
@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
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
@chapter Platform limitations
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 7904f8542..6e2cc8444 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -899,6 +899,12 @@ module = {
common = commands/verifiers.c;
};
+module = {
+ name = shim_lock;
+ common = commands/efi/shim_lock.c;
+ enable = x86_64_efi;
+};
+
module = {
name = hdparm;
common = commands/hdparm.c;
diff --git a/grub-core/commands/efi/shim_lock.c b/grub-core/commands/efi/shim_lock.c
new file mode 100644
index 000000000..01246b0fc
--- /dev/null
+++ b/grub-core/commands/efi/shim_lock.c
@@ -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 .
+ *
+ * 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);
+}