18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * mokvar-table.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2020 Red Hat 68c2ecf20Sopenharmony_ci * Author: Lenny Szubowicz <lszubowi@redhat.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This module contains the kernel support for the Linux EFI Machine 98c2ecf20Sopenharmony_ci * Owner Key (MOK) variable configuration table, which is identified by 108c2ecf20Sopenharmony_ci * the LINUX_EFI_MOK_VARIABLE_TABLE_GUID. 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * This EFI configuration table provides a more robust alternative to 138c2ecf20Sopenharmony_ci * EFI volatile variables by which an EFI boot loader can pass the 148c2ecf20Sopenharmony_ci * contents of the Machine Owner Key (MOK) certificate stores to the 158c2ecf20Sopenharmony_ci * kernel during boot. If both the EFI MOK config table and corresponding 168c2ecf20Sopenharmony_ci * EFI MOK variables are present, the table should be considered as 178c2ecf20Sopenharmony_ci * more authoritative. 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * This module includes code that validates and maps the EFI MOK table, 208c2ecf20Sopenharmony_ci * if it's presence was detected very early in boot. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * Kernel interface routines are provided to walk through all the 238c2ecf20Sopenharmony_ci * entries in the MOK config table or to search for a specific named 248c2ecf20Sopenharmony_ci * entry. 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * The contents of the individual named MOK config table entries are 278c2ecf20Sopenharmony_ci * made available to user space via read-only sysfs binary files under: 288c2ecf20Sopenharmony_ci * 298c2ecf20Sopenharmony_ci * /sys/firmware/efi/mok-variables/ 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "mokvar: " fmt 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include <linux/capability.h> 358c2ecf20Sopenharmony_ci#include <linux/efi.h> 368c2ecf20Sopenharmony_ci#include <linux/init.h> 378c2ecf20Sopenharmony_ci#include <linux/io.h> 388c2ecf20Sopenharmony_ci#include <linux/kernel.h> 398c2ecf20Sopenharmony_ci#include <linux/kobject.h> 408c2ecf20Sopenharmony_ci#include <linux/list.h> 418c2ecf20Sopenharmony_ci#include <linux/slab.h> 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#include <asm/early_ioremap.h> 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* 468c2ecf20Sopenharmony_ci * The LINUX_EFI_MOK_VARIABLE_TABLE_GUID config table is a packed 478c2ecf20Sopenharmony_ci * sequence of struct efi_mokvar_table_entry, one for each named 488c2ecf20Sopenharmony_ci * MOK variable. The sequence is terminated by an entry with a 498c2ecf20Sopenharmony_ci * completely NULL name and 0 data size. 508c2ecf20Sopenharmony_ci * 518c2ecf20Sopenharmony_ci * efi_mokvar_table_size is set to the computed size of the 528c2ecf20Sopenharmony_ci * MOK config table by efi_mokvar_table_init(). This will be 538c2ecf20Sopenharmony_ci * non-zero if and only if the table if present and has been 548c2ecf20Sopenharmony_ci * validated by efi_mokvar_table_init(). 558c2ecf20Sopenharmony_ci */ 568c2ecf20Sopenharmony_cistatic size_t efi_mokvar_table_size; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* 598c2ecf20Sopenharmony_ci * efi_mokvar_table_va is the kernel virtual address at which the 608c2ecf20Sopenharmony_ci * EFI MOK config table has been mapped by efi_mokvar_sysfs_init(). 618c2ecf20Sopenharmony_ci */ 628c2ecf20Sopenharmony_cistatic struct efi_mokvar_table_entry *efi_mokvar_table_va; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/* 658c2ecf20Sopenharmony_ci * Each /sys/firmware/efi/mok-variables/ sysfs file is represented by 668c2ecf20Sopenharmony_ci * an instance of struct efi_mokvar_sysfs_attr on efi_mokvar_sysfs_list. 678c2ecf20Sopenharmony_ci * bin_attr.private points to the associated EFI MOK config table entry. 688c2ecf20Sopenharmony_ci * 698c2ecf20Sopenharmony_ci * This list is created during boot and then remains unchanged. 708c2ecf20Sopenharmony_ci * So no synchronization is currently required to walk the list. 718c2ecf20Sopenharmony_ci */ 728c2ecf20Sopenharmony_cistruct efi_mokvar_sysfs_attr { 738c2ecf20Sopenharmony_ci struct bin_attribute bin_attr; 748c2ecf20Sopenharmony_ci struct list_head node; 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic LIST_HEAD(efi_mokvar_sysfs_list); 788c2ecf20Sopenharmony_cistatic struct kobject *mokvar_kobj; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/* 818c2ecf20Sopenharmony_ci * efi_mokvar_table_init() - Early boot validation of EFI MOK config table 828c2ecf20Sopenharmony_ci * 838c2ecf20Sopenharmony_ci * If present, validate and compute the size of the EFI MOK variable 848c2ecf20Sopenharmony_ci * configuration table. This table may be provided by an EFI boot loader 858c2ecf20Sopenharmony_ci * as an alternative to ordinary EFI variables, due to platform-dependent 868c2ecf20Sopenharmony_ci * limitations. The memory occupied by this table is marked as reserved. 878c2ecf20Sopenharmony_ci * 888c2ecf20Sopenharmony_ci * This routine must be called before efi_free_boot_services() in order 898c2ecf20Sopenharmony_ci * to guarantee that it can mark the table as reserved. 908c2ecf20Sopenharmony_ci * 918c2ecf20Sopenharmony_ci * Implicit inputs: 928c2ecf20Sopenharmony_ci * efi.mokvar_table: Physical address of EFI MOK variable config table 938c2ecf20Sopenharmony_ci * or special value that indicates no such table. 948c2ecf20Sopenharmony_ci * 958c2ecf20Sopenharmony_ci * Implicit outputs: 968c2ecf20Sopenharmony_ci * efi_mokvar_table_size: Computed size of EFI MOK variable config table. 978c2ecf20Sopenharmony_ci * The table is considered present and valid if this 988c2ecf20Sopenharmony_ci * is non-zero. 998c2ecf20Sopenharmony_ci */ 1008c2ecf20Sopenharmony_civoid __init efi_mokvar_table_init(void) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci efi_memory_desc_t md; 1038c2ecf20Sopenharmony_ci void *va = NULL; 1048c2ecf20Sopenharmony_ci unsigned long cur_offset = 0; 1058c2ecf20Sopenharmony_ci unsigned long offset_limit; 1068c2ecf20Sopenharmony_ci unsigned long map_size = 0; 1078c2ecf20Sopenharmony_ci unsigned long map_size_needed = 0; 1088c2ecf20Sopenharmony_ci unsigned long size; 1098c2ecf20Sopenharmony_ci struct efi_mokvar_table_entry *mokvar_entry; 1108c2ecf20Sopenharmony_ci int err; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci if (!efi_enabled(EFI_MEMMAP)) 1138c2ecf20Sopenharmony_ci return; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci if (efi.mokvar_table == EFI_INVALID_TABLE_ADDR) 1168c2ecf20Sopenharmony_ci return; 1178c2ecf20Sopenharmony_ci /* 1188c2ecf20Sopenharmony_ci * The EFI MOK config table must fit within a single EFI memory 1198c2ecf20Sopenharmony_ci * descriptor range. 1208c2ecf20Sopenharmony_ci */ 1218c2ecf20Sopenharmony_ci err = efi_mem_desc_lookup(efi.mokvar_table, &md); 1228c2ecf20Sopenharmony_ci if (err) { 1238c2ecf20Sopenharmony_ci pr_warn("EFI MOKvar config table is not within the EFI memory map\n"); 1248c2ecf20Sopenharmony_ci return; 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci offset_limit = efi_mem_desc_end(&md) - efi.mokvar_table; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci /* 1308c2ecf20Sopenharmony_ci * Validate the MOK config table. Since there is no table header 1318c2ecf20Sopenharmony_ci * from which we could get the total size of the MOK config table, 1328c2ecf20Sopenharmony_ci * we compute the total size as we validate each variably sized 1338c2ecf20Sopenharmony_ci * entry, remapping as necessary. 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_ci err = -EINVAL; 1368c2ecf20Sopenharmony_ci while (cur_offset + sizeof(*mokvar_entry) <= offset_limit) { 1378c2ecf20Sopenharmony_ci mokvar_entry = va + cur_offset; 1388c2ecf20Sopenharmony_ci map_size_needed = cur_offset + sizeof(*mokvar_entry); 1398c2ecf20Sopenharmony_ci if (map_size_needed > map_size) { 1408c2ecf20Sopenharmony_ci if (va) 1418c2ecf20Sopenharmony_ci early_memunmap(va, map_size); 1428c2ecf20Sopenharmony_ci /* 1438c2ecf20Sopenharmony_ci * Map a little more than the fixed size entry 1448c2ecf20Sopenharmony_ci * header, anticipating some data. It's safe to 1458c2ecf20Sopenharmony_ci * do so as long as we stay within current memory 1468c2ecf20Sopenharmony_ci * descriptor. 1478c2ecf20Sopenharmony_ci */ 1488c2ecf20Sopenharmony_ci map_size = min(map_size_needed + 2*EFI_PAGE_SIZE, 1498c2ecf20Sopenharmony_ci offset_limit); 1508c2ecf20Sopenharmony_ci va = early_memremap(efi.mokvar_table, map_size); 1518c2ecf20Sopenharmony_ci if (!va) { 1528c2ecf20Sopenharmony_ci pr_err("Failed to map EFI MOKvar config table pa=0x%lx, size=%lu.\n", 1538c2ecf20Sopenharmony_ci efi.mokvar_table, map_size); 1548c2ecf20Sopenharmony_ci return; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci mokvar_entry = va + cur_offset; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci /* Check for last sentinel entry */ 1608c2ecf20Sopenharmony_ci if (mokvar_entry->name[0] == '\0') { 1618c2ecf20Sopenharmony_ci if (mokvar_entry->data_size != 0) 1628c2ecf20Sopenharmony_ci break; 1638c2ecf20Sopenharmony_ci err = 0; 1648c2ecf20Sopenharmony_ci break; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci /* Sanity check that the name is null terminated */ 1688c2ecf20Sopenharmony_ci size = strnlen(mokvar_entry->name, 1698c2ecf20Sopenharmony_ci sizeof(mokvar_entry->name)); 1708c2ecf20Sopenharmony_ci if (size >= sizeof(mokvar_entry->name)) 1718c2ecf20Sopenharmony_ci break; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci /* Advance to the next entry */ 1748c2ecf20Sopenharmony_ci cur_offset = map_size_needed + mokvar_entry->data_size; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (va) 1788c2ecf20Sopenharmony_ci early_memunmap(va, map_size); 1798c2ecf20Sopenharmony_ci if (err) { 1808c2ecf20Sopenharmony_ci pr_err("EFI MOKvar config table is not valid\n"); 1818c2ecf20Sopenharmony_ci return; 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (md.type == EFI_BOOT_SERVICES_DATA) 1858c2ecf20Sopenharmony_ci efi_mem_reserve(efi.mokvar_table, map_size_needed); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci efi_mokvar_table_size = map_size_needed; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci/* 1918c2ecf20Sopenharmony_ci * efi_mokvar_entry_next() - Get next entry in the EFI MOK config table 1928c2ecf20Sopenharmony_ci * 1938c2ecf20Sopenharmony_ci * mokvar_entry: Pointer to current EFI MOK config table entry 1948c2ecf20Sopenharmony_ci * or null. Null indicates get first entry. 1958c2ecf20Sopenharmony_ci * Passed by reference. This is updated to the 1968c2ecf20Sopenharmony_ci * same value as the return value. 1978c2ecf20Sopenharmony_ci * 1988c2ecf20Sopenharmony_ci * Returns: Pointer to next EFI MOK config table entry 1998c2ecf20Sopenharmony_ci * or null, if there are no more entries. 2008c2ecf20Sopenharmony_ci * Same value is returned in the mokvar_entry 2018c2ecf20Sopenharmony_ci * parameter. 2028c2ecf20Sopenharmony_ci * 2038c2ecf20Sopenharmony_ci * This routine depends on the EFI MOK config table being entirely 2048c2ecf20Sopenharmony_ci * mapped with it's starting virtual address in efi_mokvar_table_va. 2058c2ecf20Sopenharmony_ci */ 2068c2ecf20Sopenharmony_cistruct efi_mokvar_table_entry *efi_mokvar_entry_next( 2078c2ecf20Sopenharmony_ci struct efi_mokvar_table_entry **mokvar_entry) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci struct efi_mokvar_table_entry *mokvar_cur; 2108c2ecf20Sopenharmony_ci struct efi_mokvar_table_entry *mokvar_next; 2118c2ecf20Sopenharmony_ci size_t size_cur; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci mokvar_cur = *mokvar_entry; 2148c2ecf20Sopenharmony_ci *mokvar_entry = NULL; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci if (efi_mokvar_table_va == NULL) 2178c2ecf20Sopenharmony_ci return NULL; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (mokvar_cur == NULL) { 2208c2ecf20Sopenharmony_ci mokvar_next = efi_mokvar_table_va; 2218c2ecf20Sopenharmony_ci } else { 2228c2ecf20Sopenharmony_ci if (mokvar_cur->name[0] == '\0') 2238c2ecf20Sopenharmony_ci return NULL; 2248c2ecf20Sopenharmony_ci size_cur = sizeof(*mokvar_cur) + mokvar_cur->data_size; 2258c2ecf20Sopenharmony_ci mokvar_next = (void *)mokvar_cur + size_cur; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (mokvar_next->name[0] == '\0') 2298c2ecf20Sopenharmony_ci return NULL; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci *mokvar_entry = mokvar_next; 2328c2ecf20Sopenharmony_ci return mokvar_next; 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci/* 2368c2ecf20Sopenharmony_ci * efi_mokvar_entry_find() - Find EFI MOK config entry by name 2378c2ecf20Sopenharmony_ci * 2388c2ecf20Sopenharmony_ci * name: Name of the entry to look for. 2398c2ecf20Sopenharmony_ci * 2408c2ecf20Sopenharmony_ci * Returns: Pointer to EFI MOK config table entry if found; 2418c2ecf20Sopenharmony_ci * null otherwise. 2428c2ecf20Sopenharmony_ci * 2438c2ecf20Sopenharmony_ci * This routine depends on the EFI MOK config table being entirely 2448c2ecf20Sopenharmony_ci * mapped with it's starting virtual address in efi_mokvar_table_va. 2458c2ecf20Sopenharmony_ci */ 2468c2ecf20Sopenharmony_cistruct efi_mokvar_table_entry *efi_mokvar_entry_find(const char *name) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci struct efi_mokvar_table_entry *mokvar_entry = NULL; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci while (efi_mokvar_entry_next(&mokvar_entry)) { 2518c2ecf20Sopenharmony_ci if (!strncmp(name, mokvar_entry->name, 2528c2ecf20Sopenharmony_ci sizeof(mokvar_entry->name))) 2538c2ecf20Sopenharmony_ci return mokvar_entry; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci return NULL; 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci/* 2598c2ecf20Sopenharmony_ci * efi_mokvar_sysfs_read() - sysfs binary file read routine 2608c2ecf20Sopenharmony_ci * 2618c2ecf20Sopenharmony_ci * Returns: Count of bytes read. 2628c2ecf20Sopenharmony_ci * 2638c2ecf20Sopenharmony_ci * Copy EFI MOK config table entry data for this mokvar sysfs binary file 2648c2ecf20Sopenharmony_ci * to the supplied buffer, starting at the specified offset into mokvar table 2658c2ecf20Sopenharmony_ci * entry data, for the specified count bytes. The copy is limited by the 2668c2ecf20Sopenharmony_ci * amount of data in this mokvar config table entry. 2678c2ecf20Sopenharmony_ci */ 2688c2ecf20Sopenharmony_cistatic ssize_t efi_mokvar_sysfs_read(struct file *file, struct kobject *kobj, 2698c2ecf20Sopenharmony_ci struct bin_attribute *bin_attr, char *buf, 2708c2ecf20Sopenharmony_ci loff_t off, size_t count) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci struct efi_mokvar_table_entry *mokvar_entry = bin_attr->private; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 2758c2ecf20Sopenharmony_ci return 0; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (off >= mokvar_entry->data_size) 2788c2ecf20Sopenharmony_ci return 0; 2798c2ecf20Sopenharmony_ci if (count > mokvar_entry->data_size - off) 2808c2ecf20Sopenharmony_ci count = mokvar_entry->data_size - off; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci memcpy(buf, mokvar_entry->data + off, count); 2838c2ecf20Sopenharmony_ci return count; 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci/* 2878c2ecf20Sopenharmony_ci * efi_mokvar_sysfs_init() - Map EFI MOK config table and create sysfs 2888c2ecf20Sopenharmony_ci * 2898c2ecf20Sopenharmony_ci * Map the EFI MOK variable config table for run-time use by the kernel 2908c2ecf20Sopenharmony_ci * and create the sysfs entries in /sys/firmware/efi/mok-variables/ 2918c2ecf20Sopenharmony_ci * 2928c2ecf20Sopenharmony_ci * This routine just returns if a valid EFI MOK variable config table 2938c2ecf20Sopenharmony_ci * was not found earlier during boot. 2948c2ecf20Sopenharmony_ci * 2958c2ecf20Sopenharmony_ci * This routine must be called during a "middle" initcall phase, i.e. 2968c2ecf20Sopenharmony_ci * after efi_mokvar_table_init() but before UEFI certs are loaded 2978c2ecf20Sopenharmony_ci * during late init. 2988c2ecf20Sopenharmony_ci * 2998c2ecf20Sopenharmony_ci * Implicit inputs: 3008c2ecf20Sopenharmony_ci * efi.mokvar_table: Physical address of EFI MOK variable config table 3018c2ecf20Sopenharmony_ci * or special value that indicates no such table. 3028c2ecf20Sopenharmony_ci * 3038c2ecf20Sopenharmony_ci * efi_mokvar_table_size: Computed size of EFI MOK variable config table. 3048c2ecf20Sopenharmony_ci * The table is considered present and valid if this 3058c2ecf20Sopenharmony_ci * is non-zero. 3068c2ecf20Sopenharmony_ci * 3078c2ecf20Sopenharmony_ci * Implicit outputs: 3088c2ecf20Sopenharmony_ci * efi_mokvar_table_va: Start virtual address of the EFI MOK config table. 3098c2ecf20Sopenharmony_ci */ 3108c2ecf20Sopenharmony_cistatic int __init efi_mokvar_sysfs_init(void) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci void *config_va; 3138c2ecf20Sopenharmony_ci struct efi_mokvar_table_entry *mokvar_entry = NULL; 3148c2ecf20Sopenharmony_ci struct efi_mokvar_sysfs_attr *mokvar_sysfs = NULL; 3158c2ecf20Sopenharmony_ci int err = 0; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci if (efi_mokvar_table_size == 0) 3188c2ecf20Sopenharmony_ci return -ENOENT; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci config_va = memremap(efi.mokvar_table, efi_mokvar_table_size, 3218c2ecf20Sopenharmony_ci MEMREMAP_WB); 3228c2ecf20Sopenharmony_ci if (!config_va) { 3238c2ecf20Sopenharmony_ci pr_err("Failed to map EFI MOKvar config table\n"); 3248c2ecf20Sopenharmony_ci return -ENOMEM; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci efi_mokvar_table_va = config_va; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci mokvar_kobj = kobject_create_and_add("mok-variables", efi_kobj); 3298c2ecf20Sopenharmony_ci if (!mokvar_kobj) { 3308c2ecf20Sopenharmony_ci pr_err("Failed to create EFI mok-variables sysfs entry\n"); 3318c2ecf20Sopenharmony_ci return -ENOMEM; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci while (efi_mokvar_entry_next(&mokvar_entry)) { 3358c2ecf20Sopenharmony_ci mokvar_sysfs = kzalloc(sizeof(*mokvar_sysfs), GFP_KERNEL); 3368c2ecf20Sopenharmony_ci if (!mokvar_sysfs) { 3378c2ecf20Sopenharmony_ci err = -ENOMEM; 3388c2ecf20Sopenharmony_ci break; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci sysfs_bin_attr_init(&mokvar_sysfs->bin_attr); 3428c2ecf20Sopenharmony_ci mokvar_sysfs->bin_attr.private = mokvar_entry; 3438c2ecf20Sopenharmony_ci mokvar_sysfs->bin_attr.attr.name = mokvar_entry->name; 3448c2ecf20Sopenharmony_ci mokvar_sysfs->bin_attr.attr.mode = 0400; 3458c2ecf20Sopenharmony_ci mokvar_sysfs->bin_attr.size = mokvar_entry->data_size; 3468c2ecf20Sopenharmony_ci mokvar_sysfs->bin_attr.read = efi_mokvar_sysfs_read; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci err = sysfs_create_bin_file(mokvar_kobj, 3498c2ecf20Sopenharmony_ci &mokvar_sysfs->bin_attr); 3508c2ecf20Sopenharmony_ci if (err) 3518c2ecf20Sopenharmony_ci break; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci list_add_tail(&mokvar_sysfs->node, &efi_mokvar_sysfs_list); 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci if (err) { 3578c2ecf20Sopenharmony_ci pr_err("Failed to create some EFI mok-variables sysfs entries\n"); 3588c2ecf20Sopenharmony_ci kfree(mokvar_sysfs); 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci return err; 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_cidevice_initcall(efi_mokvar_sysfs_init); 363