Merge tag 'efi_updates_for_v5.11' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 24 Dec 2020 20:40:07 +0000 (12:40 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 24 Dec 2020 20:40:07 +0000 (12:40 -0800)
Pull EFI updates from Borislav Petkov:
 "These got delayed due to a last minute ia64 build issue which got
  fixed in the meantime.

  EFI updates collected by Ard Biesheuvel:

   - Don't move BSS section around pointlessly in the x86 decompressor

   - Refactor helper for discovering the EFI secure boot mode

   - Wire up EFI secure boot to IMA for arm64

   - Some fixes for the capsule loader

   - Expose the RT_PROP table via the EFI test module

   - Relax DT and kernel placement restrictions on ARM

  with a few followup fixes:

   - fix the build breakage on IA64 caused by recent capsule loader
     changes

   - suppress a type mismatch build warning in the expansion of
     EFI_PHYS_ALIGN on ARM"

* tag 'efi_updates_for_v5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  efi: arm: force use of unsigned type for EFI_PHYS_ALIGN
  efi: ia64: disable the capsule loader
  efi: stub: get rid of efi_get_max_fdt_addr()
  efi/efi_test: read RuntimeServicesSupported
  efi: arm: reduce minimum alignment of uncompressed kernel
  efi: capsule: clean scatter-gather entries from the D-cache
  efi: capsule: use atomic kmap for transient sglist mappings
  efi: x86/xen: switch to efi_get_secureboot_mode helper
  arm64/ima: add ima_arch support
  ima: generalize x86/EFI arch glue for other EFI architectures
  efi: generalize efi_get_secureboot
  efi/libstub: EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER should not default to yes
  efi/x86: Only copy the compressed kernel image in efi_relocate_kernel()
  efi/libstub/x86: simplify efi_is_native()

22 files changed:
arch/arm/include/asm/efi.h
arch/arm64/Kconfig
arch/arm64/include/asm/efi.h
arch/riscv/include/asm/efi.h
arch/x86/boot/compressed/Makefile
arch/x86/include/asm/efi.h
arch/x86/kernel/Makefile
arch/x86/kernel/ima_arch.c [deleted file]
arch/x86/xen/efi.c
drivers/firmware/efi/Kconfig
drivers/firmware/efi/Makefile
drivers/firmware/efi/capsule.c
drivers/firmware/efi/libstub/efi-stub.c
drivers/firmware/efi/libstub/efistub.h
drivers/firmware/efi/libstub/fdt.c
drivers/firmware/efi/libstub/secureboot.c
drivers/firmware/efi/libstub/x86-stub.c
drivers/firmware/efi/test/efi_test.c
drivers/firmware/efi/test/efi_test.h
include/linux/efi.h
security/integrity/ima/Makefile
security/integrity/ima/ima_efi.c [new file with mode: 0644]

index 3ee4f43..9de7ab2 100644 (file)
@@ -66,24 +66,17 @@ static inline void efifb_setup_from_dmi(struct screen_info *si, const char *opt)
 #define MAX_UNCOMP_KERNEL_SIZE SZ_32M
 
 /*
- * phys-to-virt patching requires that the physical to virtual offset fits
- * into the immediate field of an add/sub instruction, which comes down to the
- * 24 least significant bits being zero, and so the offset should be a multiple
- * of 16 MB. Since PAGE_OFFSET itself is a multiple of 16 MB, the physical
- * base should be aligned to 16 MB as well.
+ * phys-to-virt patching requires that the physical to virtual offset is a
+ * multiple of 2 MiB. However, using an alignment smaller than TEXT_OFFSET
+ * here throws off the memory allocation logic, so let's use the lowest power
+ * of two greater than 2 MiB and greater than TEXT_OFFSET.
  */
-#define EFI_PHYS_ALIGN         SZ_16M
-
-/* on ARM, the FDT should be located in a lowmem region */
-static inline unsigned long efi_get_max_fdt_addr(unsigned long image_addr)
-{
-       return round_down(image_addr, EFI_PHYS_ALIGN) + SZ_512M;
-}
+#define EFI_PHYS_ALIGN         max(UL(SZ_2M), roundup_pow_of_two(TEXT_OFFSET))
 
 /* on ARM, the initrd should be loaded in a lowmem region */
 static inline unsigned long efi_get_max_initrd_addr(unsigned long image_addr)
 {
-       return round_down(image_addr, EFI_PHYS_ALIGN) + SZ_512M;
+       return round_down(image_addr, SZ_4M) + SZ_512M;
 }
 
 struct efi_arm_entry_state {
@@ -93,4 +86,9 @@ struct efi_arm_entry_state {
        u32     sctlr_after_ebs;
 };
 
+static inline void efi_capsule_flush_cache_range(void *addr, int size)
+{
+       __cpuc_flush_dcache_area(addr, size);
+}
+
 #endif /* _ASM_ARM_EFI_H */
index d0d94f7..05e1735 100644 (file)
@@ -1877,6 +1877,7 @@ config EFI
        select EFI_RUNTIME_WRAPPERS
        select EFI_STUB
        select EFI_GENERIC_STUB
+       imply IMA_SECURE_AND_OR_TRUSTED_BOOT
        default y
        help
          This option provides support for runtime services provided
index 973b144..3578aba 100644 (file)
@@ -64,12 +64,6 @@ efi_status_t __efi_rt_asm_wrapper(void *, const char *, ...);
 #define EFI_KIMG_ALIGN \
        (SEGMENT_ALIGN > THREAD_ALIGN ? SEGMENT_ALIGN : THREAD_ALIGN)
 
-/* on arm64, the FDT may be located anywhere in system RAM */
-static inline unsigned long efi_get_max_fdt_addr(unsigned long image_addr)
-{
-       return ULONG_MAX;
-}
-
 /*
  * On arm64, we have to ensure that the initrd ends up in the linear region,
  * which is a 1 GB aligned region of size '1UL << (VA_BITS_MIN - 1)' that is
@@ -141,4 +135,9 @@ static inline void efi_set_pgd(struct mm_struct *mm)
 void efi_virtmap_load(void);
 void efi_virtmap_unload(void);
 
+static inline void efi_capsule_flush_cache_range(void *addr, int size)
+{
+       __flush_dcache_area(addr, size);
+}
+
 #endif /* _ASM_EFI_H */
index 7542282..6d98cd9 100644 (file)
@@ -27,12 +27,6 @@ int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md);
 
 #define ARCH_EFI_IRQ_FLAGS_MASK (SR_IE | SR_SPIE)
 
-/* on RISC-V, the FDT may be located anywhere in system RAM */
-static inline unsigned long efi_get_max_fdt_addr(unsigned long image_addr)
-{
-       return ULONG_MAX;
-}
-
 /* Load initrd at enough distance from DRAM start */
 static inline unsigned long efi_get_max_initrd_addr(unsigned long image_addr)
 {
index 40b8fd3..e0bc398 100644 (file)
@@ -35,7 +35,7 @@ cflags-$(CONFIG_X86_32) := -march=i386
 cflags-$(CONFIG_X86_64) := -mcmodel=small -mno-red-zone
 KBUILD_CFLAGS += $(cflags-y)
 KBUILD_CFLAGS += -mno-mmx -mno-sse
-KBUILD_CFLAGS += -ffreestanding
+KBUILD_CFLAGS += -ffreestanding -fshort-wchar
 KBUILD_CFLAGS += -fno-stack-protector
 KBUILD_CFLAGS += $(call cc-disable-warning, address-of-packed-member)
 KBUILD_CFLAGS += $(call cc-disable-warning, gnu)
index bc9758e..c98f783 100644 (file)
@@ -213,8 +213,6 @@ static inline bool efi_is_64bit(void)
 
 static inline bool efi_is_native(void)
 {
-       if (!IS_ENABLED(CONFIG_X86_64))
-               return true;
        return efi_is_64bit();
 }
 
@@ -382,4 +380,7 @@ static inline void efi_fake_memmap_early(void)
 }
 #endif
 
+#define arch_ima_efi_boot_mode \
+       ({ extern struct boot_params boot_params; boot_params.secure_boot; })
+
 #endif /* _ASM_X86_EFI_H */
index 68608bd..5eeb808 100644 (file)
@@ -161,5 +161,3 @@ ifeq ($(CONFIG_X86_64),y)
        obj-$(CONFIG_MMCONF_FAM10H)     += mmconf-fam10h_64.o
        obj-y                           += vsmp_64.o
 endif
-
-obj-$(CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT)   += ima_arch.o
diff --git a/arch/x86/kernel/ima_arch.c b/arch/x86/kernel/ima_arch.c
deleted file mode 100644 (file)
index 7dfb1e8..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Copyright (C) 2018 IBM Corporation
- */
-#include <linux/efi.h>
-#include <linux/module.h>
-#include <linux/ima.h>
-
-extern struct boot_params boot_params;
-
-static enum efi_secureboot_mode get_sb_mode(void)
-{
-       efi_guid_t efi_variable_guid = EFI_GLOBAL_VARIABLE_GUID;
-       efi_status_t status;
-       unsigned long size;
-       u8 secboot, setupmode;
-
-       size = sizeof(secboot);
-
-       if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE)) {
-               pr_info("ima: secureboot mode unknown, no efi\n");
-               return efi_secureboot_mode_unknown;
-       }
-
-       /* Get variable contents into buffer */
-       status = efi.get_variable(L"SecureBoot", &efi_variable_guid,
-                                 NULL, &size, &secboot);
-       if (status == EFI_NOT_FOUND) {
-               pr_info("ima: secureboot mode disabled\n");
-               return efi_secureboot_mode_disabled;
-       }
-
-       if (status != EFI_SUCCESS) {
-               pr_info("ima: secureboot mode unknown\n");
-               return efi_secureboot_mode_unknown;
-       }
-
-       size = sizeof(setupmode);
-       status = efi.get_variable(L"SetupMode", &efi_variable_guid,
-                                 NULL, &size, &setupmode);
-
-       if (status != EFI_SUCCESS)      /* ignore unknown SetupMode */
-               setupmode = 0;
-
-       if (secboot == 0 || setupmode == 1) {
-               pr_info("ima: secureboot mode disabled\n");
-               return efi_secureboot_mode_disabled;
-       }
-
-       pr_info("ima: secureboot mode enabled\n");
-       return efi_secureboot_mode_enabled;
-}
-
-bool arch_ima_get_secureboot(void)
-{
-       static enum efi_secureboot_mode sb_mode;
-       static bool initialized;
-
-       if (!initialized && efi_enabled(EFI_BOOT)) {
-               sb_mode = boot_params.secure_boot;
-
-               if (sb_mode == efi_secureboot_mode_unset)
-                       sb_mode = get_sb_mode();
-               initialized = true;
-       }
-
-       if (sb_mode == efi_secureboot_mode_enabled)
-               return true;
-       else
-               return false;
-}
-
-/* secureboot arch rules */
-static const char * const sb_arch_rules[] = {
-#if !IS_ENABLED(CONFIG_KEXEC_SIG)
-       "appraise func=KEXEC_KERNEL_CHECK appraise_type=imasig",
-#endif /* CONFIG_KEXEC_SIG */
-       "measure func=KEXEC_KERNEL_CHECK",
-#if !IS_ENABLED(CONFIG_MODULE_SIG)
-       "appraise func=MODULE_CHECK appraise_type=imasig",
-#endif
-       "measure func=MODULE_CHECK",
-       NULL
-};
-
-const char * const *arch_get_ima_policy(void)
-{
-       if (IS_ENABLED(CONFIG_IMA_ARCH_POLICY) && arch_ima_get_secureboot()) {
-               if (IS_ENABLED(CONFIG_MODULE_SIG))
-                       set_module_sig_enforced();
-               return sb_arch_rules;
-       }
-       return NULL;
-}
index 205a9bc..7d7ffb9 100644 (file)
@@ -93,37 +93,22 @@ static efi_system_table_t __init *xen_efi_probe(void)
 
 /*
  * Determine whether we're in secure boot mode.
- *
- * Please keep the logic in sync with
- * drivers/firmware/efi/libstub/secureboot.c:efi_get_secureboot().
  */
 static enum efi_secureboot_mode xen_efi_get_secureboot(void)
 {
-       static efi_guid_t efi_variable_guid = EFI_GLOBAL_VARIABLE_GUID;
        static efi_guid_t shim_guid = EFI_SHIM_LOCK_GUID;
+       enum efi_secureboot_mode mode;
        efi_status_t status;
-       u8 moksbstate, secboot, setupmode;
+       u8 moksbstate;
        unsigned long size;
 
-       size = sizeof(secboot);
-       status = efi.get_variable(L"SecureBoot", &efi_variable_guid,
-                                 NULL, &size, &secboot);
-
-       if (status == EFI_NOT_FOUND)
-               return efi_secureboot_mode_disabled;
-
-       if (status != EFI_SUCCESS)
-               goto out_efi_err;
-
-       size = sizeof(setupmode);
-       status = efi.get_variable(L"SetupMode", &efi_variable_guid,
-                                 NULL, &size, &setupmode);
-
-       if (status != EFI_SUCCESS)
-               goto out_efi_err;
-
-       if (secboot == 0 || setupmode == 1)
-               return efi_secureboot_mode_disabled;
+       mode = efi_get_secureboot_mode(efi.get_variable);
+       if (mode == efi_secureboot_mode_unknown) {
+               pr_err("Could not determine UEFI Secure Boot status.\n");
+               return efi_secureboot_mode_unknown;
+       }
+       if (mode != efi_secureboot_mode_enabled)
+               return mode;
 
        /* See if a user has put the shim into insecure mode. */
        size = sizeof(moksbstate);
@@ -140,10 +125,6 @@ static enum efi_secureboot_mode xen_efi_get_secureboot(void)
  secure_boot_enabled:
        pr_info("UEFI Secure Boot is enabled.\n");
        return efi_secureboot_mode_enabled;
-
- out_efi_err:
-       pr_err("Could not determine UEFI Secure Boot status.\n");
-       return efi_secureboot_mode_unknown;
 }
 
 void __init xen_efi_init(struct boot_params *boot_params)
