Confidential computing (coco) hardware such as AMD SEV (Secure Encrypted
Virtualization) allows guest owners to inject secrets into the VMs
memory without the host/hypervisor being able to read them. In SEV,
secret injection is performed early in the VM launch process, before the
guest starts running.
OVMF already reserves designated area for secret injection (in its
AmdSev package; see edk2 commit 01726b6d23d4 "OvmfPkg/AmdSev: Expose the
Sev Secret area using a configuration table" [1]), but the secrets were
not available in the guest kernel.
The patch series copies the secrets from the EFI-provided memory to
kernel reserved memory, and optionally exposes them to userspace via
securityfs using a new sev_secret kernel module.
The first patch in efi/libstub copies the secret area from the EFI
memory to specially allocated memory; the second patch reserves that
memory block; and the third patch introduces the new sev_secret module
that exposes the content of the secret entries as securityfs files, and
allows clearing out secrets with a file unlink interface.
As a usage example, consider a guest performing computations on
encrypted files. The Guest Owner provides the decryption key (= secret)
using the secret injection mechanism. The guest application reads the
secret from the sev_secret filesystem and proceeds to decrypt the files
into memory and then performs the needed computations on the content.
In this example, the host can't read the files from the disk image
because they are encrypted. Host can't read the decryption key because
it is passed using the secret injection mechanism (= secure channel).
Host can't read the decrypted content from memory because it's a
confidential (memory-encrypted) guest.
This has been tested with AMD SEV guests, but the kernel side of
handling the secret area has no SEV-specific dependencies, and therefore
might be usable (perhaps with minor changes) for any confidential
computing hardware that can publish the secret area via the standard EFI
config table entry.
Here is a simple example for usage of the sev_secret module in a guest
to which a secret are with 4 secrets was injected during launch:
# modprobe sev_secret
# ls -la /sys/kernel/security/coco/sev_secret
total 0
drwxr-xr-x 2 root root 0 Jun 28 11:54 .
drwxr-xr-x 3 root root 0 Jun 28 11:54 ..
-r--r----- 1 root root 0 Jun 28 11:54 736870e5-84f0-4973-92ec-06879ce3da0b
-r--r----- 1 root root 0 Jun 28 11:54 83c83f7f-1356-4975-8b7e-d3a0b54312c6
-r--r----- 1 root root 0 Jun 28 11:54 9553f55d-3da2-43ee-ab5d-ff17f78864d2
-r--r----- 1 root root 0 Jun 28 11:54 e6f5a162-d67f-4750-a67c-5d065f2a9910
# xxd /sys/kernel/security/coco/sev_secret/e6f5a162-d67f-4750-a67c-5d065f2a9910
00000000: 7468 6573 652d 6172 652d 7468 652d 6b61 these-are-the-ka
00000010: 7461 2d73 6563 7265 7473 0001 0203 0405 ta-secrets......
00000020: 0607 ..
# rm /sys/kernel/security/coco/sev_secret/e6f5a162-d67f-4750-a67c-5d065f2a9910
# ls -la /sys/kernel/security/coco/sev_secret
total 0
drwxr-xr-x 2 root root 0 Jun 28 11:55 .
drwxr-xr-x 3 root root 0 Jun 28 11:54 ..
-r--r----- 1 root root 0 Jun 28 11:54 736870e5-84f0-4973-92ec-06879ce3da0b
-r--r----- 1 root root 0 Jun 28 11:54 83c83f7f-1356-4975-8b7e-d3a0b54312c6
-r--r----- 1 root root 0 Jun 28 11:54 9553f55d-3da2-43ee-ab5d-ff17f78864d2
Previously sent as an RFC series [2].
[1] https://github.com/tianocore/edk2/commit/01726b6d23d4
[2] https://lore.kernel.org/linux-coco/20210628183431.953934-1-dovmurik@linux.ibm.com/
Dov Murik (3):
efi/libstub: Copy confidential computing secret area
efi: Reserve confidential computing secret area
virt: Add sev_secret module to expose confidential computing secrets
arch/x86/platform/efi/efi.c | 1 +
drivers/firmware/efi/Makefile | 2 +-
drivers/firmware/efi/coco.c | 41 +++
drivers/firmware/efi/efi.c | 3 +
drivers/firmware/efi/libstub/Makefile | 2 +-
drivers/firmware/efi/libstub/coco.c | 68 +++++
drivers/firmware/efi/libstub/efi-stub.c | 2 +
drivers/firmware/efi/libstub/efistub.h | 2 +
drivers/firmware/efi/libstub/x86-stub.c | 2 +
drivers/virt/Kconfig | 3 +
drivers/virt/Makefile | 1 +
drivers/virt/coco/sev_secret/Kconfig | 11 +
drivers/virt/coco/sev_secret/Makefile | 2 +
drivers/virt/coco/sev_secret/sev_secret.c | 313 ++++++++++++++++++++++
include/linux/efi.h | 9 +
15 files changed, 460 insertions(+), 2 deletions(-)
create mode 100644 drivers/firmware/efi/coco.c
create mode 100644 drivers/firmware/efi/libstub/coco.c
create mode 100644 drivers/virt/coco/sev_secret/Kconfig
create mode 100644 drivers/virt/coco/sev_secret/Makefile
create mode 100644 drivers/virt/coco/sev_secret/sev_secret.c
base-commit: 36a21d51725af2ce0700c6ebcb6b9594aac658a6
--
2.25.1
The new sev_secret module exposes the confidential computing (coco)
secret area via securityfs interface.
When the module is loaded (and securityfs is mounted, typically under
/sys/kernel/security), a "coco/sev_secret" 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 "coco/sev_secret" 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 <redacted>
---
drivers/virt/Kconfig | 3 +
drivers/virt/Makefile | 1 +
drivers/virt/coco/sev_secret/Kconfig | 11 +
drivers/virt/coco/sev_secret/Makefile | 2 +
drivers/virt/coco/sev_secret/sev_secret.c | 313 ++++++++++++++++++++++
5 files changed, 330 insertions(+)
create mode 100644 drivers/virt/coco/sev_secret/Kconfig
create mode 100644 drivers/virt/coco/sev_secret/Makefile
create mode 100644 drivers/virt/coco/sev_secret/sev_secret.c
@@ -0,0 +1,313 @@+// SPDX-License-Identifier: GPL-2.0+/*+*sev_secretmodule+*+*Copyright(C)2021IBMCorporation+*Author:DovMurik<dovmurik@linux.ibm.com>+*/++/**+*DOC:sev_secret:Allowreadingconfidentialcomputing(coco)secretareavia+*securityfsinterface.+*+*Whenthemoduleisloaded(andsecurityfsismounted,typicallyunder+*/sys/kernel/security),a"coco/sev_secret"directoryiscreatedin+*securityfs.Init,afileiscreatedforeachsecretentry.Thenameof+*eachsuchfileistheGUIDofthesecretentry,anditscontentisthe+*secretdata.+*/++#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>++#define SEV_SECRET_NUM_FILES 64++#define EFI_SEVSECRET_TABLE_HEADER_GUID \+EFI_GUID(0x1e74f542,0x71dd,0x4d66,0x96,0x3e,0xef,0x42,0x87,0xff,0x17,0x3b)++structsev_secret{+structdentry*coco_dir;+structdentry*fs_dir;+structdentry*fs_files[SEV_SECRET_NUM_FILES];+structlinux_efi_coco_secret_area*secret_area;+};++/*+*StructureoftheSEVsecretarea+*+*OffsetLength+*(bytes)(bytes)Usage+*-------------------+*016SecrettableheaderGUID(mustbe1e74f542-71dd-4d66-963e-ef4287ff173b)+*164Lengthofbytesoftheentiresecretarea+*+*2016Firstsecretentry'sGUID+*364Firstsecretentry'slengthinbytes(=16+4+x)+*40xFirstsecretentry'sdata+*+*40+x16Secondsecretentry'sGUID+*56+x4Secondsecretentry'slengthinbytes(=16+4+y)+*60+xySecondsecretentry'sdata+*+*(...andsoonforadditionalentries)+*+*TheGUIDofeachsecretentrydesignatestheusageofthesecretdata.+*/++/**+*structsecret_header-Headerofentiresecretarea;thisshouldbefollowed+*byinstancesofstructsecret_entry.+*@guid:MustbeEFI_SEVSECRET_TABLE_HEADER_GUID+*@len:Lengthinbytesofentiresecretarea,includingheader+*/+structsecret_header{+efi_guid_tguid;+u32len;+}__attribute((packed));++/**+*structsecret_entry-Holdsonesecretentry+*@guid:Secret-specificGUID(orNULL_GUIDifthissecretentrywasdeleted)+*@len:Lengthofsecretentry,includingitsguidandlenfields+*@data:Thesecretdata(fullofzerosifthissecretentrywasdeleted)+*/+structsecret_entry{+efi_guid_tguid;+u32len;+u8data[];+}__attribute((packed));++staticsize_tsecret_entry_data_len(structsecret_entry*e)+{+returne->len-sizeof(*e);+}++staticstructsev_secretthe_sev_secret;++staticinlinestructsev_secret*sev_secret_get(void)+{+return&the_sev_secret;+}++staticintsev_secret_bin_file_show(structseq_file*file,void*data)+{+structsecret_entry*e=file->private;++if(e)+seq_write(file,e->data,secret_entry_data_len(e));++return0;+}+DEFINE_SHOW_ATTRIBUTE(sev_secret_bin_file);++staticintsev_secret_unlink(structinode*dir,structdentry*dentry)+{+structsev_secret*s=sev_secret_get();+structinode*inode=d_inode(dentry);+structsecret_entry*e=(structsecret_entry*)inode->i_private;+inti;++if(e){+/* Zero out the secret data */+memzero_explicit(e->data,secret_entry_data_len(e));+e->guid=NULL_GUID;+}++inode->i_private=NULL;++for(i=0;i<SEV_SECRET_NUM_FILES;i++)+if(s->fs_files[i]==dentry)+s->fs_files[i]=NULL;++/*+*securityfs_removetriestolockthedirectory'sinode,butwereach+*theunlinkcallbackwhenit'salreadylocked+*/+inode_unlock(dir);+securityfs_remove(dentry);+inode_lock(dir);++return0;+}++staticconststructinode_operationssev_secret_dir_inode_operations={+.lookup=simple_lookup,+.unlink=sev_secret_unlink,+};++staticintsev_secret_map_area(void)+{+structsev_secret*s=sev_secret_get();+structlinux_efi_coco_secret_area*secret_area;+u32secret_area_size;++if(efi.coco_secret==EFI_INVALID_TABLE_ADDR){+pr_err("Secret area address is not available\n");+return-EINVAL;+}++secret_area=memremap(efi.coco_secret,sizeof(*secret_area),MEMREMAP_WB);+if(secret_area==NULL){+pr_err("Could not map secret area header\n");+return-ENOMEM;+}++secret_area_size=sizeof(*secret_area)+secret_area->size;+memunmap(secret_area);++secret_area=memremap(efi.coco_secret,secret_area_size,MEMREMAP_WB);+if(secret_area==NULL){+pr_err("Could not map secret area\n");+return-ENOMEM;+}++s->secret_area=secret_area;+return0;+}++staticvoidsev_secret_securityfs_teardown(void)+{+structsev_secret*s=sev_secret_get();+inti;++for(i=(SEV_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->coco_dir);+s->coco_dir=NULL;++pr_debug("Removed sev_secret securityfs entries\n");+}++staticintsev_secret_securityfs_setup(void)+{+efi_guid_ttableheader_guid=EFI_SEVSECRET_TABLE_HEADER_GUID;+structsev_secret*s=sev_secret_get();+intret=0,i=0,bytes_left;+unsignedchar*ptr;+structsecret_header*h;+structsecret_entry*e;+structdentry*dent;+charguid_str[EFI_VARIABLE_GUID_LEN+1];++s->coco_dir=NULL;+s->fs_dir=NULL;+memset(s->fs_files,0,sizeof(s->fs_files));++dent=securityfs_create_dir("coco",NULL);+if(IS_ERR(dent)){+pr_err("Error creating coco securityfs directory entry err=%ld\n",PTR_ERR(dent));+returnPTR_ERR(dent);+}+s->coco_dir=dent;++dent=securityfs_create_dir("sev_secret",s->coco_dir);+if(IS_ERR(dent)){+pr_err("Error creating SEV secret securityfs directory entry err=%ld\n",+PTR_ERR(dent));+returnPTR_ERR(dent);+}+d_inode(dent)->i_op=&sev_secret_dir_inode_operations;+s->fs_dir=dent;++ptr=s->secret_area->area;+h=(structsecret_header*)ptr;+if(memcmp(&h->guid,&tableheader_guid,sizeof(h->guid))){+pr_err("SEV secret area does not start with correct GUID\n");+ret=-EINVAL;+gotoerr_cleanup;+}+if(h->len<sizeof(*h)){+pr_err("SEV secret area reported length is too small\n");+ret=-EINVAL;+gotoerr_cleanup;+}++bytes_left=h->len-sizeof(*h);+ptr+=sizeof(*h);+while(bytes_left>=(int)sizeof(*e)&&i<SEV_SECRET_NUM_FILES){+e=(structsecret_entry*)ptr;+if(e->len<sizeof(*e)||e->len>(unsignedint)bytes_left){+pr_err("SEV secret area is corrupted\n");+ret=-EINVAL;+gotoerr_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,+&sev_secret_bin_file_fops);+if(IS_ERR(dent)){+pr_err("Error creating SEV secret securityfs entry\n");+ret=PTR_ERR(dent);+gotoerr_cleanup;+}++s->fs_files[i++]=dent;+}+ptr+=e->len;+bytes_left-=e->len;+}++pr_debug("Created %d entries in sev_secret securityfs\n",i);+return0;++err_cleanup:+sev_secret_securityfs_teardown();+returnret;+}++staticvoidsev_secret_unmap_area(void)+{+structsev_secret*s=sev_secret_get();++if(s->secret_area){+memunmap(s->secret_area);+s->secret_area=NULL;+}+}++staticint__initsev_secret_init(void)+{+intret;++ret=sev_secret_map_area();+if(ret)+returnret;++ret=sev_secret_securityfs_setup();+if(ret)+gotoerr_unmap;++returnret;++err_unmap:+sev_secret_unmap_area();+returnret;+}++staticvoid__exitsev_secret_exit(void)+{+sev_secret_securityfs_teardown();+sev_secret_unmap_area();+}++module_init(sev_secret_init);+module_exit(sev_secret_exit);++MODULE_DESCRIPTION("AMD SEV confidential computing secret area access");+MODULE_AUTHOR("IBM");+MODULE_LICENSE("GPL");
Confidential computing (coco) hardware such as AMD SEV (Secure Encrypted
Virtualization) allows a guest owner to inject secrets into the VMs
memory without the host/hypervisor being able to read them.
Firmware support for secret injection is available in OVMF, which
reserves a memory area for secret injection and includes a pointer to it
the in EFI config table entry LINUX_EFI_COCO_SECRET_TABLE_GUID.
However, OVMF doesn't force the guest OS to keep this memory area
reserved.
If EFI exposes such a table entry, efi/libstub will copy this area to a
reserved memory for future use inside the kernel.
A pointer to the new copy is kept in the EFI table under
LINUX_EFI_COCO_SECRET_AREA_GUID.
Signed-off-by: Dov Murik <redacted>
---
drivers/firmware/efi/libstub/Makefile | 2 +-
drivers/firmware/efi/libstub/coco.c | 68 +++++++++++++++++++++++++
drivers/firmware/efi/libstub/efi-stub.c | 2 +
drivers/firmware/efi/libstub/efistub.h | 2 +
drivers/firmware/efi/libstub/x86-stub.c | 2 +
include/linux/efi.h | 6 +++
6 files changed, 81 insertions(+), 1 deletion(-)
create mode 100644 drivers/firmware/efi/libstub/coco.c
@@ -55,7 +55,7 @@ KCOV_INSTRUMENT := nlib-y:=efi-stub-helper.ogop.osecureboot.otpm.o\file.omem.orandom.orandomalloc.opci.o\skip_spaces.olib-cmdline.olib-ctype.o\-alignedmem.orelocate.ovsprintf.o+alignedmem.orelocate.ovsprintf.ococo.o# include the stub's generic dependencies from lib/ when building for ARM/arm64efi-deps-y:=fdt_rw.cfdt_ro.cfdt_wip.cfdt.cfdt_empty_tree.cfdt_sw.c
@@ -0,0 +1,68 @@+// SPDX-License-Identifier: GPL-2.0+/*+*Confidentialcomputing(coco)secretareahandling+*+*Copyright(C)2021IBMCorporation+*Author:DovMurik<dovmurik@linux.ibm.com>+*/++#include<linux/efi.h>+#include<linux/sizes.h>+#include<asm/efi.h>++#include"efistub.h"++#define LINUX_EFI_COCO_SECRET_TABLE_GUID \+EFI_GUID(0xadf956ad,0xe98c,0x484c,0xae,0x11,0xb5,0x1c,0x7d,0x33,0x64,0x47)++/**+*structefi_coco_secret_table-EFIconfigtablethatpointstothe+*confidentialcomputingsecretarea.Theguid+*LINUX_EFI_COCO_SECRET_TABLE_GUIDholdsthistable.+*@base:PhysicaladdressoftheEFIsecretarea+*@size:Size(inbytes)oftheEFIsecretarea+*/+structefi_coco_secret_table{+u64base;+u64size;+}__attribute((packed));++/*+*CreateacopyofEFI'sconfidentialcomputingsecretarea(ifavailable)so+*thatthesecretsareaccessibleinthekernelafterExitBootServices.+*/+voidefi_copy_coco_secret_area(void)+{+efi_guid_tlinux_secret_area_guid=LINUX_EFI_COCO_SECRET_AREA_GUID;+efi_status_tstatus;+structefi_coco_secret_table*secret_table;+structlinux_efi_coco_secret_area*secret_area;++secret_table=get_efi_config_table(LINUX_EFI_COCO_SECRET_TABLE_GUID);+if(!secret_table)+return;++if(secret_table->size==0||secret_table->size>=SZ_4G)+return;++/* Allocate space for the secret area and copy it */+status=efi_bs_call(allocate_pool,EFI_LOADER_DATA,+sizeof(*secret_area)+secret_table->size,(void**)&secret_area);++if(status!=EFI_SUCCESS){+efi_err("Unable to allocate memory for confidential computing secret area copy\n");+return;+}++secret_area->size=secret_table->size;+memcpy(secret_area->area,(void*)(unsignedlong)secret_table->base,secret_table->size);++status=efi_bs_call(install_configuration_table,&linux_secret_area_guid,secret_area);+if(status!=EFI_SUCCESS)+gotoerr_free;++return;++err_free:+efi_bs_call(free_pool,secret_area);+}
From: Andrew Scull <hidden> Date: 2021-08-13 13:05:46
On Mon, Aug 09, 2021 at 07:01:57PM +0000, Dov Murik wrote:
The new sev_secret module exposes the confidential computing (coco)
secret area via securityfs interface.
When the module is loaded (and securityfs is mounted, typically under
/sys/kernel/security), a "coco/sev_secret" 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 "coco/sev_secret" 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.
We've also been looking into a similar secret mechanism recently in the
context of Android and protected KVM [1]. Our secrets would come from a
different source, likely described as a reserved-memory node in the DT,
but would need to be exposed to userspace in the same way as the SEV
secrets. Originally I tried using a character device, but this approach
with securityfs feels neater to me.
We're also looking to pass secrets from the bootloader to Linux, outside
of any virtualization or confidential compute context (at least a far as
I have understood the meaning of the term). Again, this feels like it
would be exposed to userspace in the same way.
It would be good to be able to share the parts that would be common. I
expect that would mean the operations for a secret file and for a
directory of secrets at a minimum. But it might also influence the paths
in securityfs; I see, looking back, that the "coco" directory was added
since the RFC but would a generalized "secret" subsystem make sense? Or
would it be preferable for each case to define their own path?
[1] -- https://lwn.net/Articles/836693/
+static int sev_secret_unlink(struct inode *dir, struct dentry *dentry)
+{
+ struct sev_secret *s = sev_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 */
+ memzero_explicit(e->data, secret_entry_data_len(e));
Would there be a benefit in flushing these zeros?
+ e->guid = NULL_GUID;
+ }
+
+ inode->i_private = NULL;
+
+ for (i = 0; i < SEV_SECRET_NUM_FILES; i++)
+ if (s->fs_files[i] == dentry)
+ s->fs_files[i] = NULL;
+
+ /*
+ * securityfs_remove tries to lock the directory's inode, but we reach
+ * the unlink callback when it's already locked
+ */
+ inode_unlock(dir);
+ securityfs_remove(dentry);
+ inode_lock(dir);
+
+ return 0;
+}
On Fri, 13 Aug 2021 at 15:05, Andrew Scull [off-list ref] wrote:
On Mon, Aug 09, 2021 at 07:01:57PM +0000, Dov Murik wrote:
quoted
The new sev_secret module exposes the confidential computing (coco)
secret area via securityfs interface.
When the module is loaded (and securityfs is mounted, typically under
/sys/kernel/security), a "coco/sev_secret" 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 "coco/sev_secret" 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.
We've also been looking into a similar secret mechanism recently in the
context of Android and protected KVM [1]. Our secrets would come from a
different source, likely described as a reserved-memory node in the DT,
but would need to be exposed to userspace in the same way as the SEV
secrets. Originally I tried using a character device, but this approach
with securityfs feels neater to me.
Agreed. I particularly like how deleting the file wipes the secret from memory.
We're also looking to pass secrets from the bootloader to Linux, outside
of any virtualization or confidential compute context (at least a far as
I have understood the meaning of the term). Again, this feels like it
would be exposed to userspace in the same way.
Indeed.
It would be good to be able to share the parts that would be common. I
expect that would mean the operations for a secret file and for a
directory of secrets at a minimum. But it might also influence the paths
in securityfs; I see, looking back, that the "coco" directory was added
since the RFC but would a generalized "secret" subsystem make sense? Or
would it be preferable for each case to define their own path?
I think we should avoid 'secret', to be honest. Even if protected KVM
is not riding the SEV/TDX wave, I think confidential computing is
still an accurate description of its semantics.
From: Andrew Scull <hidden> Date: 2021-08-19 13:03:00
On Mon, 16 Aug 2021 at 10:57, Ard Biesheuvel [off-list ref] wrote:
On Fri, 13 Aug 2021 at 15:05, Andrew Scull [off-list ref] wrote:
quoted
On Mon, Aug 09, 2021 at 07:01:57PM +0000, Dov Murik wrote:
quoted
The new sev_secret module exposes the confidential computing (coco)
secret area via securityfs interface.
When the module is loaded (and securityfs is mounted, typically under
/sys/kernel/security), a "coco/sev_secret" 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 "coco/sev_secret" 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.
We've also been looking into a similar secret mechanism recently in the
context of Android and protected KVM [1]. Our secrets would come from a
different source, likely described as a reserved-memory node in the DT,
but would need to be exposed to userspace in the same way as the SEV
secrets. Originally I tried using a character device, but this approach
with securityfs feels neater to me.
Agreed. I particularly like how deleting the file wipes the secret from memory.
quoted
We're also looking to pass secrets from the bootloader to Linux, outside
of any virtualization or confidential compute context (at least a far as
I have understood the meaning of the term). Again, this feels like it
would be exposed to userspace in the same way.
Indeed.
quoted
It would be good to be able to share the parts that would be common. I
expect that would mean the operations for a secret file and for a
directory of secrets at a minimum. But it might also influence the paths
in securityfs; I see, looking back, that the "coco" directory was added
since the RFC but would a generalized "secret" subsystem make sense? Or
would it be preferable for each case to define their own path?
I think we should avoid 'secret', to be honest. Even if protected KVM
is not riding the SEV/TDX wave, I think confidential computing is
still an accurate description of its semantics.
I agree that protected KVM fits with the ideas of confidential
computing. It was the non-virtualization context that I was less
certain about. For example, the Open Profile for DICE [2] starts with
a hardware secret and derives, at each boot stage, a secret that is
passed to the next stage. It's a process that applies both to a VM,
matching confidential compute as I understand it, but also the host
Linux, which is the part that I wasn't so clear on.
[2] -- https://pigweed.googlesource.com/open-dice/+/refs/heads/main/docs/specification.md
On Mon, 16 Aug 2021 at 10:57, Ard Biesheuvel [off-list ref] wrote:
quoted
On Fri, 13 Aug 2021 at 15:05, Andrew Scull [off-list ref] wrote:
quoted
On Mon, Aug 09, 2021 at 07:01:57PM +0000, Dov Murik wrote:
[...]
quoted
quoted
quoted
+static int sev_secret_unlink(struct inode *dir, struct dentry *dentry)
+{
+ struct sev_secret *s = sev_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 */
+ memzero_explicit(e->data, secret_entry_data_len(e));
Would there be a benefit in flushing these zeros?
Do you mean cache clean+invalidate? Better to be precise here.
At least a clean, to have the zeros written back to memory from the
cache, in order to overwrite the secret.
I agree, but not sure how to implement this:
I see there's an arch_wb_cache_pmem exported function which internally
(in arch/x86/lib/usercopy_64.c) calls clean_cache_range which seems to
do what we want (assume the secret can be longer than the cache line).
But arch_wb_cache_pmem is declared in include/linux/libnvdimm.h and
guarded with #ifdef CONFIG_ARCH_HAS_PMEM_API -- both seem not related to
what I'm trying to do.
I see there's an exported clflush_cache_range for x86 -- but that's a
clean+flush if I understand correctly.
Suggestions on how to approach? I can copy the clean_cache_range
implementation into the sev_secret module but hopefully there's a better
way to reuse. Maybe export clean_cache_range in x86?
Since this is for SEV the solution can be x86-specific, but if there's a
generic way I guess it's better (I think all of sev_secret module
doesn't have x86-specific stuff).
-Dov
quoted
quoted
quoted
+ e->guid = NULL_GUID;
+ }
+
+ inode->i_private = NULL;
+
+ for (i = 0; i < SEV_SECRET_NUM_FILES; i++)
+ if (s->fs_files[i] == dentry)
+ s->fs_files[i] = NULL;
+
+ /*
+ * securityfs_remove tries to lock the directory's inode, but we reach
+ * the unlink callback when it's already locked
+ */
+ inode_unlock(dir);
+ securityfs_remove(dentry);
+ inode_lock(dir);
+
+ return 0;
+}
From: Andrew Scull <hidden> Date: 2021-08-23 19:22:16
On Fri, 20 Aug 2021 at 19:36, Dov Murik [off-list ref] wrote:
On 19/08/2021 16:02, Andrew Scull wrote:
quoted
On Mon, 16 Aug 2021 at 10:57, Ard Biesheuvel [off-list ref] wrote:
quoted
On Fri, 13 Aug 2021 at 15:05, Andrew Scull [off-list ref] wrote:
quoted
On Mon, Aug 09, 2021 at 07:01:57PM +0000, Dov Murik wrote:
[...]
quoted
quoted
quoted
quoted
+static int sev_secret_unlink(struct inode *dir, struct dentry *dentry)
+{
+ struct sev_secret *s = sev_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 */
+ memzero_explicit(e->data, secret_entry_data_len(e));
Would there be a benefit in flushing these zeros?
Do you mean cache clean+invalidate? Better to be precise here.
At least a clean, to have the zeros written back to memory from the
cache, in order to overwrite the secret.
I agree, but not sure how to implement this:
I see there's an arch_wb_cache_pmem exported function which internally
(in arch/x86/lib/usercopy_64.c) calls clean_cache_range which seems to
do what we want (assume the secret can be longer than the cache line).
But arch_wb_cache_pmem is declared in include/linux/libnvdimm.h and
guarded with #ifdef CONFIG_ARCH_HAS_PMEM_API -- both seem not related to
what I'm trying to do.
I see there's an exported clflush_cache_range for x86 -- but that's a
clean+flush if I understand correctly.
This would be perfectly correct, the invalidation is just unnecessary.
Suggestions on how to approach? I can copy the clean_cache_range
implementation into the sev_secret module but hopefully there's a better
way to reuse. Maybe export clean_cache_range in x86?
Exporting sounds much better than duplicating.
It looks like the clean-only instruction was added to x86 more
recently and with persistent memory as the intended application.
d9dc64f30 "x86/asm: Add support for the CLWB instruction" says:
"This should be used in favor of clflushopt or clflush in cases where
you require the cache line to be written to memory but plan to access
the data cache line to be written to memory but plan to access the
data"
I don't expect the secret table would be accessed with such frequency
that it would actually make a difference, but if it's just a quirk of
history that the clean-only version isn't exported, now seems as good
a time as any to change that!
Since this is for SEV the solution can be x86-specific, but if there's a
generic way I guess it's better (I think all of sev_secret module
doesn't have x86-specific stuff).
arch_wb_cache_pmem is the closest to arch agnostic I've seen, but that
has it own problems :/
On Mon, Aug 09, 2021 at 07:01:54PM +0000, Dov Murik wrote:
Confidential computing (coco) hardware such as AMD SEV (Secure Encrypted
Virtualization) allows guest owners to inject secrets into the VMs
memory without the host/hypervisor being able to read them. In SEV,
secret injection is performed early in the VM launch process, before the
guest starts running.
OVMF already reserves designated area for secret injection (in its
AmdSev package; see edk2 commit 01726b6d23d4 "OvmfPkg/AmdSev: Expose the
Sev Secret area using a configuration table" [1]), but the secrets were
not available in the guest kernel.
The patch series copies the secrets from the EFI-provided memory to
kernel reserved memory, and optionally exposes them to userspace via
securityfs using a new sev_secret kernel module.
The first patch in efi/libstub copies the secret area from the EFI
memory to specially allocated memory; the second patch reserves that
memory block; and the third patch introduces the new sev_secret module
that exposes the content of the secret entries as securityfs files, and
allows clearing out secrets with a file unlink interface.
As a usage example, consider a guest performing computations on
encrypted files. The Guest Owner provides the decryption key (= secret)
using the secret injection mechanism. The guest application reads the
secret from the sev_secret filesystem and proceeds to decrypt the files
into memory and then performs the needed computations on the content.
In this example, the host can't read the files from the disk image
because they are encrypted. Host can't read the decryption key because
it is passed using the secret injection mechanism (= secure channel).
Host can't read the decrypted content from memory because it's a
confidential (memory-encrypted) guest.
This has been tested with AMD SEV guests, but the kernel side of
handling the secret area has no SEV-specific dependencies, and therefore
might be usable (perhaps with minor changes) for any confidential
computing hardware that can publish the secret area via the standard EFI
config table entry.
Here is a simple example for usage of the sev_secret module in a guest
to which a secret are with 4 secrets was injected during launch:
# modprobe sev_secret
# ls -la /sys/kernel/security/coco/sev_secret
Wait, why are you using securityfs for this?
securityfs is for LSMs to use. If you want your own filesystem to play
around with stuff like this, great, write your own, it's only 200 lines
or less these days. We used to do it all the time until people realized
they should just use sysfs for driver stuff.
But this isn't a driver, so sure, add your own virtual filesystem, mount
it somewhere and away you go, no messing around with securityfs, right?
thanks,
greg k-h
On Mon, Aug 09, 2021 at 07:01:57PM +0000, Dov Murik wrote:
quoted hunk
The new sev_secret module exposes the confidential computing (coco)
secret area via securityfs interface.
When the module is loaded (and securityfs is mounted, typically under
/sys/kernel/security), a "coco/sev_secret" 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 "coco/sev_secret" 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 <redacted>
---
drivers/virt/Kconfig | 3 +
drivers/virt/Makefile | 1 +
drivers/virt/coco/sev_secret/Kconfig | 11 +
drivers/virt/coco/sev_secret/Makefile | 2 +
drivers/virt/coco/sev_secret/sev_secret.c | 313 ++++++++++++++++++++++
5 files changed, 330 insertions(+)
create mode 100644 drivers/virt/coco/sev_secret/Kconfig
create mode 100644 drivers/virt/coco/sev_secret/Makefile
create mode 100644 drivers/virt/coco/sev_secret/sev_secret.c
Why isn't all of this documented in Documentation/ABI/ which is needed
for any new user/kernel api that you come up with like this. We have to
have it documented somewhere, otherwise how will you know how to use
these files?
thanks
greg k-h
From: James Bottomley <hidden> Date: 2021-09-02 14:37:32
On Thu, 2021-09-02 at 14:57 +0200, Greg KH wrote:
[...]
Wait, why are you using securityfs for this?
securityfs is for LSMs to use.
No it isn't ... at least not exclusively; we use it for non LSM
security purposes as well, like for the TPM BIOS log and for IMA. What
makes you think we should start restricting securityfs to LSMs only?
That's not been the policy up to now.
If you want your own filesystem to play around with stuff like this,
great, write your own, it's only 200 lines or less these days. We
used to do it all the time until people realized they should just use
sysfs for driver stuff.
This is a security purpose (injected key retrieval), so securityfs
seems to be the best choice. It's certainly possible to create a new
filesystem, but I really think things with a security purpose should
use securityfs so people know where to look for them.
James
But this isn't a driver, so sure, add your own virtual filesystem,
mount it somewhere and away you go, no messing around with
securityfs, right?
thanks,
greg k-h
On Thu, Sep 02, 2021 at 07:35:10AM -0700, James Bottomley wrote:
On Thu, 2021-09-02 at 14:57 +0200, Greg KH wrote:
[...]
quoted
Wait, why are you using securityfs for this?
securityfs is for LSMs to use.
No it isn't ... at least not exclusively; we use it for non LSM
security purposes as well, like for the TPM BIOS log and for IMA. What
makes you think we should start restricting securityfs to LSMs only?
That's not been the policy up to now.
Well that was the original intent of the filesystem when it was created,
but I guess it's really up to the LSM maintainers now what they want it
for.
quoted
If you want your own filesystem to play around with stuff like this,
great, write your own, it's only 200 lines or less these days. We
used to do it all the time until people realized they should just use
sysfs for driver stuff.
This is a security purpose (injected key retrieval), so securityfs
seems to be the best choice. It's certainly possible to create a new
filesystem, but I really think things with a security purpose should
use securityfs so people know where to look for them.
knowing where to look should not be an issue, as that should be
documented in Documentation/ABI/ anyway, right?
It's just the overlap / overreach of using an existing filesystem for
things that don't seem to be LSM-related that feels odd to me.
Why not just make a cocofs if those people want a filesystem interface?
It's 200 lines or so these days, if not less, and that way you only
mount what you actually need for the system.
Why force this into securityfs if it doesn't have to be?
thanks,
greg k-h
From: James Bottomley <hidden> Date: 2021-09-02 15:20:22
On Thu, 2021-09-02 at 17:05 +0200, Greg KH wrote:
On Thu, Sep 02, 2021 at 07:35:10AM -0700, James Bottomley wrote:
quoted
On Thu, 2021-09-02 at 14:57 +0200, Greg KH wrote:
[...]
quoted
Wait, why are you using securityfs for this?
securityfs is for LSMs to use.
No it isn't ... at least not exclusively; we use it for non LSM
security purposes as well, like for the TPM BIOS log and for
IMA. What makes you think we should start restricting securityfs
to LSMs only? That's not been the policy up to now.
Well that was the original intent of the filesystem when it was
created, but I guess it's really up to the LSM maintainers now what
they want it for.
quoted
quoted
If you want your own filesystem to play around with stuff like
this, great, write your own, it's only 200 lines or less these
days. We used to do it all the time until people realized they
should just use sysfs for driver stuff.
This is a security purpose (injected key retrieval), so securityfs
seems to be the best choice. It's certainly possible to create a
new filesystem, but I really think things with a security purpose
should use securityfs so people know where to look for them.
knowing where to look should not be an issue, as that should be
documented in Documentation/ABI/ anyway, right?
It's just the overlap / overreach of using an existing filesystem for
things that don't seem to be LSM-related that feels odd to me.
Why not just make a cocofs if those people want a filesystem
interface?
It's 200 lines or so these days, if not less, and that way you only
mount what you actually need for the system.
Secrets transfer is actually broader than confidential computing,
although confidential computing is a first proposed use, so I think
cocofs would be too narrow.
Why force this into securityfs if it doesn't have to be?
It's not being forced. Secrets transfer is a security function in the
same way the bios log is.
James
From: James Bottomley <hidden> Date: 2021-09-02 16:25:57
On Thu, 2021-09-02 at 18:09 +0200, Greg KH wrote:
On Thu, Sep 02, 2021 at 08:19:51AM -0700, James Bottomley wrote:
quoted
On Thu, 2021-09-02 at 17:05 +0200, Greg KH wrote:
quoted
On Thu, Sep 02, 2021 at 07:35:10AM -0700, James Bottomley wrote:
quoted
On Thu, 2021-09-02 at 14:57 +0200, Greg KH wrote:
[...]
quoted
Wait, why are you using securityfs for this?
securityfs is for LSMs to use.
No it isn't ... at least not exclusively; we use it for non LSM
security purposes as well, like for the TPM BIOS log and for
IMA. What makes you think we should start restricting
securityfs to LSMs only? That's not been the policy up to now.
Well that was the original intent of the filesystem when it was
created, but I guess it's really up to the LSM maintainers now
what they want it for.
quoted
quoted
If you want your own filesystem to play around with stuff
like this, great, write your own, it's only 200 lines or less
these days. We used to do it all the time until people
realized they should just use sysfs for driver stuff.
This is a security purpose (injected key retrieval), so
securityfs seems to be the best choice. It's certainly
possible to create a new filesystem, but I really think things
with a security purpose should use securityfs so people know
where to look for them.
knowing where to look should not be an issue, as that should be
documented in Documentation/ABI/ anyway, right?
It's just the overlap / overreach of using an existing filesystem
for things that don't seem to be LSM-related that feels odd to
me.
Why not just make a cocofs if those people want a filesystem
interface?
It's 200 lines or so these days, if not less, and that way you
only mount what you actually need for the system.
Secrets transfer is actually broader than confidential computing,
although confidential computing is a first proposed use, so I think
cocofs would be too narrow.
quoted
Why force this into securityfs if it doesn't have to be?
It's not being forced. Secrets transfer is a security function in
the same way the bios log is.
Is the bios log in securityfs today?
Yes. It's under /sys/kernel/security/tpm0/ All the ima policy control
and its log is under /sys/kernel/security/ima/ that's why I think
declaring securityfs as being for anything security related is already
our de facto (if not de jure) policy.
Anyway, it's up to the securityfs maintainer (i.e. not me), but
personally, I think this should be a separate filesystem as that
would probably make things easier in the long run...
I know Al likes this business of loads of separate filesystems, but
personally I'm not in favour. For every one you do, you not only have
to document it all, you also have to find a preferred mount point that
the distributions can agree on and also have them agree to enable the
mount for, which often takes months of negotiation. Having fewer
filesystems grouped by common purpose which have agreed mount points
that distros actually mount seems a far easier approach to enablement.
James
On Thu, Sep 02, 2021 at 08:19:51AM -0700, James Bottomley wrote:
On Thu, 2021-09-02 at 17:05 +0200, Greg KH wrote:
quoted
On Thu, Sep 02, 2021 at 07:35:10AM -0700, James Bottomley wrote:
quoted
On Thu, 2021-09-02 at 14:57 +0200, Greg KH wrote:
[...]
quoted
Wait, why are you using securityfs for this?
securityfs is for LSMs to use.
No it isn't ... at least not exclusively; we use it for non LSM
security purposes as well, like for the TPM BIOS log and for
IMA. What makes you think we should start restricting securityfs
to LSMs only? That's not been the policy up to now.
Well that was the original intent of the filesystem when it was
created, but I guess it's really up to the LSM maintainers now what
they want it for.
quoted
quoted
If you want your own filesystem to play around with stuff like
this, great, write your own, it's only 200 lines or less these
days. We used to do it all the time until people realized they
should just use sysfs for driver stuff.
This is a security purpose (injected key retrieval), so securityfs
seems to be the best choice. It's certainly possible to create a
new filesystem, but I really think things with a security purpose
should use securityfs so people know where to look for them.
knowing where to look should not be an issue, as that should be
documented in Documentation/ABI/ anyway, right?
It's just the overlap / overreach of using an existing filesystem for
things that don't seem to be LSM-related that feels odd to me.
Why not just make a cocofs if those people want a filesystem
interface?
It's 200 lines or so these days, if not less, and that way you only
mount what you actually need for the system.
Secrets transfer is actually broader than confidential computing,
although confidential computing is a first proposed use, so I think
cocofs would be too narrow.
quoted
Why force this into securityfs if it doesn't have to be?
It's not being forced. Secrets transfer is a security function in the
same way the bios log is.
Is the bios log in securityfs today?
Anyway, it's up to the securityfs maintainer (i.e. not me), but
personally, I think this should be a separate filesystem as that would
probably make things easier in the long run...
good luck!
greg k-h
On Thu, Sep 02, 2021 at 09:19:13AM -0700, James Bottomley wrote:
On Thu, 2021-09-02 at 18:09 +0200, Greg KH wrote:
quoted
On Thu, Sep 02, 2021 at 08:19:51AM -0700, James Bottomley wrote:
quoted
On Thu, 2021-09-02 at 17:05 +0200, Greg KH wrote:
quoted
On Thu, Sep 02, 2021 at 07:35:10AM -0700, James Bottomley wrote:
quoted
On Thu, 2021-09-02 at 14:57 +0200, Greg KH wrote:
[...]
quoted
Wait, why are you using securityfs for this?
securityfs is for LSMs to use.
No it isn't ... at least not exclusively; we use it for non LSM
security purposes as well, like for the TPM BIOS log and for
IMA. What makes you think we should start restricting
securityfs to LSMs only? That's not been the policy up to now.
Well that was the original intent of the filesystem when it was
created, but I guess it's really up to the LSM maintainers now
what they want it for.
quoted
quoted
If you want your own filesystem to play around with stuff
like this, great, write your own, it's only 200 lines or less
these days. We used to do it all the time until people
realized they should just use sysfs for driver stuff.
This is a security purpose (injected key retrieval), so
securityfs seems to be the best choice. It's certainly
possible to create a new filesystem, but I really think things
with a security purpose should use securityfs so people know
where to look for them.
knowing where to look should not be an issue, as that should be
documented in Documentation/ABI/ anyway, right?
It's just the overlap / overreach of using an existing filesystem
for things that don't seem to be LSM-related that feels odd to
me.
Why not just make a cocofs if those people want a filesystem
interface?
It's 200 lines or so these days, if not less, and that way you
only mount what you actually need for the system.
Secrets transfer is actually broader than confidential computing,
although confidential computing is a first proposed use, so I think
cocofs would be too narrow.
quoted
Why force this into securityfs if it doesn't have to be?
It's not being forced. Secrets transfer is a security function in
the same way the bios log is.
Is the bios log in securityfs today?
Yes. It's under /sys/kernel/security/tpm0/ All the ima policy control
and its log is under /sys/kernel/security/ima/ that's why I think
declaring securityfs as being for anything security related is already
our de facto (if not de jure) policy.
quoted
Anyway, it's up to the securityfs maintainer (i.e. not me), but
personally, I think this should be a separate filesystem as that
would probably make things easier in the long run...
I know Al likes this business of loads of separate filesystems, but
personally I'm not in favour. For every one you do, you not only have
to document it all,
Wait, why would you not have to document your new files no matter what?
That should not be an issue either way.
you also have to find a preferred mount point that
the distributions can agree on and also have them agree to enable the
mount for,
You create that yourself, just like tracefs does, and set the standard
right away, not an issue.
which often takes months of negotiation.
Enabling it does take time, which is good because if they do not think
it should be present because they do not want to use it, then it will
not be, which means either they do not need your new feature, or you
have not made it useful enough.
So again, not an issue.
And you can even mount it yourself from the kernel if you insist on it
always being present.
Having fewer
filesystems grouped by common purpose which have agreed mount points
that distros actually mount seems a far easier approach to enablement.
The issue is that random things gets added to those filesystems,
exposing stuff that perhaps some systems do NOT want exposed to
userspace. Making it explicit as to what they have to mount to get
access to that is a good thing because you have less of an "attack
surface" and all of that.
So again, this should not be an issue. If coco stuff is so important
that people need it, then having them have to add it to their init
scripts just to mount the filesystem is not an issue as there are other
userspace components of all of this mess that they had to install
anyway. Just make it part of the userspace tools that are going to be
accessing these files because you have to get those onto the systems no
matter what.
greg k-h
On Mon, Aug 09, 2021 at 07:01:57PM +0000, Dov Murik wrote:
quoted
The new sev_secret module exposes the confidential computing (coco)
secret area via securityfs interface.
When the module is loaded (and securityfs is mounted, typically under
/sys/kernel/security), a "coco/sev_secret" 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 "coco/sev_secret" 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 <redacted>
---
drivers/virt/Kconfig | 3 +
drivers/virt/Makefile | 1 +
drivers/virt/coco/sev_secret/Kconfig | 11 +
drivers/virt/coco/sev_secret/Makefile | 2 +
drivers/virt/coco/sev_secret/sev_secret.c | 313 ++++++++++++++++++++++
5 files changed, 330 insertions(+)
create mode 100644 drivers/virt/coco/sev_secret/Kconfig
create mode 100644 drivers/virt/coco/sev_secret/Makefile
create mode 100644 drivers/virt/coco/sev_secret/sev_secret.c
Why isn't all of this documented in Documentation/ABI/ which is needed
for any new user/kernel api that you come up with like this. We have to
have it documented somewhere, otherwise how will you know how to use
these files?
Yes, you're right, I'll add such documentation.
Note that the ABI (for userspace programs) is the filesystem paths and
usage (read + unlink), and not the GUIDed table explained above your
comment. That GUIDed table is passed from the Guest Owner via SEV
secret injection into OVMF and from there to the kernel memory (patches
1+2 in this series). So userspace doesn't see this GUIDed table
structure at all.
I should probably add this story to this file's header comment, or some
other place which will document this module (suggestions welcome).
-Dov