Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

virt: Add efi_secret module to expose confidential computing secrets

The new efi_secret module exposes the confidential computing (coco)
EFI 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.

This allows applications running in a confidential computing setting to
read secrets provided by the guest owner via a secure secret injection
mechanism (such as AMD SEV's LAUNCH_SECRET command).

Removing (unlinking) files in the "secrets/coco" directory will zero out
the secret in memory, and remove the filesystem entry. If the module is
removed and loaded again, that secret will not appear in the filesystem.

Signed-off-by: Dov Murik <dovmurik@linux.ibm.com>
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
Link: https://lore.kernel.org/r/20220412212127.154182-3-dovmurik@linux.ibm.com
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>

authored by

Dov Murik and committed by
Ard Biesheuvel
cbabf03c 12274189

+422
+51
Documentation/ABI/testing/securityfs-secrets-coco
··· 1 + What: security/secrets/coco 2 + Date: February 2022 3 + Contact: Dov Murik <dovmurik@linux.ibm.com> 4 + Description: 5 + Exposes confidential computing (coco) EFI secrets to 6 + userspace via securityfs. 7 + 8 + EFI can declare memory area used by confidential computing 9 + platforms (such as AMD SEV and SEV-ES) for secret injection by 10 + the Guest Owner during VM's launch. The secrets are encrypted 11 + by the Guest Owner and decrypted inside the trusted enclave, 12 + and therefore are not readable by the untrusted host. 13 + 14 + The efi_secret module exposes the secrets to userspace. Each 15 + secret appears as a file under <securityfs>/secrets/coco, 16 + where the filename is the GUID of the entry in the secrets 17 + table. This module is loaded automatically by the EFI driver 18 + if the EFI secret area is populated. 19 + 20 + Two operations are supported for the files: read and unlink. 21 + Reading the file returns the content of secret entry. 22 + Unlinking the file overwrites the secret data with zeroes and 23 + removes the entry from the filesystem. A secret cannot be read 24 + after it has been unlinked. 25 + 26 + For example, listing the available secrets:: 27 + 28 + # modprobe efi_secret 29 + # ls -l /sys/kernel/security/secrets/coco 30 + -r--r----- 1 root root 0 Jun 28 11:54 736870e5-84f0-4973-92ec-06879ce3da0b 31 + -r--r----- 1 root root 0 Jun 28 11:54 83c83f7f-1356-4975-8b7e-d3a0b54312c6 32 + -r--r----- 1 root root 0 Jun 28 11:54 9553f55d-3da2-43ee-ab5d-ff17f78864d2 33 + -r--r----- 1 root root 0 Jun 28 11:54 e6f5a162-d67f-4750-a67c-5d065f2a9910 34 + 35 + Reading the secret data by reading a file:: 36 + 37 + # cat /sys/kernel/security/secrets/coco/e6f5a162-d67f-4750-a67c-5d065f2a9910 38 + the-content-of-the-secret-data 39 + 40 + Wiping a secret by unlinking a file:: 41 + 42 + # rm /sys/kernel/security/secrets/coco/e6f5a162-d67f-4750-a67c-5d065f2a9910 43 + # ls -l /sys/kernel/security/secrets/coco 44 + -r--r----- 1 root root 0 Jun 28 11:54 736870e5-84f0-4973-92ec-06879ce3da0b 45 + -r--r----- 1 root root 0 Jun 28 11:54 83c83f7f-1356-4975-8b7e-d3a0b54312c6 46 + -r--r----- 1 root root 0 Jun 28 11:54 9553f55d-3da2-43ee-ab5d-ff17f78864d2 47 + 48 + Note: The binary format of the secrets table injected by the 49 + Guest Owner is described in 50 + drivers/virt/coco/efi_secret/efi_secret.c under "Structure of 51 + the EFI secret area".
+3
drivers/virt/Kconfig
··· 47 47 source "drivers/virt/nitro_enclaves/Kconfig" 48 48 49 49 source "drivers/virt/acrn/Kconfig" 50 + 51 + source "drivers/virt/coco/efi_secret/Kconfig" 52 + 50 53 endif
+1
drivers/virt/Makefile
··· 9 9 10 10 obj-$(CONFIG_NITRO_ENCLAVES) += nitro_enclaves/ 11 11 obj-$(CONFIG_ACRN_HSM) += acrn/ 12 + obj-$(CONFIG_EFI_SECRET) += coco/efi_secret/
+16
drivers/virt/coco/efi_secret/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + config EFI_SECRET 3 + tristate "EFI secret area securityfs support" 4 + depends on EFI && X86_64 5 + select EFI_COCO_SECRET 6 + select SECURITYFS 7 + help 8 + This is a driver for accessing the EFI secret area via securityfs. 9 + The EFI secret area is a memory area designated by the firmware for 10 + confidential computing secret injection (for example for AMD SEV 11 + guests). The driver exposes the secrets as files in 12 + <securityfs>/secrets/coco. Files can be read and deleted (deleting 13 + a file wipes the secret from memory). 14 + 15 + To compile this driver as a module, choose M here. 16 + The module will be called efi_secret.
+2
drivers/virt/coco/efi_secret/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + obj-$(CONFIG_EFI_SECRET) += efi_secret.o
+349
drivers/virt/coco/efi_secret/efi_secret.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * efi_secret module 4 + * 5 + * Copyright (C) 2022 IBM Corporation 6 + * Author: Dov Murik <dovmurik@linux.ibm.com> 7 + */ 8 + 9 + /** 10 + * DOC: efi_secret: Allow reading EFI confidential computing (coco) secret area 11 + * via securityfs interface. 12 + * 13 + * When the module is loaded (and securityfs is mounted, typically under 14 + * /sys/kernel/security), a "secrets/coco" directory is created in securityfs. 15 + * In it, a file is created for each secret entry. The name of each such file 16 + * is the GUID of the secret entry, and its content is the secret data. 17 + */ 18 + 19 + #include <linux/platform_device.h> 20 + #include <linux/seq_file.h> 21 + #include <linux/fs.h> 22 + #include <linux/kernel.h> 23 + #include <linux/init.h> 24 + #include <linux/module.h> 25 + #include <linux/io.h> 26 + #include <linux/security.h> 27 + #include <linux/efi.h> 28 + #include <linux/cacheflush.h> 29 + 30 + #define EFI_SECRET_NUM_FILES 64 31 + 32 + struct efi_secret { 33 + struct dentry *secrets_dir; 34 + struct dentry *fs_dir; 35 + struct dentry *fs_files[EFI_SECRET_NUM_FILES]; 36 + void __iomem *secret_data; 37 + u64 secret_data_len; 38 + }; 39 + 40 + /* 41 + * Structure of the EFI secret area 42 + * 43 + * Offset Length 44 + * (bytes) (bytes) Usage 45 + * ------- ------- ----- 46 + * 0 16 Secret table header GUID (must be 1e74f542-71dd-4d66-963e-ef4287ff173b) 47 + * 16 4 Length of bytes of the entire secret area 48 + * 49 + * 20 16 First secret entry's GUID 50 + * 36 4 First secret entry's length in bytes (= 16 + 4 + x) 51 + * 40 x First secret entry's data 52 + * 53 + * 40+x 16 Second secret entry's GUID 54 + * 56+x 4 Second secret entry's length in bytes (= 16 + 4 + y) 55 + * 60+x y Second secret entry's data 56 + * 57 + * (... and so on for additional entries) 58 + * 59 + * The GUID of each secret entry designates the usage of the secret data. 60 + */ 61 + 62 + /** 63 + * struct secret_header - Header of entire secret area; this should be followed 64 + * by instances of struct secret_entry. 65 + * @guid: Must be EFI_SECRET_TABLE_HEADER_GUID 66 + * @len: Length in bytes of entire secret area, including header 67 + */ 68 + struct secret_header { 69 + efi_guid_t guid; 70 + u32 len; 71 + } __attribute((packed)); 72 + 73 + /** 74 + * struct secret_entry - Holds one secret entry 75 + * @guid: Secret-specific GUID (or NULL_GUID if this secret entry was deleted) 76 + * @len: Length of secret entry, including its guid and len fields 77 + * @data: The secret data (full of zeros if this secret entry was deleted) 78 + */ 79 + struct secret_entry { 80 + efi_guid_t guid; 81 + u32 len; 82 + u8 data[]; 83 + } __attribute((packed)); 84 + 85 + static size_t secret_entry_data_len(struct secret_entry *e) 86 + { 87 + return e->len - sizeof(*e); 88 + } 89 + 90 + static struct efi_secret the_efi_secret; 91 + 92 + static inline struct efi_secret *efi_secret_get(void) 93 + { 94 + return &the_efi_secret; 95 + } 96 + 97 + static int efi_secret_bin_file_show(struct seq_file *file, void *data) 98 + { 99 + struct secret_entry *e = file->private; 100 + 101 + if (e) 102 + seq_write(file, e->data, secret_entry_data_len(e)); 103 + 104 + return 0; 105 + } 106 + DEFINE_SHOW_ATTRIBUTE(efi_secret_bin_file); 107 + 108 + /* 109 + * Overwrite memory content with zeroes, and ensure that dirty cache lines are 110 + * actually written back to memory, to clear out the secret. 111 + */ 112 + static void wipe_memory(void *addr, size_t size) 113 + { 114 + memzero_explicit(addr, size); 115 + #ifdef CONFIG_X86 116 + clflush_cache_range(addr, size); 117 + #endif 118 + } 119 + 120 + static int efi_secret_unlink(struct inode *dir, struct dentry *dentry) 121 + { 122 + struct efi_secret *s = efi_secret_get(); 123 + struct inode *inode = d_inode(dentry); 124 + struct secret_entry *e = (struct secret_entry *)inode->i_private; 125 + int i; 126 + 127 + if (e) { 128 + /* Zero out the secret data */ 129 + wipe_memory(e->data, secret_entry_data_len(e)); 130 + e->guid = NULL_GUID; 131 + } 132 + 133 + inode->i_private = NULL; 134 + 135 + for (i = 0; i < EFI_SECRET_NUM_FILES; i++) 136 + if (s->fs_files[i] == dentry) 137 + s->fs_files[i] = NULL; 138 + 139 + /* 140 + * securityfs_remove tries to lock the directory's inode, but we reach 141 + * the unlink callback when it's already locked 142 + */ 143 + inode_unlock(dir); 144 + securityfs_remove(dentry); 145 + inode_lock(dir); 146 + 147 + return 0; 148 + } 149 + 150 + static const struct inode_operations efi_secret_dir_inode_operations = { 151 + .lookup = simple_lookup, 152 + .unlink = efi_secret_unlink, 153 + }; 154 + 155 + static int efi_secret_map_area(struct platform_device *dev) 156 + { 157 + int ret; 158 + struct efi_secret *s = efi_secret_get(); 159 + struct linux_efi_coco_secret_area *secret_area; 160 + 161 + if (efi.coco_secret == EFI_INVALID_TABLE_ADDR) { 162 + dev_err(&dev->dev, "Secret area address is not available\n"); 163 + return -EINVAL; 164 + } 165 + 166 + secret_area = memremap(efi.coco_secret, sizeof(*secret_area), MEMREMAP_WB); 167 + if (secret_area == NULL) { 168 + dev_err(&dev->dev, "Could not map secret area EFI config entry\n"); 169 + return -ENOMEM; 170 + } 171 + if (!secret_area->base_pa || secret_area->size < sizeof(struct secret_header)) { 172 + dev_err(&dev->dev, 173 + "Invalid secret area memory location (base_pa=0x%llx size=0x%llx)\n", 174 + secret_area->base_pa, secret_area->size); 175 + ret = -EINVAL; 176 + goto unmap; 177 + } 178 + 179 + s->secret_data = ioremap_encrypted(secret_area->base_pa, secret_area->size); 180 + if (s->secret_data == NULL) { 181 + dev_err(&dev->dev, "Could not map secret area\n"); 182 + ret = -ENOMEM; 183 + goto unmap; 184 + } 185 + 186 + s->secret_data_len = secret_area->size; 187 + ret = 0; 188 + 189 + unmap: 190 + memunmap(secret_area); 191 + return ret; 192 + } 193 + 194 + static void efi_secret_securityfs_teardown(struct platform_device *dev) 195 + { 196 + struct efi_secret *s = efi_secret_get(); 197 + int i; 198 + 199 + for (i = (EFI_SECRET_NUM_FILES - 1); i >= 0; i--) { 200 + securityfs_remove(s->fs_files[i]); 201 + s->fs_files[i] = NULL; 202 + } 203 + 204 + securityfs_remove(s->fs_dir); 205 + s->fs_dir = NULL; 206 + 207 + securityfs_remove(s->secrets_dir); 208 + s->secrets_dir = NULL; 209 + 210 + dev_dbg(&dev->dev, "Removed securityfs entries\n"); 211 + } 212 + 213 + static int efi_secret_securityfs_setup(struct platform_device *dev) 214 + { 215 + struct efi_secret *s = efi_secret_get(); 216 + int ret = 0, i = 0, bytes_left; 217 + unsigned char *ptr; 218 + struct secret_header *h; 219 + struct secret_entry *e; 220 + struct dentry *dent; 221 + char guid_str[EFI_VARIABLE_GUID_LEN + 1]; 222 + 223 + ptr = (void __force *)s->secret_data; 224 + h = (struct secret_header *)ptr; 225 + if (efi_guidcmp(h->guid, EFI_SECRET_TABLE_HEADER_GUID)) { 226 + /* 227 + * This is not an error: it just means that EFI defines secret 228 + * area but it was not populated by the Guest Owner. 229 + */ 230 + dev_dbg(&dev->dev, "EFI secret area does not start with correct GUID\n"); 231 + return -ENODEV; 232 + } 233 + if (h->len < sizeof(*h)) { 234 + dev_err(&dev->dev, "EFI secret area reported length is too small\n"); 235 + return -EINVAL; 236 + } 237 + if (h->len > s->secret_data_len) { 238 + dev_err(&dev->dev, "EFI secret area reported length is too big\n"); 239 + return -EINVAL; 240 + } 241 + 242 + s->secrets_dir = NULL; 243 + s->fs_dir = NULL; 244 + memset(s->fs_files, 0, sizeof(s->fs_files)); 245 + 246 + dent = securityfs_create_dir("secrets", NULL); 247 + if (IS_ERR(dent)) { 248 + dev_err(&dev->dev, "Error creating secrets securityfs directory entry err=%ld\n", 249 + PTR_ERR(dent)); 250 + return PTR_ERR(dent); 251 + } 252 + s->secrets_dir = dent; 253 + 254 + dent = securityfs_create_dir("coco", s->secrets_dir); 255 + if (IS_ERR(dent)) { 256 + dev_err(&dev->dev, "Error creating coco securityfs directory entry err=%ld\n", 257 + PTR_ERR(dent)); 258 + return PTR_ERR(dent); 259 + } 260 + d_inode(dent)->i_op = &efi_secret_dir_inode_operations; 261 + s->fs_dir = dent; 262 + 263 + bytes_left = h->len - sizeof(*h); 264 + ptr += sizeof(*h); 265 + while (bytes_left >= (int)sizeof(*e) && i < EFI_SECRET_NUM_FILES) { 266 + e = (struct secret_entry *)ptr; 267 + if (e->len < sizeof(*e) || e->len > (unsigned int)bytes_left) { 268 + dev_err(&dev->dev, "EFI secret area is corrupted\n"); 269 + ret = -EINVAL; 270 + goto err_cleanup; 271 + } 272 + 273 + /* Skip deleted entries (which will have NULL_GUID) */ 274 + if (efi_guidcmp(e->guid, NULL_GUID)) { 275 + efi_guid_to_str(&e->guid, guid_str); 276 + 277 + dent = securityfs_create_file(guid_str, 0440, s->fs_dir, (void *)e, 278 + &efi_secret_bin_file_fops); 279 + if (IS_ERR(dent)) { 280 + dev_err(&dev->dev, "Error creating efi_secret securityfs entry\n"); 281 + ret = PTR_ERR(dent); 282 + goto err_cleanup; 283 + } 284 + 285 + s->fs_files[i++] = dent; 286 + } 287 + ptr += e->len; 288 + bytes_left -= e->len; 289 + } 290 + 291 + dev_info(&dev->dev, "Created %d entries in securityfs secrets/coco\n", i); 292 + return 0; 293 + 294 + err_cleanup: 295 + efi_secret_securityfs_teardown(dev); 296 + return ret; 297 + } 298 + 299 + static void efi_secret_unmap_area(void) 300 + { 301 + struct efi_secret *s = efi_secret_get(); 302 + 303 + if (s->secret_data) { 304 + iounmap(s->secret_data); 305 + s->secret_data = NULL; 306 + s->secret_data_len = 0; 307 + } 308 + } 309 + 310 + static int efi_secret_probe(struct platform_device *dev) 311 + { 312 + int ret; 313 + 314 + ret = efi_secret_map_area(dev); 315 + if (ret) 316 + return ret; 317 + 318 + ret = efi_secret_securityfs_setup(dev); 319 + if (ret) 320 + goto err_unmap; 321 + 322 + return ret; 323 + 324 + err_unmap: 325 + efi_secret_unmap_area(); 326 + return ret; 327 + } 328 + 329 + static int efi_secret_remove(struct platform_device *dev) 330 + { 331 + efi_secret_securityfs_teardown(dev); 332 + efi_secret_unmap_area(); 333 + return 0; 334 + } 335 + 336 + static struct platform_driver efi_secret_driver = { 337 + .probe = efi_secret_probe, 338 + .remove = efi_secret_remove, 339 + .driver = { 340 + .name = "efi_secret", 341 + }, 342 + }; 343 + 344 + module_platform_driver(efi_secret_driver); 345 + 346 + MODULE_DESCRIPTION("Confidential computing EFI secret area access"); 347 + MODULE_AUTHOR("IBM"); 348 + MODULE_LICENSE("GPL"); 349 + MODULE_ALIAS("platform:efi_secret");