1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
|
From ba2b209daf984514229626803472e0b055832345 Mon Sep 17 00:00:00 2001
From: Josh Boyer <jwboyer@fedoraproject.org>
Date: Fri, 26 Oct 2012 12:42:16 -0400
Subject: [PATCH] MODSIGN: Import certificates from UEFI Secure Boot
Secure Boot stores a list of allowed certificates in the 'db' variable.
This imports those certificates into the system trusted keyring. This
allows for a third party signing certificate to be used in conjunction
with signed modules. By importing the public certificate into the 'db'
variable, a user can allow a module signed with that certificate to
load. The shim UEFI bootloader has a similar certificate list stored
in the 'MokListRT' variable. We import those as well.
In the opposite case, Secure Boot maintains a list of disallowed
certificates in the 'dbx' variable. We load those certificates into
the newly introduced system blacklist keyring and forbid any module
signed with those from loading.
Signed-off-by: Josh Boyer <jwboyer@fedoraproject.org>
---
certs/system_keyring.c | 13 ++++++
include/keys/system_keyring.h | 1 +
include/linux/efi.h | 6 +++
init/Kconfig | 9 ++++
kernel/Makefile | 3 ++
kernel/modsign_uefi.c | 99 +++++++++++++++++++++++++++++++++++++++++++
6 files changed, 131 insertions(+)
create mode 100644 kernel/modsign_uefi.c
diff --git a/certs/system_keyring.c b/certs/system_keyring.c
index 787eeead2f57..4d9123ed5c07 100644
--- a/certs/system_keyring.c
+++ b/certs/system_keyring.c
@@ -30,6 +30,19 @@ extern __initconst const u8 system_certificate_list[];
extern __initconst const unsigned long system_certificate_list_size;
/**
+ * get_system_keyring - Return a pointer to the system keyring
+ *
+ */
+struct key *get_system_keyring(void)
+{
+ struct key *system_keyring = NULL;
+
+ system_keyring = builtin_trusted_keys;
+ return system_keyring;
+}
+EXPORT_SYMBOL_GPL(get_system_keyring);
+
+/**
* restrict_link_to_builtin_trusted - Restrict keyring addition by built in CA
*
* Restrict the addition of keys into a keyring based on the key-to-be-added
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
index 5bc291a3d261..56ff5715ab67 100644
--- a/include/keys/system_keyring.h
+++ b/include/keys/system_keyring.h
@@ -36,6 +36,7 @@ extern int restrict_link_by_builtin_and_secondary_trusted(
#ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING
extern struct key *system_blacklist_keyring;
#endif
+extern struct key *get_system_keyring(void);
#ifdef CONFIG_IMA_BLACKLIST_KEYRING
extern struct key *ima_blacklist_keyring;
diff --git a/include/linux/efi.h b/include/linux/efi.h
index ff1877145aa4..2483de19c719 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -658,6 +658,12 @@ typedef struct {
u64 table;
} efi_config_table_64_t;
+#define EFI_IMAGE_SECURITY_DATABASE_GUID \
+ EFI_GUID( 0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f )
+
+#define EFI_SHIM_LOCK_GUID \
+ EFI_GUID( 0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 )
+
typedef struct {
efi_guid_t guid;
u32 table;
diff --git a/init/Kconfig b/init/Kconfig
index e5449d5aeff9..5408c96f6604 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1979,6 +1979,15 @@ config MODULE_SIG_ALL
comment "Do not forget to sign required modules with scripts/sign-file"
depends on MODULE_SIG_FORCE && !MODULE_SIG_ALL
+config MODULE_SIG_UEFI
+ bool "Allow modules signed with certs stored in UEFI"
+ depends on MODULE_SIG && SYSTEM_BLACKLIST_KEYRING && EFI
+ select EFI_SIGNATURE_LIST_PARSER
+ help
+ This will import certificates stored in UEFI and allow modules
+ signed with those to be loaded. It will also disallow loading
+ of modules stored in the UEFI dbx variable.
+
choice
prompt "Which hash algorithm should modules be signed with?"
depends on MODULE_SIG
diff --git a/kernel/Makefile b/kernel/Makefile
index e2ec54e2b952..8dab549985d8 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -57,6 +57,7 @@ endif
obj-$(CONFIG_UID16) += uid16.o
obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_MODULE_SIG) += module_signing.o
+obj-$(CONFIG_MODULE_SIG_UEFI) += modsign_uefi.o
obj-$(CONFIG_KALLSYMS) += kallsyms.o
obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
obj-$(CONFIG_KEXEC_CORE) += kexec_core.o
@@ -113,6 +114,8 @@ obj-$(CONFIG_MEMBARRIER) += membarrier.o
obj-$(CONFIG_HAS_IOMEM) += memremap.o
+$(obj)/modsign_uefi.o: KBUILD_CFLAGS += -fshort-wchar
+
$(obj)/configs.o: $(obj)/config_data.h
# config_data.h contains the same information as ikconfig.h but gzipped.
diff --git a/kernel/modsign_uefi.c b/kernel/modsign_uefi.c
new file mode 100644
index 000000000000..fe4a6f2bf10a
--- /dev/null
+++ b/kernel/modsign_uefi.c
@@ -0,0 +1,99 @@
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/cred.h>
+#include <linux/err.h>
+#include <linux/efi.h>
+#include <linux/slab.h>
+#include <keys/asymmetric-type.h>
+#include <keys/system_keyring.h>
+#include "module-internal.h"
+
+static __init void *get_cert_list(efi_char16_t *name, efi_guid_t *guid, unsigned long *size)
+{
+ efi_status_t status;
+ unsigned long lsize = 4;
+ unsigned long tmpdb[4];
+ void *db = NULL;
+
+ status = efi.get_variable(name, guid, NULL, &lsize, &tmpdb);
+ if (status != EFI_BUFFER_TOO_SMALL) {
+ pr_err("Couldn't get size: 0x%lx\n", status);
+ return NULL;
+ }
+
+ db = kmalloc(lsize, GFP_KERNEL);
+ if (!db) {
+ pr_err("Couldn't allocate memory for uefi cert list\n");
+ goto out;
+ }
+
+ status = efi.get_variable(name, guid, NULL, &lsize, db);
+ if (status != EFI_SUCCESS) {
+ kfree(db);
+ db = NULL;
+ pr_err("Error reading db var: 0x%lx\n", status);
+ }
+out:
+ *size = lsize;
+ return db;
+}
+
+/*
+ * * Load the certs contained in the UEFI databases
+ * */
+static int __init load_uefi_certs(void)
+{
+ efi_guid_t secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
+ efi_guid_t mok_var = EFI_SHIM_LOCK_GUID;
+ void *db = NULL, *dbx = NULL, *mok = NULL;
+ unsigned long dbsize = 0, dbxsize = 0, moksize = 0;
+ int rc = 0;
+ struct key *keyring = NULL;
+
+ /* Check if SB is enabled and just return if not */
+ if (!efi_enabled(EFI_SECURE_BOOT))
+ return 0;
+
+ keyring = get_system_keyring();
+ if (!keyring) {
+ pr_err("MODSIGN: Couldn't get system keyring\n");
+ return -EINVAL;
+ }
+
+ /* Get db, MokListRT, and dbx. They might not exist, so it isn't
+ * an error if we can't get them.
+ */
+ db = get_cert_list(L"db", &secure_var, &dbsize);
+ if (!db) {
+ pr_err("MODSIGN: Couldn't get UEFI db list\n");
+ } else {
+ rc = parse_efi_signature_list(db, dbsize, keyring);
+ if (rc)
+ pr_err("Couldn't parse db signatures: %d\n", rc);
+ kfree(db);
+ }
+
+ mok = get_cert_list(L"MokListRT", &mok_var, &moksize);
+ if (!mok) {
+ pr_info("MODSIGN: Couldn't get UEFI MokListRT\n");
+ } else {
+ rc = parse_efi_signature_list(mok, moksize, keyring);
+ if (rc)
+ pr_err("Couldn't parse MokListRT signatures: %d\n", rc);
+ kfree(mok);
+ }
+
+ dbx = get_cert_list(L"dbx", &secure_var, &dbxsize);
+ if (!dbx) {
+ pr_info("MODSIGN: Couldn't get UEFI dbx list\n");
+ } else {
+ rc = parse_efi_signature_list(dbx, dbxsize,
+ system_blacklist_keyring);
+ if (rc)
+ pr_err("Couldn't parse dbx signatures: %d\n", rc);
+ kfree(dbx);
+ }
+
+ return rc;
+}
+late_initcall(load_uefi_certs);
--
2.5.5
|