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