Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/firmware/efi/mokvar-table.c
26444 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* mokvar-table.c
4
*
5
* Copyright (c) 2020 Red Hat
6
* Author: Lenny Szubowicz <[email protected]>
7
*
8
* This module contains the kernel support for the Linux EFI Machine
9
* Owner Key (MOK) variable configuration table, which is identified by
10
* the LINUX_EFI_MOK_VARIABLE_TABLE_GUID.
11
*
12
* This EFI configuration table provides a more robust alternative to
13
* EFI volatile variables by which an EFI boot loader can pass the
14
* contents of the Machine Owner Key (MOK) certificate stores to the
15
* kernel during boot. If both the EFI MOK config table and corresponding
16
* EFI MOK variables are present, the table should be considered as
17
* more authoritative.
18
*
19
* This module includes code that validates and maps the EFI MOK table,
20
* if it's presence was detected very early in boot.
21
*
22
* Kernel interface routines are provided to walk through all the
23
* entries in the MOK config table or to search for a specific named
24
* entry.
25
*
26
* The contents of the individual named MOK config table entries are
27
* made available to user space via read-only sysfs binary files under:
28
*
29
* /sys/firmware/efi/mok-variables/
30
*
31
*/
32
#define pr_fmt(fmt) "mokvar: " fmt
33
34
#include <linux/capability.h>
35
#include <linux/efi.h>
36
#include <linux/init.h>
37
#include <linux/io.h>
38
#include <linux/kernel.h>
39
#include <linux/kobject.h>
40
#include <linux/list.h>
41
#include <linux/slab.h>
42
43
#include <asm/early_ioremap.h>
44
45
/*
46
* The LINUX_EFI_MOK_VARIABLE_TABLE_GUID config table is a packed
47
* sequence of struct efi_mokvar_table_entry, one for each named
48
* MOK variable. The sequence is terminated by an entry with a
49
* completely NULL name and 0 data size.
50
*
51
* efi_mokvar_table_size is set to the computed size of the
52
* MOK config table by efi_mokvar_table_init(). This will be
53
* non-zero if and only if the table if present and has been
54
* validated by efi_mokvar_table_init().
55
*/
56
static size_t efi_mokvar_table_size;
57
58
/*
59
* efi_mokvar_table_va is the kernel virtual address at which the
60
* EFI MOK config table has been mapped by efi_mokvar_sysfs_init().
61
*/
62
static struct efi_mokvar_table_entry *efi_mokvar_table_va;
63
64
/*
65
* Each /sys/firmware/efi/mok-variables/ sysfs file is represented by
66
* an instance of struct efi_mokvar_sysfs_attr on efi_mokvar_sysfs_list.
67
* bin_attr.private points to the associated EFI MOK config table entry.
68
*
69
* This list is created during boot and then remains unchanged.
70
* So no synchronization is currently required to walk the list.
71
*/
72
struct efi_mokvar_sysfs_attr {
73
struct bin_attribute bin_attr;
74
struct list_head node;
75
};
76
77
static LIST_HEAD(efi_mokvar_sysfs_list);
78
static struct kobject *mokvar_kobj;
79
80
/*
81
* efi_mokvar_table_init() - Early boot validation of EFI MOK config table
82
*
83
* If present, validate and compute the size of the EFI MOK variable
84
* configuration table. This table may be provided by an EFI boot loader
85
* as an alternative to ordinary EFI variables, due to platform-dependent
86
* limitations. The memory occupied by this table is marked as reserved.
87
*
88
* This routine must be called before efi_free_boot_services() in order
89
* to guarantee that it can mark the table as reserved.
90
*
91
* Implicit inputs:
92
* efi.mokvar_table: Physical address of EFI MOK variable config table
93
* or special value that indicates no such table.
94
*
95
* Implicit outputs:
96
* efi_mokvar_table_size: Computed size of EFI MOK variable config table.
97
* The table is considered present and valid if this
98
* is non-zero.
99
*/
100
void __init efi_mokvar_table_init(void)
101
{
102
struct efi_mokvar_table_entry __aligned(1) *mokvar_entry, *next_entry;
103
efi_memory_desc_t md;
104
void *va = NULL;
105
unsigned long cur_offset = 0;
106
unsigned long offset_limit;
107
unsigned long map_size_needed = 0;
108
unsigned long size;
109
int err;
110
111
if (!efi_enabled(EFI_MEMMAP))
112
return;
113
114
if (efi.mokvar_table == EFI_INVALID_TABLE_ADDR)
115
return;
116
/*
117
* The EFI MOK config table must fit within a single EFI memory
118
* descriptor range.
119
*/
120
err = efi_mem_desc_lookup(efi.mokvar_table, &md);
121
if (err) {
122
pr_warn("EFI MOKvar config table is not within the EFI memory map\n");
123
return;
124
}
125
126
offset_limit = efi_mem_desc_end(&md) - efi.mokvar_table;
127
128
/*
129
* Validate the MOK config table. Since there is no table header
130
* from which we could get the total size of the MOK config table,
131
* we compute the total size as we validate each variably sized
132
* entry, remapping as necessary.
133
*/
134
err = -EINVAL;
135
while (cur_offset + sizeof(*mokvar_entry) <= offset_limit) {
136
if (va)
137
early_memunmap(va, sizeof(*mokvar_entry));
138
va = early_memremap(efi.mokvar_table + cur_offset, sizeof(*mokvar_entry));
139
if (!va) {
140
pr_err("Failed to map EFI MOKvar config table pa=0x%lx, size=%zu.\n",
141
efi.mokvar_table + cur_offset, sizeof(*mokvar_entry));
142
return;
143
}
144
mokvar_entry = va;
145
next:
146
/* Check for last sentinel entry */
147
if (mokvar_entry->name[0] == '\0') {
148
if (mokvar_entry->data_size != 0)
149
break;
150
err = 0;
151
map_size_needed = cur_offset + sizeof(*mokvar_entry);
152
break;
153
}
154
155
/* Enforce that the name is NUL terminated */
156
mokvar_entry->name[sizeof(mokvar_entry->name) - 1] = '\0';
157
158
/* Advance to the next entry */
159
size = sizeof(*mokvar_entry) + mokvar_entry->data_size;
160
cur_offset += size;
161
162
/*
163
* Don't bother remapping if the current entry header and the
164
* next one end on the same page.
165
*/
166
next_entry = (void *)((unsigned long)mokvar_entry + size);
167
if (((((unsigned long)(mokvar_entry + 1) - 1) ^
168
((unsigned long)(next_entry + 1) - 1)) & PAGE_MASK) == 0) {
169
mokvar_entry = next_entry;
170
goto next;
171
}
172
}
173
174
if (va)
175
early_memunmap(va, sizeof(*mokvar_entry));
176
if (err) {
177
pr_err("EFI MOKvar config table is not valid\n");
178
return;
179
}
180
181
if (md.type == EFI_BOOT_SERVICES_DATA)
182
efi_mem_reserve(efi.mokvar_table, map_size_needed);
183
184
efi_mokvar_table_size = map_size_needed;
185
}
186
187
/*
188
* efi_mokvar_entry_next() - Get next entry in the EFI MOK config table
189
*
190
* mokvar_entry: Pointer to current EFI MOK config table entry
191
* or null. Null indicates get first entry.
192
* Passed by reference. This is updated to the
193
* same value as the return value.
194
*
195
* Returns: Pointer to next EFI MOK config table entry
196
* or null, if there are no more entries.
197
* Same value is returned in the mokvar_entry
198
* parameter.
199
*
200
* This routine depends on the EFI MOK config table being entirely
201
* mapped with it's starting virtual address in efi_mokvar_table_va.
202
*/
203
struct efi_mokvar_table_entry *efi_mokvar_entry_next(
204
struct efi_mokvar_table_entry **mokvar_entry)
205
{
206
struct efi_mokvar_table_entry *mokvar_cur;
207
struct efi_mokvar_table_entry *mokvar_next;
208
size_t size_cur;
209
210
mokvar_cur = *mokvar_entry;
211
*mokvar_entry = NULL;
212
213
if (efi_mokvar_table_va == NULL)
214
return NULL;
215
216
if (mokvar_cur == NULL) {
217
mokvar_next = efi_mokvar_table_va;
218
} else {
219
if (mokvar_cur->name[0] == '\0')
220
return NULL;
221
size_cur = sizeof(*mokvar_cur) + mokvar_cur->data_size;
222
mokvar_next = (void *)mokvar_cur + size_cur;
223
}
224
225
if (mokvar_next->name[0] == '\0')
226
return NULL;
227
228
*mokvar_entry = mokvar_next;
229
return mokvar_next;
230
}
231
232
/*
233
* efi_mokvar_entry_find() - Find EFI MOK config entry by name
234
*
235
* name: Name of the entry to look for.
236
*
237
* Returns: Pointer to EFI MOK config table entry if found;
238
* null otherwise.
239
*
240
* This routine depends on the EFI MOK config table being entirely
241
* mapped with it's starting virtual address in efi_mokvar_table_va.
242
*/
243
struct efi_mokvar_table_entry *efi_mokvar_entry_find(const char *name)
244
{
245
struct efi_mokvar_table_entry *mokvar_entry = NULL;
246
247
while (efi_mokvar_entry_next(&mokvar_entry)) {
248
if (!strncmp(name, mokvar_entry->name,
249
sizeof(mokvar_entry->name)))
250
return mokvar_entry;
251
}
252
return NULL;
253
}
254
255
/*
256
* efi_mokvar_sysfs_read() - sysfs binary file read routine
257
*
258
* Returns: Count of bytes read.
259
*
260
* Copy EFI MOK config table entry data for this mokvar sysfs binary file
261
* to the supplied buffer, starting at the specified offset into mokvar table
262
* entry data, for the specified count bytes. The copy is limited by the
263
* amount of data in this mokvar config table entry.
264
*/
265
static ssize_t efi_mokvar_sysfs_read(struct file *file, struct kobject *kobj,
266
const struct bin_attribute *bin_attr, char *buf,
267
loff_t off, size_t count)
268
{
269
struct efi_mokvar_table_entry *mokvar_entry = bin_attr->private;
270
271
if (!capable(CAP_SYS_ADMIN))
272
return 0;
273
274
if (off >= mokvar_entry->data_size)
275
return 0;
276
if (count > mokvar_entry->data_size - off)
277
count = mokvar_entry->data_size - off;
278
279
memcpy(buf, mokvar_entry->data + off, count);
280
return count;
281
}
282
283
/*
284
* efi_mokvar_sysfs_init() - Map EFI MOK config table and create sysfs
285
*
286
* Map the EFI MOK variable config table for run-time use by the kernel
287
* and create the sysfs entries in /sys/firmware/efi/mok-variables/
288
*
289
* This routine just returns if a valid EFI MOK variable config table
290
* was not found earlier during boot.
291
*
292
* This routine must be called during a "middle" initcall phase, i.e.
293
* after efi_mokvar_table_init() but before UEFI certs are loaded
294
* during late init.
295
*
296
* Implicit inputs:
297
* efi.mokvar_table: Physical address of EFI MOK variable config table
298
* or special value that indicates no such table.
299
*
300
* efi_mokvar_table_size: Computed size of EFI MOK variable config table.
301
* The table is considered present and valid if this
302
* is non-zero.
303
*
304
* Implicit outputs:
305
* efi_mokvar_table_va: Start virtual address of the EFI MOK config table.
306
*/
307
static int __init efi_mokvar_sysfs_init(void)
308
{
309
void *config_va;
310
struct efi_mokvar_table_entry *mokvar_entry = NULL;
311
struct efi_mokvar_sysfs_attr *mokvar_sysfs = NULL;
312
int err = 0;
313
314
if (efi_mokvar_table_size == 0)
315
return -ENOENT;
316
317
config_va = memremap(efi.mokvar_table, efi_mokvar_table_size,
318
MEMREMAP_WB);
319
if (!config_va) {
320
pr_err("Failed to map EFI MOKvar config table\n");
321
return -ENOMEM;
322
}
323
efi_mokvar_table_va = config_va;
324
325
mokvar_kobj = kobject_create_and_add("mok-variables", efi_kobj);
326
if (!mokvar_kobj) {
327
pr_err("Failed to create EFI mok-variables sysfs entry\n");
328
return -ENOMEM;
329
}
330
331
while (efi_mokvar_entry_next(&mokvar_entry)) {
332
mokvar_sysfs = kzalloc(sizeof(*mokvar_sysfs), GFP_KERNEL);
333
if (!mokvar_sysfs) {
334
err = -ENOMEM;
335
break;
336
}
337
338
sysfs_bin_attr_init(&mokvar_sysfs->bin_attr);
339
mokvar_sysfs->bin_attr.private = mokvar_entry;
340
mokvar_sysfs->bin_attr.attr.name = mokvar_entry->name;
341
mokvar_sysfs->bin_attr.attr.mode = 0400;
342
mokvar_sysfs->bin_attr.size = mokvar_entry->data_size;
343
mokvar_sysfs->bin_attr.read = efi_mokvar_sysfs_read;
344
345
err = sysfs_create_bin_file(mokvar_kobj,
346
&mokvar_sysfs->bin_attr);
347
if (err)
348
break;
349
350
list_add_tail(&mokvar_sysfs->node, &efi_mokvar_sysfs_list);
351
}
352
353
if (err) {
354
pr_err("Failed to create some EFI mok-variables sysfs entries\n");
355
kfree(mokvar_sysfs);
356
}
357
return err;
358
}
359
fs_initcall(efi_mokvar_sysfs_init);
360
361