0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032 #define pr_fmt(fmt) "mokvar: " fmt
0033
0034 #include <linux/capability.h>
0035 #include <linux/efi.h>
0036 #include <linux/init.h>
0037 #include <linux/io.h>
0038 #include <linux/kernel.h>
0039 #include <linux/kobject.h>
0040 #include <linux/list.h>
0041 #include <linux/slab.h>
0042
0043 #include <asm/early_ioremap.h>
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056 static size_t efi_mokvar_table_size;
0057
0058
0059
0060
0061
0062 static struct efi_mokvar_table_entry *efi_mokvar_table_va;
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072 struct efi_mokvar_sysfs_attr {
0073 struct bin_attribute bin_attr;
0074 struct list_head node;
0075 };
0076
0077 static LIST_HEAD(efi_mokvar_sysfs_list);
0078 static struct kobject *mokvar_kobj;
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100 void __init efi_mokvar_table_init(void)
0101 {
0102 efi_memory_desc_t md;
0103 void *va = NULL;
0104 unsigned long cur_offset = 0;
0105 unsigned long offset_limit;
0106 unsigned long map_size = 0;
0107 unsigned long map_size_needed = 0;
0108 unsigned long size;
0109 struct efi_mokvar_table_entry *mokvar_entry;
0110 int err;
0111
0112 if (!efi_enabled(EFI_MEMMAP))
0113 return;
0114
0115 if (efi.mokvar_table == EFI_INVALID_TABLE_ADDR)
0116 return;
0117
0118
0119
0120
0121 err = efi_mem_desc_lookup(efi.mokvar_table, &md);
0122 if (err) {
0123 pr_warn("EFI MOKvar config table is not within the EFI memory map\n");
0124 return;
0125 }
0126
0127 offset_limit = efi_mem_desc_end(&md) - efi.mokvar_table;
0128
0129
0130
0131
0132
0133
0134
0135 err = -EINVAL;
0136 while (cur_offset + sizeof(*mokvar_entry) <= offset_limit) {
0137 mokvar_entry = va + cur_offset;
0138 map_size_needed = cur_offset + sizeof(*mokvar_entry);
0139 if (map_size_needed > map_size) {
0140 if (va)
0141 early_memunmap(va, map_size);
0142
0143
0144
0145
0146
0147
0148 map_size = min(map_size_needed + 2*EFI_PAGE_SIZE,
0149 offset_limit);
0150 va = early_memremap(efi.mokvar_table, map_size);
0151 if (!va) {
0152 pr_err("Failed to map EFI MOKvar config table pa=0x%lx, size=%lu.\n",
0153 efi.mokvar_table, map_size);
0154 return;
0155 }
0156 mokvar_entry = va + cur_offset;
0157 }
0158
0159
0160 if (mokvar_entry->name[0] == '\0') {
0161 if (mokvar_entry->data_size != 0)
0162 break;
0163 err = 0;
0164 break;
0165 }
0166
0167
0168 size = strnlen(mokvar_entry->name,
0169 sizeof(mokvar_entry->name));
0170 if (size >= sizeof(mokvar_entry->name))
0171 break;
0172
0173
0174 cur_offset = map_size_needed + mokvar_entry->data_size;
0175 }
0176
0177 if (va)
0178 early_memunmap(va, map_size);
0179 if (err) {
0180 pr_err("EFI MOKvar config table is not valid\n");
0181 return;
0182 }
0183
0184 if (md.type == EFI_BOOT_SERVICES_DATA)
0185 efi_mem_reserve(efi.mokvar_table, map_size_needed);
0186
0187 efi_mokvar_table_size = map_size_needed;
0188 }
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206 struct efi_mokvar_table_entry *efi_mokvar_entry_next(
0207 struct efi_mokvar_table_entry **mokvar_entry)
0208 {
0209 struct efi_mokvar_table_entry *mokvar_cur;
0210 struct efi_mokvar_table_entry *mokvar_next;
0211 size_t size_cur;
0212
0213 mokvar_cur = *mokvar_entry;
0214 *mokvar_entry = NULL;
0215
0216 if (efi_mokvar_table_va == NULL)
0217 return NULL;
0218
0219 if (mokvar_cur == NULL) {
0220 mokvar_next = efi_mokvar_table_va;
0221 } else {
0222 if (mokvar_cur->name[0] == '\0')
0223 return NULL;
0224 size_cur = sizeof(*mokvar_cur) + mokvar_cur->data_size;
0225 mokvar_next = (void *)mokvar_cur + size_cur;
0226 }
0227
0228 if (mokvar_next->name[0] == '\0')
0229 return NULL;
0230
0231 *mokvar_entry = mokvar_next;
0232 return mokvar_next;
0233 }
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246 struct efi_mokvar_table_entry *efi_mokvar_entry_find(const char *name)
0247 {
0248 struct efi_mokvar_table_entry *mokvar_entry = NULL;
0249
0250 while (efi_mokvar_entry_next(&mokvar_entry)) {
0251 if (!strncmp(name, mokvar_entry->name,
0252 sizeof(mokvar_entry->name)))
0253 return mokvar_entry;
0254 }
0255 return NULL;
0256 }
0257
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268 static ssize_t efi_mokvar_sysfs_read(struct file *file, struct kobject *kobj,
0269 struct bin_attribute *bin_attr, char *buf,
0270 loff_t off, size_t count)
0271 {
0272 struct efi_mokvar_table_entry *mokvar_entry = bin_attr->private;
0273
0274 if (!capable(CAP_SYS_ADMIN))
0275 return 0;
0276
0277 if (off >= mokvar_entry->data_size)
0278 return 0;
0279 if (count > mokvar_entry->data_size - off)
0280 count = mokvar_entry->data_size - off;
0281
0282 memcpy(buf, mokvar_entry->data + off, count);
0283 return count;
0284 }
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310 static int __init efi_mokvar_sysfs_init(void)
0311 {
0312 void *config_va;
0313 struct efi_mokvar_table_entry *mokvar_entry = NULL;
0314 struct efi_mokvar_sysfs_attr *mokvar_sysfs = NULL;
0315 int err = 0;
0316
0317 if (efi_mokvar_table_size == 0)
0318 return -ENOENT;
0319
0320 config_va = memremap(efi.mokvar_table, efi_mokvar_table_size,
0321 MEMREMAP_WB);
0322 if (!config_va) {
0323 pr_err("Failed to map EFI MOKvar config table\n");
0324 return -ENOMEM;
0325 }
0326 efi_mokvar_table_va = config_va;
0327
0328 mokvar_kobj = kobject_create_and_add("mok-variables", efi_kobj);
0329 if (!mokvar_kobj) {
0330 pr_err("Failed to create EFI mok-variables sysfs entry\n");
0331 return -ENOMEM;
0332 }
0333
0334 while (efi_mokvar_entry_next(&mokvar_entry)) {
0335 mokvar_sysfs = kzalloc(sizeof(*mokvar_sysfs), GFP_KERNEL);
0336 if (!mokvar_sysfs) {
0337 err = -ENOMEM;
0338 break;
0339 }
0340
0341 sysfs_bin_attr_init(&mokvar_sysfs->bin_attr);
0342 mokvar_sysfs->bin_attr.private = mokvar_entry;
0343 mokvar_sysfs->bin_attr.attr.name = mokvar_entry->name;
0344 mokvar_sysfs->bin_attr.attr.mode = 0400;
0345 mokvar_sysfs->bin_attr.size = mokvar_entry->data_size;
0346 mokvar_sysfs->bin_attr.read = efi_mokvar_sysfs_read;
0347
0348 err = sysfs_create_bin_file(mokvar_kobj,
0349 &mokvar_sysfs->bin_attr);
0350 if (err)
0351 break;
0352
0353 list_add_tail(&mokvar_sysfs->node, &efi_mokvar_sysfs_list);
0354 }
0355
0356 if (err) {
0357 pr_err("Failed to create some EFI mok-variables sysfs entries\n");
0358 kfree(mokvar_sysfs);
0359 }
0360 return err;
0361 }
0362 fs_initcall(efi_mokvar_sysfs_init);