index d989549..2c3dac5 100644 (file)
@@ -122,7 +122,7 @@ config EFI_ARMSTUB_DTB_LOADER
 config EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER
        bool "Enable the command line initrd loader" if !X86
        depends on EFI_STUB && (EFI_GENERIC_STUB || X86)
-       default y
+       default y if X86
        depends on !RISCV
        help
          Select this config option to add support for the initrd= command
@@ -147,7 +147,7 @@ config EFI_BOOTLOADER_CONTROL
 
 config EFI_CAPSULE_LOADER
        tristate "EFI capsule loader"
-       depends on EFI
+       depends on EFI && !IA64
        help
          This option exposes a loader interface "/dev/efi_capsule_loader" for
          users to load EFI capsules. This driver requires working runtime
index d6ca2da..467e942 100644 (file)
@@ -12,7 +12,10 @@ KASAN_SANITIZE_runtime-wrappers.o    := n
 
 obj-$(CONFIG_ACPI_BGRT)                += efi-bgrt.o
 obj-$(CONFIG_EFI)                      += efi.o vars.o reboot.o memattr.o tpm.o
-obj-$(CONFIG_EFI)                      += capsule.o memmap.o
+obj-$(CONFIG_EFI)                      += memmap.o
+ifneq ($(CONFIG_EFI_CAPSULE_LOADER),)
+obj-$(CONFIG_EFI)                      += capsule.o
+endif
 obj-$(CONFIG_EFI_PARAMS_FROM_FDT)      += fdtparams.o
 obj-$(CONFIG_EFI_VARS)                 += efivars.o
 obj-$(CONFIG_EFI_ESRT)                 += esrt.o
