summaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorJosh Boyer <jwboyer@fedoraproject.org>2018-12-12 15:07:56 -0500
committerMimi Zohar <zohar@linux.ibm.com>2018-12-12 22:04:33 -0500
commit15ea0e1e3e185040bed6119f815096f2e4326242 (patch)
treecc0ecb830489dc77ffcec87b2500ac9aa540b31f /security
parent0bc9ae395b3f3b6557f0c5f0a0b0cd2fd5c00a04 (diff)
efi: Import certificates from UEFI Secure Boot
Secure Boot stores a list of allowed certificates in the 'db' variable. This patch imports those certificates into the platform keyring. The shim UEFI bootloader has a similar certificate list stored in the 'MokListRT' variable. We import those as well. Secure Boot also maintains a list of disallowed certificates in the 'dbx' variable. We load those certificates into the system blacklist keyring and forbid any kernel signed with those from loading. [zohar@linux.ibm.com: dropped Josh's original patch description] Signed-off-by: Josh Boyer <jwboyer@fedoraproject.org> Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Nayna Jain <nayna@linux.ibm.com> Acked-by: Serge Hallyn <serge@hallyn.com> Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
Diffstat (limited to 'security')
-rw-r--r--security/integrity/Makefile5
-rw-r--r--security/integrity/platform_certs/load_uefi.c169
2 files changed, 173 insertions, 1 deletions
diff --git a/security/integrity/Makefile b/security/integrity/Makefile
index 6ee9058866cd..86df9aba8c0f 100644
--- a/security/integrity/Makefile
+++ b/security/integrity/Makefile
@@ -10,7 +10,10 @@ integrity-$(CONFIG_INTEGRITY_AUDIT) += integrity_audit.o
10integrity-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o 10integrity-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o
11integrity-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o 11integrity-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o
12integrity-$(CONFIG_INTEGRITY_PLATFORM_KEYRING) += platform_certs/platform_keyring.o \ 12integrity-$(CONFIG_INTEGRITY_PLATFORM_KEYRING) += platform_certs/platform_keyring.o \
13 platform_certs/efi_parser.o 13 platform_certs/efi_parser.o \
14 platform_certs/load_uefi.o
15obj-$(CONFIG_LOAD_UEFI_KEYS) += platform_certs/load_uefi.o
16$(obj)/load_uefi.o: KBUILD_CFLAGS += -fshort-wchar
14 17
15subdir-$(CONFIG_IMA) += ima 18subdir-$(CONFIG_IMA) += ima
16obj-$(CONFIG_IMA) += ima/ 19obj-$(CONFIG_IMA) += ima/
diff --git a/security/integrity/platform_certs/load_uefi.c b/security/integrity/platform_certs/load_uefi.c
new file mode 100644
index 000000000000..8ceafa58d98c
--- /dev/null
+++ b/security/integrity/platform_certs/load_uefi.c
@@ -0,0 +1,169 @@
1// SPDX-License-Identifier: GPL-2.0
2
3#include <linux/kernel.h>
4#include <linux/sched.h>
5#include <linux/cred.h>
6#include <linux/err.h>
7#include <linux/efi.h>
8#include <linux/slab.h>
9#include <keys/asymmetric-type.h>
10#include <keys/system_keyring.h>
11#include "../integrity.h"
12
13static efi_guid_t efi_cert_x509_guid __initdata = EFI_CERT_X509_GUID;
14static efi_guid_t efi_cert_x509_sha256_guid __initdata =
15 EFI_CERT_X509_SHA256_GUID;
16static efi_guid_t efi_cert_sha256_guid __initdata = EFI_CERT_SHA256_GUID;
17
18/*
19 * Get a certificate list blob from the named EFI variable.
20 */
21static __init void *get_cert_list(efi_char16_t *name, efi_guid_t *guid,
22 unsigned long *size)
23{
24 efi_status_t status;
25 unsigned long lsize = 4;
26 unsigned long tmpdb[4];
27 void *db;
28
29 status = efi.get_variable(name, guid, NULL, &lsize, &tmpdb);
30 if (status != EFI_BUFFER_TOO_SMALL) {
31 pr_err("Couldn't get size: 0x%lx\n", status);
32 return NULL;
33 }
34
35 db = kmalloc(lsize, GFP_KERNEL);
36 if (!db)
37 return NULL;
38
39 status = efi.get_variable(name, guid, NULL, &lsize, db);
40 if (status != EFI_SUCCESS) {
41 kfree(db);
42 pr_err("Error reading db var: 0x%lx\n", status);
43 return NULL;
44 }
45
46 *size = lsize;
47 return db;
48}
49
50/*
51 * Blacklist a hash.
52 */
53static __init void uefi_blacklist_hash(const char *source, const void *data,
54 size_t len, const char *type,
55 size_t type_len)
56{
57 char *hash, *p;
58
59 hash = kmalloc(type_len + len * 2 + 1, GFP_KERNEL);
60 if (!hash)
61 return;
62 p = memcpy(hash, type, type_len);
63 p += type_len;
64 bin2hex(p, data, len);
65 p += len * 2;
66 *p = 0;
67
68 mark_hash_blacklisted(hash);
69 kfree(hash);
70}
71
72/*
73 * Blacklist an X509 TBS hash.
74 */
75static __init void uefi_blacklist_x509_tbs(const char *source,
76 const void *data, size_t len)
77{
78 uefi_blacklist_hash(source, data, len, "tbs:", 4);
79}
80
81/*
82 * Blacklist the hash of an executable.
83 */
84static __init void uefi_blacklist_binary(const char *source,
85 const void *data, size_t len)
86{
87 uefi_blacklist_hash(source, data, len, "bin:", 4);
88}
89
90/*
91 * Return the appropriate handler for particular signature list types found in
92 * the UEFI db and MokListRT tables.
93 */
94static __init efi_element_handler_t get_handler_for_db(const efi_guid_t *
95 sig_type)
96{
97 if (efi_guidcmp(*sig_type, efi_cert_x509_guid) == 0)
98 return add_to_platform_keyring;
99 return 0;
100}
101
102/*
103 * Return the appropriate handler for particular signature list types found in
104 * the UEFI dbx and MokListXRT tables.
105 */
106static __init efi_element_handler_t get_handler_for_dbx(const efi_guid_t *
107 sig_type)
108{
109 if (efi_guidcmp(*sig_type, efi_cert_x509_sha256_guid) == 0)
110 return uefi_blacklist_x509_tbs;
111 if (efi_guidcmp(*sig_type, efi_cert_sha256_guid) == 0)
112 return uefi_blacklist_binary;
113 return 0;
114}
115
116/*
117 * Load the certs contained in the UEFI databases
118 */
119static int __init load_uefi_certs(void)
120{
121 efi_guid_t secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
122 efi_guid_t mok_var = EFI_SHIM_LOCK_GUID;
123 void *db = NULL, *dbx = NULL, *mok = NULL;
124 unsigned long dbsize = 0, dbxsize = 0, moksize = 0;
125 int rc = 0;
126
127 if (!efi.get_variable)
128 return false;
129
130 /* Get db, MokListRT, and dbx. They might not exist, so it isn't
131 * an error if we can't get them.
132 */
133 db = get_cert_list(L"db", &secure_var, &dbsize);
134 if (!db) {
135 pr_err("Couldn't get UEFI db list\n");
136 } else {
137 rc = parse_efi_signature_list("UEFI:db",
138 db, dbsize, get_handler_for_db);
139 if (rc)
140 pr_err("Couldn't parse db signatures: %d\n", rc);
141 kfree(db);
142 }
143
144 mok = get_cert_list(L"MokListRT", &mok_var, &moksize);
145 if (!mok) {
146 pr_info("Couldn't get UEFI MokListRT\n");
147 } else {
148 rc = parse_efi_signature_list("UEFI:MokListRT",
149 mok, moksize, get_handler_for_db);
150 if (rc)
151 pr_err("Couldn't parse MokListRT signatures: %d\n", rc);
152 kfree(mok);
153 }
154
155 dbx = get_cert_list(L"dbx", &secure_var, &dbxsize);
156 if (!dbx) {
157 pr_info("Couldn't get UEFI dbx list\n");
158 } else {
159 rc = parse_efi_signature_list("UEFI:dbx",
160 dbx, dbxsize,
161 get_handler_for_dbx);
162 if (rc)
163 pr_err("Couldn't parse dbx signatures: %d\n", rc);
164 kfree(dbx);
165 }
166
167 return rc;
168}
169late_initcall(load_uefi_certs);