use confidential computing provisioned secrets for disk decryption
The code of this functionality is cherry-picked from https://mail.gnu.org/archive/html/grub-devel/2022-02/msg00064.html. Signed-off-by: hanliyang <hanliyang@hygon.cn>
This commit is contained in:
parent
c1abe607ea
commit
7413ba71dd
176
0001-cryptodisk-add-OS-provided-secret-support.patch
Normal file
176
0001-cryptodisk-add-OS-provided-secret-support.patch
Normal file
@ -0,0 +1,176 @@
|
||||
From 90d00b832a2fcab9424fff1859bb2b9b4be01a2a Mon Sep 17 00:00:00 2001
|
||||
From: James Bottomley <jejb@linux.ibm.com>
|
||||
Date: Mon, 11 Nov 2024 14:20:23 +0800
|
||||
Subject: [PATCH 1/2] cryptodisk: add OS provided secret support
|
||||
|
||||
cherry-picked from https://mail.gnu.org/archive/html/grub-devel/2022-02/msg00065.html.
|
||||
|
||||
Make use of the new OS provided secrets API so that if the new '-s'
|
||||
option is passed in we try to extract the secret from the API rather
|
||||
than prompting for it.
|
||||
|
||||
The primary consumer of this is AMD SEV, which has been programmed to
|
||||
provide an injectable secret to the encrypted virtual machine. OVMF
|
||||
provides the secret area and passes it into the EFI Configuration
|
||||
Tables. The grub EFI layer pulls the secret out and primes the
|
||||
secrets API with it. The upshot of all of this is that a SEV
|
||||
protected VM can do an encrypted boot with a protected boot secret.
|
||||
|
||||
[ hly: The patch from James Bottomley can not work properly, fix it
|
||||
when backport the patch. ]
|
||||
|
||||
Signed-off-by: James Bottomley <jejb@linux.ibm.com>
|
||||
Signed-off-by: hanliyang <hanliyang@hygon.cn>
|
||||
---
|
||||
grub-core/disk/cryptodisk.c | 62 +++++++++++++++++++++++++++++++++++--
|
||||
include/grub/cryptodisk.h | 14 +++++++++
|
||||
2 files changed, 73 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
|
||||
index 8bc559b..4d8deba 100644
|
||||
--- a/grub-core/disk/cryptodisk.c
|
||||
+++ b/grub-core/disk/cryptodisk.c
|
||||
@@ -48,7 +48,8 @@ enum
|
||||
OPTION_KEYFILE_OFFSET,
|
||||
OPTION_KEYFILE_SIZE,
|
||||
OPTION_HEADER,
|
||||
- OPTION_PROTECTOR
|
||||
+ OPTION_PROTECTOR,
|
||||
+ OPTION_SECRET
|
||||
};
|
||||
|
||||
static const struct grub_arg_option options[] =
|
||||
@@ -64,6 +65,7 @@ static const struct grub_arg_option options[] =
|
||||
{"header", 'H', 0, N_("Read header from file"), 0, ARG_TYPE_STRING},
|
||||
{"protector", 'P', GRUB_ARG_OPTION_REPEATABLE,
|
||||
N_("Unlock volume(s) using key protector(s)."), 0, ARG_TYPE_STRING},
|
||||
+ {"secret", 's', 0, N_("Get secret passphrase from named module and optional identifier"), 0, 0},
|
||||
{0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
@@ -1026,6 +1028,9 @@ grub_util_cryptodisk_get_uuid (grub_disk_t disk)
|
||||
|
||||
#endif
|
||||
|
||||
+/* variable to hold the list of secret providers */
|
||||
+static struct grub_secret_entry *secret_providers;
|
||||
+
|
||||
static void
|
||||
cryptodisk_close (grub_cryptodisk_t dev)
|
||||
{
|
||||
@@ -1260,6 +1265,18 @@ grub_cryptodisk_scan_device_real (const char *name,
|
||||
return dev;
|
||||
}
|
||||
|
||||
+void
|
||||
+grub_cryptodisk_add_secret_provider (struct grub_secret_entry *e)
|
||||
+{
|
||||
+ grub_list_push(GRUB_AS_LIST_P (&secret_providers), GRUB_AS_LIST (e));
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+grub_cryptodisk_remove_secret_provider (struct grub_secret_entry *e)
|
||||
+{
|
||||
+ grub_list_remove (GRUB_AS_LIST (e));
|
||||
+}
|
||||
+
|
||||
#ifdef GRUB_UTIL
|
||||
#include <grub/util/misc.h>
|
||||
grub_err_t
|
||||
@@ -1376,7 +1393,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
struct grub_arg_list *state = ctxt->state;
|
||||
struct grub_cryptomount_args cargs = {0};
|
||||
|
||||
- if (argc < 1 && !state[OPTION_ALL].set && !state[OPTION_BOOT].set)
|
||||
+ if (argc < 1 && !state[OPTION_ALL].set && !state[OPTION_BOOT].set && !state[OPTION_SECRET].set)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
|
||||
|
||||
if (grub_cryptodisk_list == NULL)
|
||||
@@ -1386,6 +1403,11 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
"a password and a key protector cannot both be set");
|
||||
|
||||
+ if (state[OPTION_SECRET].set &&
|
||||
+ (state[OPTION_PASSWORD].set || state[OPTION_PROTECTOR].set)) /* secret module and password/key protector */
|
||||
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
+ "a secret module and a password/key protector cannot both be set");
|
||||
+
|
||||
if (state[OPTION_PASSWORD].set) /* password */
|
||||
{
|
||||
cargs.key_data = (grub_uint8_t *) state[OPTION_PASSWORD].arg;
|
||||
@@ -1527,6 +1549,40 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
grub_cryptodisk_clear_key_cache (&cargs);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
+ else if (state[OPTION_SECRET].set) /* secret module */
|
||||
+ {
|
||||
+ struct grub_secret_entry *se = NULL;
|
||||
+ grub_err_t rc;
|
||||
+
|
||||
+ if (argc < 1)
|
||||
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "secret module must be specified");
|
||||
+#ifndef GRUB_UTIL
|
||||
+ grub_dl_load (args[0]);
|
||||
+#endif
|
||||
+ se = grub_named_list_find (GRUB_AS_NAMED_LIST (secret_providers), args[0]);
|
||||
+ if (se == NULL)
|
||||
+ return grub_error (GRUB_ERR_INVALID_COMMAND, "No secret provider is found");
|
||||
+
|
||||
+ rc = se->get (args[1], &cargs.key_data);
|
||||
+ if (rc)
|
||||
+ return rc;
|
||||
+
|
||||
+ cargs.key_len = grub_strlen((char *) cargs.key_data);
|
||||
+
|
||||
+ cargs.check_boot = state[OPTION_BOOT].set;
|
||||
+ cargs.search_uuid = NULL;
|
||||
+
|
||||
+ grub_device_iterate (&grub_cryptodisk_scan_device, &cargs);
|
||||
+
|
||||
+ if (state[OPTION_SECRET].set)
|
||||
+ {
|
||||
+ rc = se->put (args[1], 1, &cargs.key_data);
|
||||
+ }
|
||||
+
|
||||
+ grub_cryptodisk_clear_key_cache (&cargs);
|
||||
+
|
||||
+ return rc;
|
||||
+ }
|
||||
else
|
||||
{
|
||||
grub_disk_t disk;
|
||||
@@ -1721,7 +1777,7 @@ GRUB_MOD_INIT (cryptodisk)
|
||||
N_("[ [-p password] | [-k keyfile"
|
||||
" [-O keyoffset] [-S keysize] ] ] [-H file]"
|
||||
" [-P protector [-P protector ...]]"
|
||||
- " <SOURCE|-u UUID|-a|-b>"),
|
||||
+ " <SOURCE|-u UUID|-a|-b|-s MOD [ID]>"),
|
||||
N_("Mount a crypto device."), options);
|
||||
grub_procfs_register ("luks_script", &luks_script);
|
||||
}
|
||||
diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h
|
||||
index 0b41e24..d0804a7 100644
|
||||
--- a/include/grub/cryptodisk.h
|
||||
+++ b/include/grub/cryptodisk.h
|
||||
@@ -203,4 +203,18 @@ grub_util_get_geli_uuid (const char *dev);
|
||||
grub_cryptodisk_t grub_cryptodisk_get_by_uuid (const char *uuid);
|
||||
grub_cryptodisk_t grub_cryptodisk_get_by_source_disk (grub_disk_t disk);
|
||||
|
||||
+struct grub_secret_entry {
|
||||
+ /* as named list */
|
||||
+ struct grub_secret_entry *next;
|
||||
+ struct grub_secret_entry **prev;
|
||||
+ const char *name;
|
||||
+
|
||||
+ /* additional entries */
|
||||
+ grub_err_t (*get) (const char *arg, grub_uint8_t **secret);
|
||||
+ grub_err_t (*put) (const char *arg, int have_it, grub_uint8_t **secret);
|
||||
+};
|
||||
+
|
||||
+void grub_cryptodisk_add_secret_provider (struct grub_secret_entry *e);
|
||||
+void grub_cryptodisk_remove_secret_provider (struct grub_secret_entry *e);
|
||||
+
|
||||
#endif
|
||||
--
|
||||
2.25.1
|
||||
|
||||
218
0002-efi-Add-API-for-retrieving-the-EFI-secret-for-crypto.patch
Normal file
218
0002-efi-Add-API-for-retrieving-the-EFI-secret-for-crypto.patch
Normal file
@ -0,0 +1,218 @@
|
||||
From 2078f52e5481cc7900aa7dcdd22498604700767f Mon Sep 17 00:00:00 2001
|
||||
From: James Bottomley <jejb@linux.ibm.com>
|
||||
Date: Mon, 11 Nov 2024 20:45:47 +0800
|
||||
Subject: [PATCH 2/2] efi: Add API for retrieving the EFI secret for cryptodisk
|
||||
|
||||
cherry-picked from https://mail.gnu.org/archive/html/grub-devel/2022-02/msg00066.html.
|
||||
|
||||
This module is designed to provide an efisecret provider which
|
||||
interrogates the EFI configuration table to find the location of the
|
||||
confidential computing secret and tries to register the secret with
|
||||
the cryptodisk.
|
||||
|
||||
The secret is stored in a boot allocated area, usually a page in size.
|
||||
The layout of the secret injection area is a header
|
||||
|
||||
|GRUB_EFI_SECRET_TABLE_HEADER_GUID|len|
|
||||
|
||||
with entries of the form
|
||||
|
||||
|guid|len|data|
|
||||
|
||||
the guid corresponding to the disk encryption passphrase is
|
||||
GRUB_EFI_DISKPASSWD_GUID and data must be a zero terminated string.
|
||||
To get a high entropy string that doesn't need large numbers of
|
||||
iterations, use a base64 encoding of 33 bytes of random data.
|
||||
|
||||
Signed-off-by: James Bottomley <jejb@linux.ibm.com>
|
||||
Signed-off-by: hanliyang <hanliyang@hygon.cn>
|
||||
---
|
||||
grub-core/Makefile.core.def | 8 ++
|
||||
grub-core/disk/efi/efisecret.c | 129 +++++++++++++++++++++++++++++++++
|
||||
include/grub/efi/api.h | 15 ++++
|
||||
3 files changed, 152 insertions(+)
|
||||
create mode 100644 grub-core/disk/efi/efisecret.c
|
||||
|
||||
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
|
||||
index 730aea0..1329b81 100644
|
||||
--- a/grub-core/Makefile.core.def
|
||||
+++ b/grub-core/Makefile.core.def
|
||||
@@ -815,6 +815,14 @@ module = {
|
||||
enable = efi;
|
||||
};
|
||||
|
||||
+module = {
|
||||
+ name = efisecret;
|
||||
+
|
||||
+ common = disk/efi/efisecret.c;
|
||||
+
|
||||
+ enable = efi;
|
||||
+};
|
||||
+
|
||||
module = {
|
||||
name = lsefimmap;
|
||||
|
||||
diff --git a/grub-core/disk/efi/efisecret.c b/grub-core/disk/efi/efisecret.c
|
||||
new file mode 100644
|
||||
index 0000000..1b5bf81
|
||||
--- /dev/null
|
||||
+++ b/grub-core/disk/efi/efisecret.c
|
||||
@@ -0,0 +1,129 @@
|
||||
+#include <grub/err.h>
|
||||
+#include <grub/misc.h>
|
||||
+#include <grub/cryptodisk.h>
|
||||
+#include <grub/efi/efi.h>
|
||||
+#include <grub/efi/api.h>
|
||||
+#include <grub/dl.h>
|
||||
+
|
||||
+GRUB_MOD_LICENSE ("GPLv3+");
|
||||
+
|
||||
+static grub_packed_guid_t secret_guid = GRUB_EFI_SECRET_TABLE_GUID;
|
||||
+static grub_packed_guid_t tableheader_guid = GRUB_EFI_SECRET_TABLE_HEADER_GUID;
|
||||
+static grub_packed_guid_t diskpasswd_guid = GRUB_EFI_DISKPASSWD_GUID;
|
||||
+
|
||||
+struct efi_secret {
|
||||
+ grub_uint64_t base;
|
||||
+ grub_uint64_t size;
|
||||
+};
|
||||
+
|
||||
+struct secret_header {
|
||||
+ grub_packed_guid_t guid;
|
||||
+ grub_uint32_t len;
|
||||
+};
|
||||
+
|
||||
+struct secret_entry {
|
||||
+ grub_packed_guid_t guid;
|
||||
+ grub_uint32_t len;
|
||||
+ grub_uint8_t data[0];
|
||||
+};
|
||||
+
|
||||
+static grub_err_t
|
||||
+grub_efi_secret_put (const char *arg __attribute__((unused)), int have_it,
|
||||
+ grub_uint8_t **ptr)
|
||||
+{
|
||||
+ struct secret_entry *e = (struct secret_entry *)(*ptr - (long)&((struct secret_entry *)0)->data);
|
||||
+ int len = e->len;
|
||||
+
|
||||
+ /* destroy the secret */
|
||||
+ grub_memset (e, 0, len);
|
||||
+ /* put back the length to make sure the table is still traversable */
|
||||
+ e->len = len;
|
||||
+
|
||||
+ *ptr = NULL;
|
||||
+
|
||||
+ if (have_it)
|
||||
+ return GRUB_ERR_NONE;
|
||||
+
|
||||
+ return grub_error (GRUB_ERR_ACCESS_DENIED, "EFI secret failed to unlock any volumes");
|
||||
+}
|
||||
+
|
||||
+static grub_err_t
|
||||
+grub_efi_secret_find (struct efi_secret *s, grub_uint8_t **secret_ptr)
|
||||
+{
|
||||
+ int len;
|
||||
+ struct secret_header *h;
|
||||
+ struct secret_entry *e;
|
||||
+ unsigned char *ptr = (unsigned char *)(unsigned long)s->base;
|
||||
+
|
||||
+ /* the area must be big enough for a guid and a u32 length */
|
||||
+ if (s->size < sizeof (*h))
|
||||
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "EFI secret area is too small");
|
||||
+
|
||||
+ h = (struct secret_header *)ptr;
|
||||
+ if (grub_memcmp(&h->guid, &tableheader_guid, sizeof (h->guid)))
|
||||
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "EFI secret area does not start with correct guid\n");
|
||||
+ if (h->len < sizeof (*h))
|
||||
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "EFI secret area is too small\n");
|
||||
+
|
||||
+ len = h->len - sizeof (*h);
|
||||
+ ptr += sizeof (*h);
|
||||
+
|
||||
+ while (len >= (int)sizeof (*e)) {
|
||||
+ e = (struct secret_entry *)ptr;
|
||||
+ if (e->len < sizeof(*e) || e->len > (unsigned int)len)
|
||||
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "EFI secret area is corrupt\n");
|
||||
+
|
||||
+ if (! grub_memcmp (&e->guid, &diskpasswd_guid, sizeof (e->guid))) {
|
||||
+ int end = e->len - sizeof(*e);
|
||||
+
|
||||
+ /*
|
||||
+ * the passphrase must be a zero terminated string because the
|
||||
+ * password routines call grub_strlen () to find its size
|
||||
+ */
|
||||
+ if (end < 2 || e->data[end - 1] != '\0')
|
||||
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "EFI secret area disk encryption password is corrupt\n");
|
||||
+
|
||||
+ *secret_ptr = e->data;
|
||||
+ return GRUB_ERR_NONE;
|
||||
+ }
|
||||
+ ptr += e->len;
|
||||
+ len -= e->len;
|
||||
+ }
|
||||
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "EFI secret area does not contain disk decryption password\n");
|
||||
+}
|
||||
+
|
||||
+static grub_err_t
|
||||
+grub_efi_secret_get (const char *arg __attribute__((unused)), grub_uint8_t **ptr)
|
||||
+{
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ for (i = 0; i < grub_efi_system_table->num_table_entries; i++)
|
||||
+ {
|
||||
+ grub_packed_guid_t *guid =
|
||||
+ &grub_efi_system_table->configuration_table[i].vendor_guid;
|
||||
+
|
||||
+ if (! grub_memcmp (guid, &secret_guid, sizeof (grub_packed_guid_t))) {
|
||||
+ struct efi_secret *s =
|
||||
+ grub_efi_system_table->configuration_table[i].vendor_table;
|
||||
+
|
||||
+ return grub_efi_secret_find(s, ptr);
|
||||
+ }
|
||||
+ }
|
||||
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "No secret found in the EFI configuration table");
|
||||
+}
|
||||
+
|
||||
+static struct grub_secret_entry secret = {
|
||||
+ .name = "efisecret",
|
||||
+ .get = grub_efi_secret_get,
|
||||
+ .put = grub_efi_secret_put,
|
||||
+};
|
||||
+
|
||||
+GRUB_MOD_INIT(efisecret)
|
||||
+{
|
||||
+ grub_cryptodisk_add_secret_provider (&secret);
|
||||
+}
|
||||
+
|
||||
+GRUB_MOD_FINI(efisecret)
|
||||
+{
|
||||
+ grub_cryptodisk_remove_secret_provider (&secret);
|
||||
+}
|
||||
diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
|
||||
index 7947cf5..ccd01c0 100644
|
||||
--- a/include/grub/efi/api.h
|
||||
+++ b/include/grub/efi/api.h
|
||||
@@ -314,6 +314,21 @@
|
||||
{ 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
|
||||
}
|
||||
|
||||
+#define GRUB_EFI_SECRET_TABLE_GUID \
|
||||
+ { 0xadf956ad, 0xe98c, 0x484c, \
|
||||
+ { 0xae, 0x11, 0xb5, 0x1c, 0x7d, 0x33, 0x64, 0x47} \
|
||||
+ }
|
||||
+
|
||||
+#define GRUB_EFI_SECRET_TABLE_HEADER_GUID \
|
||||
+ { 0x1e74f542, 0x71dd, 0x4d66, \
|
||||
+ { 0x96, 0x3e, 0xef, 0x42, 0x87, 0xff, 0x17, 0x3b } \
|
||||
+ }
|
||||
+
|
||||
+#define GRUB_EFI_DISKPASSWD_GUID \
|
||||
+ { 0x736869e5, 0x84f0, 0x4973, \
|
||||
+ { 0x92, 0xec, 0x06, 0x87, 0x9c, 0xe3, 0xda, 0x0b } \
|
||||
+ }
|
||||
+
|
||||
#define GRUB_EFI_ACPI_TABLE_GUID \
|
||||
{ 0xeb9d2d30, 0x2d88, 0x11d3, \
|
||||
{ 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@ -455,7 +455,7 @@ GRUB_MODULES=" all_video boot blscfg btrfs \\\
|
||||
video xfs " \
|
||||
GRUB_MODULES+=%{efi_modules} \
|
||||
%if "%{1}" == "x86_64-efi" \
|
||||
GRUB_MODULES+=" tpcm_hygon " \
|
||||
GRUB_MODULES+=" tpcm_hygon efisecret " \
|
||||
%endif \
|
||||
%{expand:%%{mkimage %{1} %{2} %{3} %{4}}} \
|
||||
%{nil}
|
||||
|
||||
@ -241,3 +241,5 @@ Patch240: 0061-Add-BLS-support-to-grub-mkconfig.patch
|
||||
Patch241: 0064-Add-grub2-switch-to-blscfg.patch
|
||||
Patch242: 0001-newfeature-tpcm-add-hygon-tpcm-support.patch
|
||||
Patch243: 10_linux-fix-missing-ro-in-kernel-boot-parameters.patch
|
||||
Patch244: 0001-cryptodisk-add-OS-provided-secret-support.patch
|
||||
Patch245: 0002-efi-Add-API-for-retrieving-the-EFI-secret-for-crypto.patch
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
Name: grub2
|
||||
Epoch: 1
|
||||
Version: 2.12
|
||||
Release: 25
|
||||
Release: 26
|
||||
Summary: Bootloader with support for Linux, Multiboot and more
|
||||
License: GPLv3+
|
||||
URL: http://www.gnu.org/software/grub/
|
||||
@ -461,6 +461,12 @@ fi
|
||||
%{_datadir}/man/man*
|
||||
|
||||
%changelog
|
||||
* Wed Nov 13 2024 hanliyang <hanliyang@hygon.cn> - 1:2.12-26
|
||||
- Type:requirement
|
||||
- CVE:NA
|
||||
- SUG:NA
|
||||
- DESC:use confidential computing provisioned secrets for disk decryption
|
||||
|
||||
* Thu Oct 10 2024 zhangqiumiao <zhangqiumiao1@huawei.com> - 1:2.12-25
|
||||
- Type:bugfix
|
||||
- CVE:NA
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user