| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * efi_secret module
- *
- * Copyright (C) 2022 IBM Corporation
- * Author: Dov Murik <dovmurik@linux.ibm.com>
- */
- /**
- * DOC: efi_secret: Allow reading EFI confidential computing (coco) secret area
- * via securityfs interface.
- *
- * When the module is loaded (and securityfs is mounted, typically under
- * /sys/kernel/security), a "secrets/coco" directory is created in securityfs.
- * In it, a file is created for each secret entry. The name of each such file
- * is the GUID of the secret entry, and its content is the secret data.
- */
- #include <linux/platform_device.h>
- #include <linux/seq_file.h>
- #include <linux/fs.h>
- #include <linux/kernel.h>
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/io.h>
- #include <linux/security.h>
- #include <linux/efi.h>
- #include <linux/cacheflush.h>
- #define EFI_SECRET_NUM_FILES 64
- struct efi_secret {
- struct dentry *secrets_dir;
- struct dentry *fs_dir;
- struct dentry *fs_files[EFI_SECRET_NUM_FILES];
- void __iomem *secret_data;
- u64 secret_data_len;
- };
- /*
- * Structure of the EFI secret area
- *
- * Offset Length
- * (bytes) (bytes) Usage
- * ------- ------- -----
- * 0 16 Secret table header GUID (must be 1e74f542-71dd-4d66-963e-ef4287ff173b)
- * 16 4 Length of bytes of the entire secret area
- *
- * 20 16 First secret entry's GUID
- * 36 4 First secret entry's length in bytes (= 16 + 4 + x)
- * 40 x First secret entry's data
- *
- * 40+x 16 Second secret entry's GUID
- * 56+x 4 Second secret entry's length in bytes (= 16 + 4 + y)
- * 60+x y Second secret entry's data
- *
- * (... and so on for additional entries)
- *
- * The GUID of each secret entry designates the usage of the secret data.
- */
- /**
- * struct secret_header - Header of entire secret area; this should be followed
- * by instances of struct secret_entry.
- * @guid: Must be EFI_SECRET_TABLE_HEADER_GUID
- * @len: Length in bytes of entire secret area, including header
- */
- struct secret_header {
- efi_guid_t guid;
- u32 len;
- } __attribute((packed));
- /**
- * struct secret_entry - Holds one secret entry
- * @guid: Secret-specific GUID (or NULL_GUID if this secret entry was deleted)
- * @len: Length of secret entry, including its guid and len fields
- * @data: The secret data (full of zeros if this secret entry was deleted)
- */
- struct secret_entry {
- efi_guid_t guid;
- u32 len;
- u8 data[];
- } __attribute((packed));
- static size_t secret_entry_data_len(struct secret_entry *e)
- {
- return e->len - sizeof(*e);
- }
- static struct efi_secret the_efi_secret;
- static inline struct efi_secret *efi_secret_get(void)
- {
- return &the_efi_secret;
- }
- static int efi_secret_bin_file_show(struct seq_file *file, void *data)
- {
- struct secret_entry *e = file->private;
- if (e)
- seq_write(file, e->data, secret_entry_data_len(e));
- return 0;
- }
- DEFINE_SHOW_ATTRIBUTE(efi_secret_bin_file);
- /*
- * Overwrite memory content with zeroes, and ensure that dirty cache lines are
- * actually written back to memory, to clear out the secret.
- */
- static void wipe_memory(void *addr, size_t size)
- {
- memzero_explicit(addr, size);
- #ifdef CONFIG_X86
- clflush_cache_range(addr, size);
- #endif
- }
- static int efi_secret_unlink(struct inode *dir, struct dentry *dentry)
- {
- struct efi_secret *s = efi_secret_get();
- struct inode *inode = d_inode(dentry);
- struct secret_entry *e = (struct secret_entry *)inode->i_private;
- int i;
- if (e) {
- /* Zero out the secret data */
- wipe_memory(e->data, secret_entry_data_len(e));
- e->guid = NULL_GUID;
- }
- inode->i_private = NULL;
- for (i = 0; i < EFI_SECRET_NUM_FILES; i++)
- if (s->fs_files[i] == dentry)
- s->fs_files[i] = NULL;
- return simple_unlink(inode, dentry);
- }
- static const struct inode_operations efi_secret_dir_inode_operations = {
- .lookup = simple_lookup,
- .unlink = efi_secret_unlink,
- };
- static int efi_secret_map_area(struct platform_device *dev)
- {
- int ret;
- struct efi_secret *s = efi_secret_get();
- struct linux_efi_coco_secret_area *secret_area;
- if (efi.coco_secret == EFI_INVALID_TABLE_ADDR) {
- dev_err(&dev->dev, "Secret area address is not available\n");
- return -EINVAL;
- }
- secret_area = memremap(efi.coco_secret, sizeof(*secret_area), MEMREMAP_WB);
- if (secret_area == NULL) {
- dev_err(&dev->dev, "Could not map secret area EFI config entry\n");
- return -ENOMEM;
- }
- if (!secret_area->base_pa || secret_area->size < sizeof(struct secret_header)) {
- dev_err(&dev->dev,
- "Invalid secret area memory location (base_pa=0x%llx size=0x%llx)\n",
- secret_area->base_pa, secret_area->size);
- ret = -EINVAL;
- goto unmap;
- }
- s->secret_data = ioremap_encrypted(secret_area->base_pa, secret_area->size);
- if (s->secret_data == NULL) {
- dev_err(&dev->dev, "Could not map secret area\n");
- ret = -ENOMEM;
- goto unmap;
- }
- s->secret_data_len = secret_area->size;
- ret = 0;
- unmap:
- memunmap(secret_area);
- return ret;
- }
- static void efi_secret_securityfs_teardown(struct platform_device *dev)
- {
- struct efi_secret *s = efi_secret_get();
- int i;
- for (i = (EFI_SECRET_NUM_FILES - 1); i >= 0; i--) {
- securityfs_remove(s->fs_files[i]);
- s->fs_files[i] = NULL;
- }
- securityfs_remove(s->fs_dir);
- s->fs_dir = NULL;
- securityfs_remove(s->secrets_dir);
- s->secrets_dir = NULL;
- dev_dbg(&dev->dev, "Removed securityfs entries\n");
- }
- static int efi_secret_securityfs_setup(struct platform_device *dev)
- {
- struct efi_secret *s = efi_secret_get();
- int ret = 0, i = 0, bytes_left;
- unsigned char *ptr;
- struct secret_header *h;
- struct secret_entry *e;
- struct dentry *dent;
- char guid_str[EFI_VARIABLE_GUID_LEN + 1];
- ptr = (void __force *)s->secret_data;
- h = (struct secret_header *)ptr;
- if (efi_guidcmp(h->guid, EFI_SECRET_TABLE_HEADER_GUID)) {
- /*
- * This is not an error: it just means that EFI defines secret
- * area but it was not populated by the Guest Owner.
- */
- dev_dbg(&dev->dev, "EFI secret area does not start with correct GUID\n");
- return -ENODEV;
- }
- if (h->len < sizeof(*h)) {
- dev_err(&dev->dev, "EFI secret area reported length is too small\n");
- return -EINVAL;
- }
- if (h->len > s->secret_data_len) {
- dev_err(&dev->dev, "EFI secret area reported length is too big\n");
- return -EINVAL;
- }
- s->secrets_dir = NULL;
- s->fs_dir = NULL;
- memset(s->fs_files, 0, sizeof(s->fs_files));
- dent = securityfs_create_dir("secrets", NULL);
- if (IS_ERR(dent)) {
- dev_err(&dev->dev, "Error creating secrets securityfs directory entry err=%ld\n",
- PTR_ERR(dent));
- return PTR_ERR(dent);
- }
- s->secrets_dir = dent;
- dent = securityfs_create_dir("coco", s->secrets_dir);
- if (IS_ERR(dent)) {
- dev_err(&dev->dev, "Error creating coco securityfs directory entry err=%ld\n",
- PTR_ERR(dent));
- return PTR_ERR(dent);
- }
- d_inode(dent)->i_op = &efi_secret_dir_inode_operations;
- s->fs_dir = dent;
- bytes_left = h->len - sizeof(*h);
- ptr += sizeof(*h);
- while (bytes_left >= (int)sizeof(*e) && i < EFI_SECRET_NUM_FILES) {
- e = (struct secret_entry *)ptr;
- if (e->len < sizeof(*e) || e->len > (unsigned int)bytes_left) {
- dev_err(&dev->dev, "EFI secret area is corrupted\n");
- ret = -EINVAL;
- goto err_cleanup;
- }
- /* Skip deleted entries (which will have NULL_GUID) */
- if (efi_guidcmp(e->guid, NULL_GUID)) {
- efi_guid_to_str(&e->guid, guid_str);
- dent = securityfs_create_file(guid_str, 0440, s->fs_dir, (void *)e,
- &efi_secret_bin_file_fops);
- if (IS_ERR(dent)) {
- dev_err(&dev->dev, "Error creating efi_secret securityfs entry\n");
- ret = PTR_ERR(dent);
- goto err_cleanup;
- }
- s->fs_files[i++] = dent;
- }
- ptr += e->len;
- bytes_left -= e->len;
- }
- dev_info(&dev->dev, "Created %d entries in securityfs secrets/coco\n", i);
- return 0;
- err_cleanup:
- efi_secret_securityfs_teardown(dev);
- return ret;
- }
- static void efi_secret_unmap_area(void)
- {
- struct efi_secret *s = efi_secret_get();
- if (s->secret_data) {
- iounmap(s->secret_data);
- s->secret_data = NULL;
- s->secret_data_len = 0;
- }
- }
- static int efi_secret_probe(struct platform_device *dev)
- {
- int ret;
- ret = efi_secret_map_area(dev);
- if (ret)
- return ret;
- ret = efi_secret_securityfs_setup(dev);
- if (ret)
- goto err_unmap;
- return ret;
- err_unmap:
- efi_secret_unmap_area();
- return ret;
- }
- static void efi_secret_remove(struct platform_device *dev)
- {
- efi_secret_securityfs_teardown(dev);
- efi_secret_unmap_area();
- }
- static struct platform_driver efi_secret_driver = {
- .probe = efi_secret_probe,
- .remove_new = efi_secret_remove,
- .driver = {
- .name = "efi_secret",
- },
- };
- module_platform_driver(efi_secret_driver);
- MODULE_DESCRIPTION("Confidential computing EFI secret area access");
- MODULE_AUTHOR("IBM");
- MODULE_LICENSE("GPL");
- MODULE_ALIAS("platform:efi_secret");
|