index 598b780..7684302 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/highmem.h>
 #include <linux/efi.h>
 #include <linux/vmalloc.h>
+#include <asm/efi.h>
 #include <asm/io.h>
 
 typedef struct {
@@ -244,7 +245,7 @@ int efi_capsule_update(efi_capsule_header_t *capsule, phys_addr_t *pages)
        for (i = 0; i < sg_count; i++) {
                efi_capsule_block_desc_t *sglist;
 
-               sglist = kmap(sg_pages[i]);
+               sglist = kmap_atomic(sg_pages[i]);
 
                for (j = 0; j < SGLIST_PER_PAGE && count > 0; j++) {
                        u64 sz = min_t(u64, imagesize,
@@ -265,7 +266,18 @@ int efi_capsule_update(efi_capsule_header_t *capsule, phys_addr_t *pages)
                else
                        sglist[j].data = page_to_phys(sg_pages[i + 1]);
 
-               kunmap(sg_pages[i]);
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+               /*
+                * At runtime, the firmware has no way to find out where the
+                * sglist elements are mapped, if they are mapped in the first
+                * place. Therefore, on architectures that can only perform
+                * cache maintenance by virtual address, the firmware is unable
+                * to perform this maintenance, and so it is up to the OS to do
+                * it instead.
+                */
+               efi_capsule_flush_cache_range(sglist, PAGE_SIZE);
+#endif
+               kunmap_atomic(sglist);
        }
 
        mutex_lock(&capsule_mutex);
index 914a343..ec2f398 100644 (file)
@@ -273,7 +273,6 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
        install_memreserve_table();
 
        status = allocate_new_fdt_and_exit_boot(handle, &fdt_addr,
-                                               efi_get_max_fdt_addr(image_addr),
                                                initrd_addr, initrd_size,
                                                cmdline_ptr, fdt_addr, fdt_size);
        if (status != EFI_SUCCESS)
index 2d7abcd..b50a6c6 100644 (file)
@@ -750,7 +750,6 @@ efi_status_t efi_exit_boot_services(void *handle,
 
 efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
                                            unsigned long *new_fdt_addr,
-                                           unsigned long max_addr,
                                            u64 initrd_addr, u64 initrd_size,
                                            char *cmdline_ptr,
                                            unsigned long fdt_addr,
@@ -848,4 +847,6 @@ asmlinkage void __noreturn efi_enter_kernel(unsigned long entrypoint,
 
 void efi_handle_post_ebs_state(void);
 
+enum efi_secureboot_mode efi_get_secureboot(void);
+
 #endif
index 368cd60..365c3a4 100644 (file)
@@ -238,7 +238,6 @@ static efi_status_t exit_boot_func(struct efi_boot_memmap *map,
 
 efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
                                            unsigned long *new_fdt_addr,
-                                           unsigned long max_addr,
                                            u64 initrd_addr, u64 initrd_size,
                                            char *cmdline_ptr,
                                            unsigned long fdt_addr,
@@ -275,7 +274,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
        efi_info("Exiting boot services and installing virtual address map...\n");
 
        map.map = &memory_map;
-       status = efi_allocate_pages(MAX_FDT_SIZE, new_fdt_addr, max_addr);
+       status = efi_allocate_pages(MAX_FDT_SIZE, new_fdt_addr, ULONG_MAX);
        if (status != EFI_SUCCESS) {
                efi_err("Unable to allocate memory for new device tree.\n");
                goto fail;
index 5efc524..8a18930 100644 (file)
 
 #include "efistub.h"
 
-/* BIOS variables */
-static const efi_guid_t efi_variable_guid = EFI_GLOBAL_VARIABLE_GUID;
-static const efi_char16_t efi_SecureBoot_name[] = L"SecureBoot";
-static const efi_char16_t efi_SetupMode_name[] = L"SetupMode";
-
 /* SHIM variables */
 static const efi_guid_t shim_guid = EFI_SHIM_LOCK_GUID;
 static const efi_char16_t shim_MokSBState_name[] = L"MokSBState";
 
+static efi_status_t get_var(efi_char16_t *name, efi_guid_t *vendor, u32 *attr,
+                           unsigned long *data_size, void *data)
+{
+       return get_efi_var(name, vendor, attr, data_size, data);
+}
+
 /*
  * Determine whether we're in secure boot mode.
- *
- * Please keep the logic in sync with
- * arch/x86/xen/efi.c:xen_efi_get_secureboot().
  */
 enum efi_secureboot_mode efi_get_secureboot(void)
 {
        u32 attr;
-       u8 secboot, setupmode, moksbstate;
        unsigned long size;
+       enum efi_secureboot_mode mode;
        efi_status_t status;
+       u8 moksbstate;
 
-       size = sizeof(secboot);
-       status = get_efi_var(efi_SecureBoot_name, &efi_variable_guid,
-                            NULL, &size, &secboot);
-       if (status == EFI_NOT_FOUND)
-               return efi_secureboot_mode_disabled;
-       if (status != EFI_SUCCESS)
-               goto out_efi_err;
-
-       size = sizeof(setupmode);
-       status = get_efi_var(efi_SetupMode_name, &efi_variable_guid,
-                            NULL, &size, &setupmode);
-       if (status != EFI_SUCCESS)
-               goto out_efi_err;
-
-       if (secboot == 0 || setupmode == 1)
-               return efi_secureboot_mode_disabled;
+       mode = efi_get_secureboot_mode(get_var);
+       if (mode == efi_secureboot_mode_unknown) {
+               efi_err("Could not determine UEFI Secure Boot status.\n");
+               return efi_secureboot_mode_unknown;
+       }
+       if (mode != efi_secureboot_mode_enabled)
+               return mode;
 
        /*
         * See if a user has put the shim into insecure mode. If so, and if the
@@ -69,8 +59,4 @@ enum efi_secureboot_mode efi_get_secureboot(void)
 secure_boot_enabled:
        efi_info("UEFI Secure Boot is enabled.\n");
        return efi_secureboot_mode_enabled;
-
-out_efi_err:
-       efi_err("Could not determine UEFI Secure Boot status.\n");
-       return efi_secureboot_mode_unknown;
 }
index 3672539..f14c4ff 100644 (file)
@@ -715,8 +715,11 @@ unsigned long efi_main(efi_handle_t handle,
            (IS_ENABLED(CONFIG_X86_32) && buffer_end > KERNEL_IMAGE_SIZE)    ||
            (IS_ENABLED(CONFIG_X86_64) && buffer_end > MAXMEM_X86_64_4LEVEL) ||
            (image_offset == 0)) {
+               extern char _bss[];
+
                status = efi_relocate_kernel(&bzimage_addr,
-                                            hdr->init_size, hdr->init_size,
+                                            (unsigned long)_bss - bzimage_addr,
+                                            hdr->init_size,
                                             hdr->pref_address,
                                             hdr->kernel_alignment,
                                             LOAD_PHYSICAL_ADDR);
index ddf9eae..47d67bb 100644 (file)
@@ -663,6 +663,19 @@ out:
        return rv;
 }
 
+static long efi_runtime_get_supported_mask(unsigned long arg)
+{
+       unsigned int __user *supported_mask;
+       int rv = 0;
+
+       supported_mask = (unsigned int *)arg;
+
+       if (put_user(efi.runtime_supported_mask, supported_mask))
+               rv = -EFAULT;
+
+       return rv;
+}
+
 static long efi_test_ioctl(struct file *file, unsigned int cmd,
                                                        unsigned long arg)
 {
@@ -699,6 +712,9 @@ static long efi_test_ioctl(struct file *file, unsigned int cmd,
 
        case EFI_RUNTIME_RESET_SYSTEM:
                return efi_runtime_reset_system(arg);
+
+       case EFI_RUNTIME_GET_SUPPORTED_MASK:
+               return efi_runtime_get_supported_mask(arg);
        }
 
        return -ENOTTY;
index f2446aa..117349e 100644 (file)
@@ -118,4 +118,7 @@ struct efi_resetsystem {
 #define EFI_RUNTIME_RESET_SYSTEM \
        _IOW('p', 0x0B, struct efi_resetsystem)
 
+#define EFI_RUNTIME_GET_SUPPORTED_MASK \
+       _IOR('p', 0x0C, unsigned int)
+
 #endif /* _DRIVERS_FIRMWARE_EFI_TEST_H_ */
index d7c0e73..763b816 100644 (file)
@@ -817,12 +817,6 @@ static inline bool efi_enabled(int feature)
 static inline void
 efi_reboot(enum reboot_mode reboot_mode, const char *__unused) {}
 
-static inline bool
-efi_capsule_pending(int *reset_type)
-{
-       return false;
-}
-
 static inline bool efi_soft_reserve_enabled(void)
 {
        return false;
@@ -1038,6 +1032,7 @@ bool efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data,
 bool efivar_variable_is_removable(efi_guid_t vendor, const char *name,
                                  size_t len);
 
+#if IS_ENABLED(CONFIG_EFI_CAPSULE_LOADER)
 extern bool efi_capsule_pending(int *reset_type);
 
 extern int efi_capsule_supported(efi_guid_t guid, u32 flags,
@@ -1045,6 +1040,9 @@ extern int efi_capsule_supported(efi_guid_t guid, u32 flags,
 
 extern int efi_capsule_update(efi_capsule_header_t *capsule,
                              phys_addr_t *pages);
+#else
+static inline bool efi_capsule_pending(int *reset_type) { return false; }
+#endif
 
 #ifdef CONFIG_EFI_RUNTIME_MAP
 int efi_runtime_map_init(struct kobject *);
@@ -1089,7 +1087,28 @@ enum efi_secureboot_mode {
        efi_secureboot_mode_disabled,
        efi_secureboot_mode_enabled,
 };
-enum efi_secureboot_mode efi_get_secureboot(void);
+
+static inline
+enum efi_secureboot_mode efi_get_secureboot_mode(efi_get_variable_t *get_var)
+{
+       u8 secboot, setupmode = 0;
+       efi_status_t status;
+       unsigned long size;
+
+       size = sizeof(secboot);
+       status = get_var(L"SecureBoot", &EFI_GLOBAL_VARIABLE_GUID, NULL, &size,
+                        &secboot);
+       if (status == EFI_NOT_FOUND)
+               return efi_secureboot_mode_disabled;
+       if (status != EFI_SUCCESS)
+               return efi_secureboot_mode_unknown;
+
+       size = sizeof(setupmode);
+       get_var(L"SetupMode", &EFI_GLOBAL_VARIABLE_GUID, NULL, &size, &setupmode);
+       if (secboot == 0 || setupmode == 1)
+               return efi_secureboot_mode_disabled;
+       return efi_secureboot_mode_enabled;
+}
 
 #ifdef CONFIG_RESET_ATTACK_MITIGATION
 void efi_enable_reset_attack_mitigation(void);
index 67dabca..2499f24 100644 (file)
@@ -14,3 +14,7 @@ ima-$(CONFIG_HAVE_IMA_KEXEC) += ima_kexec.o
 ima-$(CONFIG_IMA_BLACKLIST_KEYRING) += ima_mok.o
 ima-$(CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS) += ima_asymmetric_keys.o
 ima-$(CONFIG_IMA_QUEUE_EARLY_BOOT_KEYS) += ima_queue_keys.o
+
+ifeq ($(CONFIG_EFI),y)
+ima-$(CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT) += ima_efi.o
+endif
diff --git a/security/integrity/ima/ima_efi.c b/security/integrity/ima/ima_efi.c
new file mode 100644 (file)
index 0000000..71786d0
--- /dev/null
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2018 IBM Corporation
+ */
+#include <linux/efi.h>
+#include <linux/module.h>
+#include <linux/ima.h>
+#include <asm/efi.h>
+
+#ifndef arch_ima_efi_boot_mode
+#define arch_ima_efi_boot_mode efi_secureboot_mode_unset
+#endif
+
+static enum efi_secureboot_mode get_sb_mode(void)
+{
+       enum efi_secureboot_mode mode;
+
+       if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE)) {
+               pr_info("ima: secureboot mode unknown, no efi\n");
+               return efi_secureboot_mode_unknown;
+       }
+
+       mode = efi_get_secureboot_mode(efi.get_variable);
+       if (mode == efi_secureboot_mode_disabled)
+               pr_info("ima: secureboot mode disabled\n");
+       else if (mode == efi_secureboot_mode_unknown)
+               pr_info("ima: secureboot mode unknown\n");
+       else
+               pr_info("ima: secureboot mode enabled\n");
+       return mode;
+}
+
+bool arch_ima_get_secureboot(void)
+{
+       static enum efi_secureboot_mode sb_mode;
+       static bool initialized;
+
+       if (!initialized && efi_enabled(EFI_BOOT)) {
+               sb_mode = arch_ima_efi_boot_mode;
+
+               if (sb_mode == efi_secureboot_mode_unset)
+                       sb_mode = get_sb_mode();
+               initialized = true;
+       }
+
+       if (sb_mode == efi_secureboot_mode_enabled)
+               return true;
+       else
+               return false;
+}
+
+/* secureboot arch rules */
+static const char * const sb_arch_rules[] = {
+#if !IS_ENABLED(CONFIG_KEXEC_SIG)
+       "appraise func=KEXEC_KERNEL_CHECK appraise_type=imasig",
+#endif /* CONFIG_KEXEC_SIG */
+       "measure func=KEXEC_KERNEL_CHECK",
+#if !IS_ENABLED(CONFIG_MODULE_SIG)
+       "appraise func=MODULE_CHECK appraise_type=imasig",
+#endif
+       "measure func=MODULE_CHECK",
+       NULL
+};
+
+const char * const *arch_get_ima_policy(void)
+{
+       if (IS_ENABLED(CONFIG_IMA_ARCH_POLICY) && arch_ima_get_secureboot()) {
+               if (IS_ENABLED(CONFIG_MODULE_SIG))
+                       set_module_sig_enforced();
+               return sb_arch_rules;
+       }
+       return NULL;
+}