diff options
author | David Howells <dhowells@redhat.com> | 2017-02-06 06:22:43 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2017-02-07 04:42:10 -0500 |
commit | de8cb458625c164bb3f93c4e415e479afce8fa9d (patch) | |
tree | 6da87e0a45c5d1e39bc5f46413123358734d8eba | |
parent | e58910cdc9f43cda2e52fcdf2fddbdc74e80b2f7 (diff) |
efi: Get and store the secure boot status
Get the firmware's secure-boot status in the kernel boot wrapper and stash
it somewhere that the main kernel image can find.
The efi_get_secureboot() function is extracted from the ARM stub and (a)
generalised so that it can be called from x86 and (b) made to use
efi_call_runtime() so that it can be run in mixed-mode.
For x86, it is stored in boot_params and can be overridden by the boot
loader or kexec. This allows secure-boot mode to be passed on to a new
kernel.
Suggested-by: Lukas Wunner <lukas@wunner.de>
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Matt Fleming <matt@codeblueprint.co.uk>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-efi@vger.kernel.org
Link: http://lkml.kernel.org/r/1486380166-31868-5-git-send-email-ard.biesheuvel@linaro.org
[ Small readability edits. ]
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | Documentation/x86/zero-page.txt | 2 | ||||
-rw-r--r-- | arch/x86/boot/compressed/eboot.c | 7 | ||||
-rw-r--r-- | arch/x86/include/uapi/asm/bootparam.h | 3 | ||||
-rw-r--r-- | arch/x86/kernel/asm-offsets.c | 1 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/Makefile | 2 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/arm-stub.c | 63 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/secureboot.c | 61 | ||||
-rw-r--r-- | include/linux/efi.h | 8 |
8 files changed, 88 insertions, 59 deletions
diff --git a/Documentation/x86/zero-page.txt b/Documentation/x86/zero-page.txt index 95a4d34af3fd..b8527c6b7646 100644 --- a/Documentation/x86/zero-page.txt +++ b/Documentation/x86/zero-page.txt | |||
@@ -31,6 +31,8 @@ Offset Proto Name Meaning | |||
31 | 1E9/001 ALL eddbuf_entries Number of entries in eddbuf (below) | 31 | 1E9/001 ALL eddbuf_entries Number of entries in eddbuf (below) |
32 | 1EA/001 ALL edd_mbr_sig_buf_entries Number of entries in edd_mbr_sig_buffer | 32 | 1EA/001 ALL edd_mbr_sig_buf_entries Number of entries in edd_mbr_sig_buffer |
33 | (below) | 33 | (below) |
34 | 1EB/001 ALL kbd_status Numlock is enabled | ||
35 | 1EC/001 ALL secure_boot Secure boot is enabled in the firmware | ||
34 | 1EF/001 ALL sentinel Used to detect broken bootloaders | 36 | 1EF/001 ALL sentinel Used to detect broken bootloaders |
35 | 290/040 ALL edd_mbr_sig_buffer EDD MBR signatures | 37 | 290/040 ALL edd_mbr_sig_buffer EDD MBR signatures |
36 | 2D0/A00 ALL e820_map E820 memory map table | 38 | 2D0/A00 ALL e820_map E820 memory map table |
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index f99978db6b6f..801c7a158e55 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c | |||
@@ -988,6 +988,13 @@ struct boot_params *efi_main(struct efi_config *c, | |||
988 | else | 988 | else |
989 | setup_boot_services32(efi_early); | 989 | setup_boot_services32(efi_early); |
990 | 990 | ||
991 | /* | ||
992 | * If the boot loader gave us a value for secure_boot then we use that, | ||
993 | * otherwise we ask the BIOS. | ||
994 | */ | ||
995 | if (boot_params->secure_boot == efi_secureboot_mode_unset) | ||
996 | boot_params->secure_boot = efi_get_secureboot(sys_table); | ||
997 | |||
991 | setup_graphics(boot_params); | 998 | setup_graphics(boot_params); |
992 | 999 | ||
993 | setup_efi_pci(boot_params); | 1000 | setup_efi_pci(boot_params); |
diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h index b10bf319ed20..5138dacf8bb8 100644 --- a/arch/x86/include/uapi/asm/bootparam.h +++ b/arch/x86/include/uapi/asm/bootparam.h | |||
@@ -135,7 +135,8 @@ struct boot_params { | |||
135 | __u8 eddbuf_entries; /* 0x1e9 */ | 135 | __u8 eddbuf_entries; /* 0x1e9 */ |
136 | __u8 edd_mbr_sig_buf_entries; /* 0x1ea */ | 136 | __u8 edd_mbr_sig_buf_entries; /* 0x1ea */ |
137 | __u8 kbd_status; /* 0x1eb */ | 137 | __u8 kbd_status; /* 0x1eb */ |
138 | __u8 _pad5[3]; /* 0x1ec */ | 138 | __u8 secure_boot; /* 0x1ec */ |
139 | __u8 _pad5[2]; /* 0x1ed */ | ||
139 | /* | 140 | /* |
140 | * The sentinel is set to a nonzero value (0xff) in header.S. | 141 | * The sentinel is set to a nonzero value (0xff) in header.S. |
141 | * | 142 | * |
diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c index c62e015b126c..de827d6ac8c2 100644 --- a/arch/x86/kernel/asm-offsets.c +++ b/arch/x86/kernel/asm-offsets.c | |||
@@ -81,6 +81,7 @@ void common(void) { | |||
81 | 81 | ||
82 | BLANK(); | 82 | BLANK(); |
83 | OFFSET(BP_scratch, boot_params, scratch); | 83 | OFFSET(BP_scratch, boot_params, scratch); |
84 | OFFSET(BP_secure_boot, boot_params, secure_boot); | ||
84 | OFFSET(BP_loadflags, boot_params, hdr.loadflags); | 85 | OFFSET(BP_loadflags, boot_params, hdr.loadflags); |
85 | OFFSET(BP_hardware_subarch, boot_params, hdr.hardware_subarch); | 86 | OFFSET(BP_hardware_subarch, boot_params, hdr.hardware_subarch); |
86 | OFFSET(BP_version, boot_params, hdr.version); | 87 | OFFSET(BP_version, boot_params, hdr.version); |
diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 33e0e2f1a730..f7425960f6a5 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile | |||
@@ -28,7 +28,7 @@ OBJECT_FILES_NON_STANDARD := y | |||
28 | # Prevents link failures: __sanitizer_cov_trace_pc() is not linked in. | 28 | # Prevents link failures: __sanitizer_cov_trace_pc() is not linked in. |
29 | KCOV_INSTRUMENT := n | 29 | KCOV_INSTRUMENT := n |
30 | 30 | ||
31 | lib-y := efi-stub-helper.o gop.o | 31 | lib-y := efi-stub-helper.o gop.o secureboot.o |
32 | 32 | ||
33 | # include the stub's generic dependencies from lib/ when building for ARM/arm64 | 33 | # include the stub's generic dependencies from lib/ when building for ARM/arm64 |
34 | arm-deps := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c fdt_empty_tree.c fdt_sw.c sort.c | 34 | arm-deps := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c fdt_empty_tree.c fdt_sw.c sort.c |
diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index 6fca48c9e054..d4056c6be1ec 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c | |||
@@ -20,52 +20,6 @@ | |||
20 | 20 | ||
21 | bool __nokaslr; | 21 | bool __nokaslr; |
22 | 22 | ||
23 | static int efi_get_secureboot(efi_system_table_t *sys_table_arg) | ||
24 | { | ||
25 | static efi_char16_t const sb_var_name[] = { | ||
26 | 'S', 'e', 'c', 'u', 'r', 'e', 'B', 'o', 'o', 't', 0 }; | ||
27 | static efi_char16_t const sm_var_name[] = { | ||
28 | 'S', 'e', 't', 'u', 'p', 'M', 'o', 'd', 'e', 0 }; | ||
29 | |||
30 | efi_guid_t var_guid = EFI_GLOBAL_VARIABLE_GUID; | ||
31 | efi_get_variable_t *f_getvar = sys_table_arg->runtime->get_variable; | ||
32 | u8 val; | ||
33 | unsigned long size = sizeof(val); | ||
34 | efi_status_t status; | ||
35 | |||
36 | status = f_getvar((efi_char16_t *)sb_var_name, (efi_guid_t *)&var_guid, | ||
37 | NULL, &size, &val); | ||
38 | |||
39 | if (status != EFI_SUCCESS) | ||
40 | goto out_efi_err; | ||
41 | |||
42 | if (val == 0) | ||
43 | return 0; | ||
44 | |||
45 | status = f_getvar((efi_char16_t *)sm_var_name, (efi_guid_t *)&var_guid, | ||
46 | NULL, &size, &val); | ||
47 | |||
48 | if (status != EFI_SUCCESS) | ||
49 | goto out_efi_err; | ||
50 | |||
51 | if (val == 1) | ||
52 | return 0; | ||
53 | |||
54 | return 1; | ||
55 | |||
56 | out_efi_err: | ||
57 | switch (status) { | ||
58 | case EFI_NOT_FOUND: | ||
59 | return 0; | ||
60 | case EFI_DEVICE_ERROR: | ||
61 | return -EIO; | ||
62 | case EFI_SECURITY_VIOLATION: | ||
63 | return -EACCES; | ||
64 | default: | ||
65 | return -EINVAL; | ||
66 | } | ||
67 | } | ||
68 | |||
69 | efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, | 23 | efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, |
70 | void *__image, void **__fh) | 24 | void *__image, void **__fh) |
71 | { | 25 | { |
@@ -157,7 +111,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, | |||
157 | efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID; | 111 | efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID; |
158 | unsigned long reserve_addr = 0; | 112 | unsigned long reserve_addr = 0; |
159 | unsigned long reserve_size = 0; | 113 | unsigned long reserve_size = 0; |
160 | int secure_boot = 0; | 114 | enum efi_secureboot_mode secure_boot; |
161 | struct screen_info *si; | 115 | struct screen_info *si; |
162 | 116 | ||
163 | /* Check if we were booted by the EFI firmware */ | 117 | /* Check if we were booted by the EFI firmware */ |
@@ -227,19 +181,14 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, | |||
227 | pr_efi_err(sys_table, "Failed to parse EFI cmdline options\n"); | 181 | pr_efi_err(sys_table, "Failed to parse EFI cmdline options\n"); |
228 | 182 | ||
229 | secure_boot = efi_get_secureboot(sys_table); | 183 | secure_boot = efi_get_secureboot(sys_table); |
230 | if (secure_boot > 0) | ||
231 | pr_efi(sys_table, "UEFI Secure Boot is enabled.\n"); | ||
232 | |||
233 | if (secure_boot < 0) { | ||
234 | pr_efi_err(sys_table, | ||
235 | "could not determine UEFI Secure Boot status.\n"); | ||
236 | } | ||
237 | 184 | ||
238 | /* | 185 | /* |
239 | * Unauthenticated device tree data is a security hazard, so | 186 | * Unauthenticated device tree data is a security hazard, so ignore |
240 | * ignore 'dtb=' unless UEFI Secure Boot is disabled. | 187 | * 'dtb=' unless UEFI Secure Boot is disabled. We assume that secure |
188 | * boot is enabled if we can't determine its state. | ||
241 | */ | 189 | */ |
242 | if (secure_boot != 0 && strstr(cmdline_ptr, "dtb=")) { | 190 | if (secure_boot != efi_secureboot_mode_disabled && |
191 | strstr(cmdline_ptr, "dtb=")) { | ||
243 | pr_efi(sys_table, "Ignoring DTB from command line.\n"); | 192 | pr_efi(sys_table, "Ignoring DTB from command line.\n"); |
244 | } else { | 193 | } else { |
245 | status = handle_cmdline_files(sys_table, image, cmdline_ptr, | 194 | status = handle_cmdline_files(sys_table, image, cmdline_ptr, |
diff --git a/drivers/firmware/efi/libstub/secureboot.c b/drivers/firmware/efi/libstub/secureboot.c new file mode 100644 index 000000000000..b20b8b460d77 --- /dev/null +++ b/drivers/firmware/efi/libstub/secureboot.c | |||
@@ -0,0 +1,61 @@ | |||
1 | /* | ||
2 | * Secure boot handling. | ||
3 | * | ||
4 | * Copyright (C) 2013,2014 Linaro Limited | ||
5 | * Roy Franz <roy.franz@linaro.org | ||
6 | * Copyright (C) 2013 Red Hat, Inc. | ||
7 | * Mark Salter <msalter@redhat.com> | ||
8 | * | ||
9 | * This file is part of the Linux kernel, and is made available under the | ||
10 | * terms of the GNU General Public License version 2. | ||
11 | */ | ||
12 | #include <linux/efi.h> | ||
13 | #include <asm/efi.h> | ||
14 | |||
15 | /* BIOS variables */ | ||
16 | static const efi_guid_t efi_variable_guid = EFI_GLOBAL_VARIABLE_GUID; | ||
17 | static const efi_char16_t const efi_SecureBoot_name[] = { | ||
18 | 'S', 'e', 'c', 'u', 'r', 'e', 'B', 'o', 'o', 't', 0 | ||
19 | }; | ||
20 | static const efi_char16_t const efi_SetupMode_name[] = { | ||
21 | 'S', 'e', 't', 'u', 'p', 'M', 'o', 'd', 'e', 0 | ||
22 | }; | ||
23 | |||
24 | #define get_efi_var(name, vendor, ...) \ | ||
25 | efi_call_runtime(get_variable, \ | ||
26 | (efi_char16_t *)(name), (efi_guid_t *)(vendor), \ | ||
27 | __VA_ARGS__); | ||
28 | |||
29 | /* | ||
30 | * Determine whether we're in secure boot mode. | ||
31 | */ | ||
32 | enum efi_secureboot_mode efi_get_secureboot(efi_system_table_t *sys_table_arg) | ||
33 | { | ||
34 | u8 secboot, setupmode; | ||
35 | unsigned long size; | ||
36 | efi_status_t status; | ||
37 | |||
38 | size = sizeof(secboot); | ||
39 | status = get_efi_var(efi_SecureBoot_name, &efi_variable_guid, | ||
40 | NULL, &size, &secboot); | ||
41 | if (status != EFI_SUCCESS) | ||
42 | goto out_efi_err; | ||
43 | |||
44 | size = sizeof(setupmode); | ||
45 | status = get_efi_var(efi_SetupMode_name, &efi_variable_guid, | ||
46 | NULL, &size, &setupmode); | ||
47 | if (status != EFI_SUCCESS) | ||
48 | goto out_efi_err; | ||
49 | |||
50 | if (secboot == 0 || setupmode == 1) | ||
51 | return efi_secureboot_mode_disabled; | ||
52 | |||
53 | pr_efi(sys_table_arg, "UEFI Secure Boot is enabled.\n"); | ||
54 | return efi_secureboot_mode_enabled; | ||
55 | |||
56 | out_efi_err: | ||
57 | pr_efi_err(sys_table_arg, "Could not determine UEFI Secure Boot status.\n"); | ||
58 | if (status == EFI_NOT_FOUND) | ||
59 | return efi_secureboot_mode_disabled; | ||
60 | return efi_secureboot_mode_unknown; | ||
61 | } | ||
diff --git a/include/linux/efi.h b/include/linux/efi.h index d00538a65899..94d34e0be24f 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h | |||
@@ -1480,6 +1480,14 @@ efi_status_t efi_setup_gop(efi_system_table_t *sys_table_arg, | |||
1480 | bool efi_runtime_disabled(void); | 1480 | bool efi_runtime_disabled(void); |
1481 | extern void efi_call_virt_check_flags(unsigned long flags, const char *call); | 1481 | extern void efi_call_virt_check_flags(unsigned long flags, const char *call); |
1482 | 1482 | ||
1483 | enum efi_secureboot_mode { | ||
1484 | efi_secureboot_mode_unset, | ||
1485 | efi_secureboot_mode_unknown, | ||
1486 | efi_secureboot_mode_disabled, | ||
1487 | efi_secureboot_mode_enabled, | ||
1488 | }; | ||
1489 | enum efi_secureboot_mode efi_get_secureboot(efi_system_table_t *sys_table); | ||
1490 | |||
1483 | /* | 1491 | /* |
1484 | * Arch code can implement the following three template macros, avoiding | 1492 | * Arch code can implement the following three template macros, avoiding |
1485 | * reptition for the void/non-void return cases of {__,}efi_call_virt(): | 1493 | * reptition for the void/non-void return cases of {__,}efi_call_virt(): |