diff --git a/debian/changelog b/debian/changelog index 461cb3e..37121a3 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +grub2 (2.12-1deepin14) unstable; urgency=medium + + * Support use confidential computing provisioned secrets for disk decryption + + -- hanliyang Fri, 15 Nov 2024 10:30:11 +0800 + grub2 (2.12-1deepin13) unstable; urgency=medium * Support hygon tpcm diff --git a/debian/patches/deepin/0004-cryptodisk-add-OS-provided-secret-support.patch b/debian/patches/deepin/0004-cryptodisk-add-OS-provided-secret-support.patch new file mode 100644 index 0000000..c4f27df --- /dev/null +++ b/debian/patches/deepin/0004-cryptodisk-add-OS-provided-secret-support.patch @@ -0,0 +1,162 @@ +From 16b09bbdd2f2fa271daaf10fc4f3d1861f52ccf0 Mon Sep 17 00:00:00 2001 +From: James Bottomley +Date: Mon, 11 Nov 2024 14:20:23 +0800 +Subject: [PATCH 4/5] 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 +Signed-off-by: hanliyang +--- + grub-core/disk/cryptodisk.c | 55 +++++++++++++++++++++++++++++++++++-- + include/grub/cryptodisk.h | 14 ++++++++++ + 2 files changed, 66 insertions(+), 3 deletions(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 2246af5..86af122 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -44,7 +44,8 @@ enum + OPTION_KEYFILE, + OPTION_KEYFILE_OFFSET, + OPTION_KEYFILE_SIZE, +- OPTION_HEADER ++ OPTION_HEADER, ++ OPTION_SECRET + }; + + static const struct grub_arg_option options[] = +@@ -58,6 +59,7 @@ static const struct grub_arg_option options[] = + {"keyfile-offset", 'O', 0, N_("Key file offset (bytes)"), 0, ARG_TYPE_INT}, + {"keyfile-size", 'S', 0, N_("Key file data size (bytes)"), 0, ARG_TYPE_INT}, + {"header", 'H', 0, N_("Read header from file"), 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} + }; + +@@ -1020,6 +1022,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) + { +@@ -1167,6 +1172,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_err_t +@@ -1265,7 +1282,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) +@@ -1400,6 +1417,38 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + grub_device_iterate (&grub_cryptodisk_scan_device, &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); ++ } ++ ++ return rc; ++ } + else + { + grub_disk_t disk; +@@ -1590,7 +1639,7 @@ GRUB_MOD_INIT (cryptodisk) + cmd = grub_register_extcmd ("cryptomount", grub_cmd_cryptomount, 0, + N_("[ [-p password] | [-k keyfile" + " [-O keyoffset] [-S keysize] ] ] [-H file]" +- " "), ++ " "), + 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 d94df68..1b609bf 100644 +--- a/include/grub/cryptodisk.h ++++ b/include/grub/cryptodisk.h +@@ -187,4 +187,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 + diff --git a/debian/patches/deepin/0005-efi-Add-API-for-retrieving-the-EFI-secret-for-crypto.patch b/debian/patches/deepin/0005-efi-Add-API-for-retrieving-the-EFI-secret-for-crypto.patch new file mode 100644 index 0000000..c5898a1 --- /dev/null +++ b/debian/patches/deepin/0005-efi-Add-API-for-retrieving-the-EFI-secret-for-crypto.patch @@ -0,0 +1,220 @@ +From aaf8760725bddaf5c31b8561b0440043bb5a4c3c Mon Sep 17 00:00:00 2001 +From: James Bottomley +Date: Mon, 11 Nov 2024 20:45:47 +0800 +Subject: [PATCH 5/5] 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 +Signed-off-by: hanliyang +--- + grub-core/Makefile.core.def | 8 ++ + grub-core/disk/efi/efisecret.c | 131 +++++++++++++++++++++++++++++++++ + include/grub/efi/api.h | 15 ++++ + 3 files changed, 154 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 5ee8199..83fb179 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..ca0bfa8 +--- /dev/null ++++ b/grub-core/disk/efi/efisecret.c +@@ -0,0 +1,131 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++#pragma GCC diagnostic ignored "-Wcast-align" ++ ++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 a89bf3d..b718ecd 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -393,6 +393,21 @@ + {0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f } \ + } + ++#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 } \ ++ } ++ + struct grub_efi_sal_system_table + { + grub_uint32_t signature; +-- +2.25.1 + diff --git a/debian/patches/series b/debian/patches/series index 79480b4..83e6364 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -111,3 +111,6 @@ uniontech0035-block-terminal-output.patch deepin/0002-hygon-newfeature-tpcm-add-tpcm-support.patch deepin/0003-hygon-newfeature-tpcm-embed-tpcm-module-into-kernel.img-by.patch + +deepin/0004-cryptodisk-add-OS-provided-secret-support.patch +deepin/0005-efi-Add-API-for-retrieving-the-EFI-secret-for-crypto.patch