From 8c3cd1e56a65487e92f9ea788284e153b648749e371c621b89c40bdde4fc5105 Mon Sep 17 00:00:00 2001 From: Michael Chang Date: Mon, 27 Nov 2023 00:14:50 +0000 Subject: [PATCH] Accepting request 1128487 from home:michael-chang:branches:Base:System - Fix unattended boot with TPM2 allows downgrading kernel and rootfs, also enhancing the overall security posture (bsc#1216680) * 0001-Improve-TPM-key-protection-on-boot-interruptions.patch * 0002-Restrict-file-access-on-cryptodisk-print.patch * 0003-Restrict-ls-and-auto-file-completion-on-cryptodisk-p.patch * 0004-Key-revocation-on-out-of-bound-file-access.patch OBS-URL: https://build.opensuse.org/request/show/1128487 OBS-URL: https://build.opensuse.org/package/show/Base:System/grub2?expand=0&rev=477 --- ...key-protection-on-boot-interruptions.patch | 286 ++++++++++++++++++ ...rict-file-access-on-cryptodisk-print.patch | 197 ++++++++++++ ...auto-file-completion-on-cryptodisk-p.patch | 117 +++++++ ...vocation-on-out-of-bound-file-access.patch | 91 ++++++ grub2.changes | 10 + grub2.spec | 4 + 6 files changed, 705 insertions(+) create mode 100644 0001-Improve-TPM-key-protection-on-boot-interruptions.patch create mode 100644 0002-Restrict-file-access-on-cryptodisk-print.patch create mode 100644 0003-Restrict-ls-and-auto-file-completion-on-cryptodisk-p.patch create mode 100644 0004-Key-revocation-on-out-of-bound-file-access.patch diff --git a/0001-Improve-TPM-key-protection-on-boot-interruptions.patch b/0001-Improve-TPM-key-protection-on-boot-interruptions.patch new file mode 100644 index 0000000..3669f4e --- /dev/null +++ b/0001-Improve-TPM-key-protection-on-boot-interruptions.patch @@ -0,0 +1,286 @@ +From fe7ed9104cef56f9e532a0c9a7164393d5d69ae1 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Fri, 17 Nov 2023 12:32:59 +0800 +Subject: [PATCH 1/4] Improve TPM key protection on boot interruptions + +The unattended boot process for full disk encryption relies on an +authorized TPM policy to ensure the system's integrity before releasing +the key to grub. Subsequently, grub assumes responsibility for securing +the boot process, directing it towards a trusted default without any +expected interruptions. Any interruption during this process indicates +potential modification attempts, and releasing the obtained key to the +next stage should not occur in such cases. + +This commit addresses a vulnerability associated with interrupted boot +processes that could potentially enable malicious modifications to the +default or trusted boot target. To reinforce system security, the code +has been updated to incorporate measures that discard the TPM protected +key in the event of boot interruptions. + +Furthermore, this patch aims to enhance code readability by renaming +structures and function names related to cryptographic keys, improving +clarity and maintainability. + +By implementing these changes, this enhancement seeks to fortify the +protection of TPM keys, thereby ensuring a more robust defense against +potential unauthorized modifications during the boot process. + +Signed-Off-by Michael Chang +--- + grub-core/commands/crypttab.c | 38 ++++++++++++++++++++++++++--------- + grub-core/disk/cryptodisk.c | 8 +++++++- + grub-core/loader/linux.c | 6 +++--- + grub-core/normal/main.c | 2 +- + grub-core/normal/menu.c | 7 +++++++ + grub-core/normal/menu_entry.c | 2 +- + include/grub/crypttab.h | 18 ++++++++++------- + 7 files changed, 59 insertions(+), 22 deletions(-) + +diff --git a/grub-core/commands/crypttab.c b/grub-core/commands/crypttab.c +index c2217ca98..9397bede9 100644 +--- a/grub-core/commands/crypttab.c ++++ b/grub-core/commands/crypttab.c +@@ -9,17 +9,20 @@ + + GRUB_MOD_LICENSE ("GPLv3+"); + +-struct grub_key_publisher *kpuber; ++grub_crypto_key_list_t *cryptokey_lst; + + grub_err_t +-grub_initrd_publish_key (const char *uuid, const char *key, grub_size_t key_len, const char *path) ++grub_cryptokey_add_or_update (const char *uuid, const char *key, grub_size_t key_len, const char *path, int is_tpmkey) + { +- struct grub_key_publisher *cur = NULL; ++ grub_crypto_key_list_t *cur = NULL; + +- FOR_LIST_ELEMENTS (cur, kpuber) ++ FOR_LIST_ELEMENTS (cur, cryptokey_lst) + if (grub_uuidcasecmp (cur->name, uuid, sizeof (cur->name)) == 0) + break; + ++ if (!cur && !uuid) ++ return GRUB_ERR_NONE; ++ + if (!cur) + cur = grub_zalloc (sizeof (*cur)); + if (!cur) +@@ -44,21 +47,24 @@ grub_initrd_publish_key (const char *uuid, const char *key, grub_size_t key_len, + cur->path = grub_strdup (path); + } + ++ if (is_tpmkey >= 0) ++ cur->is_tpmkey = is_tpmkey; ++ + if (!cur->name) + { + cur->name = grub_strdup (uuid); +- grub_list_push (GRUB_AS_LIST_P (&kpuber), GRUB_AS_LIST (cur)); ++ grub_list_push (GRUB_AS_LIST_P (&cryptokey_lst), GRUB_AS_LIST (cur)); + } + + return GRUB_ERR_NONE; + } + + void +-grub_initrd_discard_key (void) ++grub_cryptokey_discard (void) + { +- struct grub_key_publisher *cur, *nxt; ++ grub_crypto_key_list_t *cur, *nxt; + +- FOR_LIST_ELEMENTS_SAFE (cur, nxt, kpuber) ++ FOR_LIST_ELEMENTS_SAFE (cur, nxt, cryptokey_lst) + { + grub_list_remove (GRUB_AS_LIST (cur)); + grub_memset (cur->key, 0, cur->key_len); +@@ -69,6 +75,20 @@ grub_initrd_discard_key (void) + } + } + ++void ++grub_cryptokey_tpmkey_discard (void) ++{ ++ grub_crypto_key_list_t *cur = NULL; ++ ++ FOR_LIST_ELEMENTS (cur, cryptokey_lst) ++ if (cur->is_tpmkey) ++ break; ++ ++ /* Discard all keys if any of them is tpm */ ++ if (cur) ++ grub_cryptokey_discard(); ++} ++ + static grub_err_t + grub_cmd_crypttab_entry (grub_command_t cmd __attribute__ ((unused)), + int argc, char **argv) +@@ -92,7 +112,7 @@ grub_cmd_crypttab_entry (grub_command_t cmd __attribute__ ((unused)), + } + + /*FIXME: Validate UUID string*/ +- return grub_initrd_publish_key (argv[1], NULL, 0, path); ++ return grub_cryptokey_add_or_update (argv[1], NULL, 0, path, -1); + } + + static grub_command_t cmd; +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index c79d4125a..d90ca06dc 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -1071,6 +1071,9 @@ grub_cryptodisk_scan_device_real (const char *name, + struct cryptodisk_read_hook_ctx read_hook_data = {0}; + int askpass = 0; + char *part = NULL; ++#ifndef GRUB_UTIL ++ int is_tpmkey = 0; ++#endif + + dev = grub_cryptodisk_get_by_source_disk (source); + +@@ -1183,6 +1186,9 @@ grub_cryptodisk_scan_device_real (const char *name, + ret = grub_cryptodisk_insert (dev, name, source); + if (ret != GRUB_ERR_NONE) + goto error; ++#ifndef GRUB_UTIL ++ is_tpmkey = 1; ++#endif + goto cleanup; + } + } +@@ -1244,7 +1250,7 @@ grub_cryptodisk_scan_device_real (const char *name, + + #ifndef GRUB_UTIL + if (cargs->key_data && dev) +- grub_initrd_publish_key (dev->uuid, (const char *)cargs->key_data, cargs->key_len, NULL); ++ grub_cryptokey_add_or_update (dev->uuid, (const char *)cargs->key_data, cargs->key_len, NULL, is_tpmkey); + #endif + if (askpass) + { +diff --git a/grub-core/loader/linux.c b/grub-core/loader/linux.c +index 9ee8f3790..e5e792958 100644 +--- a/grub-core/loader/linux.c ++++ b/grub-core/loader/linux.c +@@ -226,13 +226,13 @@ grub_initrd_init (int argc, char *argv[], + int i; + int newc = 0; + struct dir *root = 0; +- struct grub_key_publisher *pk; ++ grub_crypto_key_list_t *pk; + int numkey = 0; + + initrd_ctx->nfiles = 0; + initrd_ctx->components = 0; + +- FOR_LIST_ELEMENTS (pk, kpuber) ++ FOR_LIST_ELEMENTS (pk, cryptokey_lst) + if (pk->key && pk->path) + numkey++; + +@@ -305,7 +305,7 @@ grub_initrd_init (int argc, char *argv[], + goto overflow; + } + +- FOR_LIST_ELEMENTS (pk, kpuber) ++ FOR_LIST_ELEMENTS (pk, cryptokey_lst) + if (pk->key && pk->path) + { + grub_initrd_component (pk->key, pk->key_len, pk->path, initrd_ctx); +diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c +index a3f711d1d..1b426af69 100644 +--- a/grub-core/normal/main.c ++++ b/grub-core/normal/main.c +@@ -479,7 +479,7 @@ grub_cmdline_run (int nested, int force_auth) + return; + } + +- grub_initrd_discard_key (); ++ grub_cryptokey_discard (); + grub_normal_reader_init (nested); + + while (1) +diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c +index 14b0ab1ec..1df2638d7 100644 +--- a/grub-core/normal/menu.c ++++ b/grub-core/normal/menu.c +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + + /* Time to delay after displaying an error message about a default/fallback + entry failing to boot. */ +@@ -708,6 +709,7 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot, int *notify_boot) + if (grub_key_is_interrupt (key)) + { + timeout = -1; ++ grub_cryptokey_tpmkey_discard(); + break; + } + +@@ -790,6 +792,11 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot, int *notify_boot) + clear_timeout (); + } + ++ /* Timeout is interrupted by external input, Forget tpmkey if timeout ++ * is not cut by enter */ ++ if (c != '\n' && c != '\r') ++ grub_cryptokey_tpmkey_discard(); ++ + switch (c) + { + case GRUB_TERM_KEY_HOME: +diff --git a/grub-core/normal/menu_entry.c b/grub-core/normal/menu_entry.c +index 384ab9ce3..e5ba91ea4 100644 +--- a/grub-core/normal/menu_entry.c ++++ b/grub-core/normal/menu_entry.c +@@ -1263,7 +1263,7 @@ grub_menu_entry_run (grub_menu_entry_t entry) + return; + } + +- grub_initrd_discard_key(); ++ grub_cryptokey_discard(); + + screen = make_screen (entry); + if (! screen) +diff --git a/include/grub/crypttab.h b/include/grub/crypttab.h +index 113c53cfc..f86404686 100644 +--- a/include/grub/crypttab.h ++++ b/include/grub/crypttab.h +@@ -4,21 +4,25 @@ + #include + #include + +-struct grub_key_publisher ++typedef struct grub_crypto_key_list + { +- struct grub_key_publisher *next; +- struct grub_key_publisher **prev; ++ struct grub_crypto_key_list *next; ++ struct grub_crypto_key_list **prev; + char *name; /* UUID */ + char *path; + char *key; + grub_size_t key_len; +-}; ++ int is_tpmkey; ++} grub_crypto_key_list_t; + +-extern struct grub_key_publisher *EXPORT_VAR (kpuber); ++extern grub_crypto_key_list_t *EXPORT_VAR (cryptokey_lst); + + grub_err_t +-grub_initrd_publish_key (const char *uuid, const char *key, grub_size_t key_len, const char *path); ++grub_cryptokey_add_or_update (const char *uuid, const char *key, grub_size_t key_len, const char *path, int is_tpmkey); + + void +-grub_initrd_discard_key (void); ++grub_cryptokey_discard (void); ++ ++void ++grub_cryptokey_tpmkey_discard (void); + #endif /* ! GRUB_CRYPTTAB_HEADER */ +-- +2.42.1 + diff --git a/0002-Restrict-file-access-on-cryptodisk-print.patch b/0002-Restrict-file-access-on-cryptodisk-print.patch new file mode 100644 index 0000000..2280169 --- /dev/null +++ b/0002-Restrict-file-access-on-cryptodisk-print.patch @@ -0,0 +1,197 @@ +From 912384e63c1e3b6aa9d90effb71cd535a17da1e2 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Sat, 18 Nov 2023 19:02:31 +0800 +Subject: [PATCH 2/4] Restrict file access on cryptodisk print + +When the encrypted partition is automatically unlocked by TPM, granting +access to the system upon validation of its known good state, there's a +potential vulnerability. Grub gains access to file systems that were +previously inaccessible to the public, enabling certain commands from +the grub console to print content. This arises due to grub lacking +restrictions similar to those imposed by password authentication, which +typically occurs before privileged access is granted. + +Although the automatic unlocking process ensures system integrity and a +secure environment for grub to operate in, it doesn't directly address +the issue of authentication for viewing encrypted partition content. + +This commit addresses this security loophole by implementing a file +filter upon adding a TPM key. The newly added file filter will +specifically verify if the disk is encrypted, denying access and +returning an "Access Denied: prohibited to view encrypted data" error +message to alert the user. + +Since the policy to filter out unwanted commands from leaking encrypted +content is irreversible, it is advisable to make the loaded module +persistent to prevent its removal. + +This enhancement aims to bolster security measures and prevent +unauthorized access to encrypted data. + +Signed-Off-by Michael Chang +--- + grub-core/commands/crypttab.c | 35 ++++++++++++++++++++++++++++++++++- + grub-core/disk/diskfilter.c | 35 +++++++++++++++++++++++++++++++++++ + include/grub/disk.h | 10 ++++++++++ + include/grub/file.h | 1 + + 4 files changed, 80 insertions(+), 1 deletion(-) + +diff --git a/grub-core/commands/crypttab.c b/grub-core/commands/crypttab.c +index 9397bede9..d3acc4b59 100644 +--- a/grub-core/commands/crypttab.c ++++ b/grub-core/commands/crypttab.c +@@ -6,11 +6,39 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + + grub_crypto_key_list_t *cryptokey_lst; + ++static grub_file_t ++grub_nocat_open (grub_file_t io, enum grub_file_type type) ++{ ++ grub_disk_t disk; ++ ++ /* Network device */ ++ if (!io->device->disk) ++ return io; ++ ++ disk = io->device->disk; ++ ++ if (grub_disk_is_crypto (disk)) ++ { ++ switch (type & GRUB_FILE_TYPE_MASK) ++ { ++ case GRUB_FILE_TYPE_CAT: ++ case GRUB_FILE_TYPE_HEXCAT: ++ grub_error (GRUB_ERR_ACCESS_DENIED, N_("prohibited to view encrypted data")); ++ return NULL; ++ default: ++ break; ++ } ++ } ++ ++ return io; ++} ++ + grub_err_t + grub_cryptokey_add_or_update (const char *uuid, const char *key, grub_size_t key_len, const char *path, int is_tpmkey) + { +@@ -48,7 +76,11 @@ grub_cryptokey_add_or_update (const char *uuid, const char *key, grub_size_t key + } + + if (is_tpmkey >= 0) +- cur->is_tpmkey = is_tpmkey; ++ { ++ cur->is_tpmkey = is_tpmkey; ++ if (is_tpmkey) ++ grub_file_filter_register (GRUB_FILE_FILTER_NOCAT, grub_nocat_open); ++ } + + if (!cur->name) + { +@@ -121,6 +153,7 @@ GRUB_MOD_INIT(crypttab) + { + cmd = grub_register_command ("crypttab_entry", grub_cmd_crypttab_entry, + N_("VOLUME-NAME ENCRYPTED-DEVICE KEY-FILE") , N_("No description")); ++ grub_dl_set_persistent (mod); + } + + GRUB_MOD_FINI(crypttab) +diff --git a/grub-core/disk/diskfilter.c b/grub-core/disk/diskfilter.c +index 5c5fabe1a..b0c1c880d 100644 +--- a/grub-core/disk/diskfilter.c ++++ b/grub-core/disk/diskfilter.c +@@ -558,6 +558,39 @@ find_lv (const char *name) + return NULL; + } + ++static int ++grub_diskfilter_has_cryptodisk (const struct grub_diskfilter_lv *lv) ++{ ++ struct grub_diskfilter_pv *pv; ++ ++ if (!lv) ++ return 0; ++ ++ if (lv->vg->pvs) ++ for (pv = lv->vg->pvs; pv; pv = pv->next) ++ { ++ if (!pv->disk) ++ { ++ grub_dprintf ("diskfilter", _("Couldn't find physical volume `%s'." ++ " Some modules may be missing from core image."), ++ pv->name); ++ continue; ++ } ++ ++ switch (pv->disk->dev->id) ++ { ++ case GRUB_DISK_DEVICE_CRYPTODISK_ID: ++ return 1; ++ case GRUB_DISK_DEVICE_DISKFILTER_ID: ++ return grub_diskfilter_has_cryptodisk (pv->disk->data); ++ default: ++ break; ++ } ++ } ++ ++ return 0; ++} ++ + static grub_err_t + grub_diskfilter_open (const char *name, grub_disk_t disk) + { +@@ -589,6 +622,8 @@ grub_diskfilter_open (const char *name, grub_disk_t disk) + + disk->total_sectors = lv->size; + disk->max_agglomerate = GRUB_DISK_MAX_MAX_AGGLOMERATE; ++ disk->is_crypto_diskfilter = grub_diskfilter_has_cryptodisk (lv); ++ + return 0; + } + +diff --git a/include/grub/disk.h b/include/grub/disk.h +index 3b3db6222..63982f16c 100644 +--- a/include/grub/disk.h ++++ b/include/grub/disk.h +@@ -147,6 +147,8 @@ struct grub_disk + + /* Device-specific data. */ + void *data; ++ ++ int is_crypto_diskfilter; + }; + typedef struct grub_disk *grub_disk_t; + +@@ -314,4 +316,12 @@ void grub_mdraid1x_fini (void); + void grub_diskfilter_fini (void); + #endif + ++static inline int ++grub_disk_is_crypto (grub_disk_t disk) ++{ ++ return ((disk->is_crypto_diskfilter || ++ disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID) ? ++ 1 : 0); ++} ++ + #endif /* ! GRUB_DISK_HEADER */ +diff --git a/include/grub/file.h b/include/grub/file.h +index fde58f0fa..fcfd32ce2 100644 +--- a/include/grub/file.h ++++ b/include/grub/file.h +@@ -185,6 +185,7 @@ extern grub_disk_read_hook_t EXPORT_VAR(grub_file_progress_hook); + /* Filters with lower ID are executed first. */ + typedef enum grub_file_filter_id + { ++ GRUB_FILE_FILTER_NOCAT, + GRUB_FILE_FILTER_VERIFY, + GRUB_FILE_FILTER_GZIO, + GRUB_FILE_FILTER_XZIO, +-- +2.42.1 + diff --git a/0003-Restrict-ls-and-auto-file-completion-on-cryptodisk-p.patch b/0003-Restrict-ls-and-auto-file-completion-on-cryptodisk-p.patch new file mode 100644 index 0000000..0f56012 --- /dev/null +++ b/0003-Restrict-ls-and-auto-file-completion-on-cryptodisk-p.patch @@ -0,0 +1,117 @@ +From 6c8d390809956d355fed8bc830f64e86838e3e82 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Sat, 18 Nov 2023 21:42:00 +0800 +Subject: [PATCH 3/4] Restrict 'ls' and auto file completion on cryptodisk + print + +The 'ls' command allows file listing, while file completion assists in +providing matched file names by partially inputting via the TAB key. +Both functionalities should be restricted when the disk is automatically +unlocked for the same reasons as highlighted in the previous patch +addressing the limitation on file access to the cryptodisk. + +Given that no file is explicitly opened for listing, employing file +filters becomes impractical. Consequently, this patch focuses on +modifying relevant routines separately to incorporate necessary checks. +The objective is to introduce measures that prevent 'ls' and auto file +completion from accessing encrypted data when the disk is automatically +unlocked. + +By implementing these modifications, any attempt to utilize 'ls' or file +completion on the cryptodisk will result in an "Access Denied: +prohibited to browse encrypted data" error message, thus effectively +alerting the user about the restricted access. + +While protecting content within disk files from viewing is essential, +it's equally crucial to restrict access to in-memory content. This +includes prohibiting access to the decrypted in-memory copies of disk +files. + +This enhancement aims to fortify security protocols by extending +restrictions to additional functionalities beyond direct file access. + +Signed-Off-by Michael Chang +--- + grub-core/commands/ls.c | 8 ++++++++ + grub-core/commands/minicmd.c | 6 ++++++ + grub-core/kern/corecmd.c | 8 ++++++++ + grub-core/normal/completion.c | 8 ++++++++ + 4 files changed, 30 insertions(+) + +diff --git a/grub-core/commands/ls.c b/grub-core/commands/ls.c +index 8e98c73cc..aeb336a73 100644 +--- a/grub-core/commands/ls.c ++++ b/grub-core/commands/ls.c +@@ -183,6 +183,14 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human) + if (! dev) + goto fail; + ++ if (dev->disk && ++ grub_disk_is_crypto (dev->disk) && ++ grub_file_filters[GRUB_FILE_FILTER_NOCAT]) ++ { ++ grub_error (GRUB_ERR_ACCESS_DENIED, N_("prohibited to browse encrypted content")); ++ goto fail; ++ } ++ + fs = grub_fs_probe (dev); + path = grub_strchr (dirname, ')'); + if (! path) +diff --git a/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c +index fa498931e..8f2ac0539 100644 +--- a/grub-core/commands/minicmd.c ++++ b/grub-core/commands/minicmd.c +@@ -101,6 +101,12 @@ grub_mini_cmd_dump (struct grub_command *cmd __attribute__ ((unused)), + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no address specified"); + ++ /* NOCAT filter is applied to prevent cat alike command from revealing file ++ * content, the dump command should also be prohibited to revealing memory ++ * content as well */ ++ if (grub_file_filters[GRUB_FILE_FILTER_NOCAT]) ++ return grub_error (GRUB_ERR_ACCESS_DENIED, N_("prohibited by security policy")); ++ + #if GRUB_CPU_SIZEOF_VOID_P == GRUB_CPU_SIZEOF_LONG + #define grub_strtoaddr grub_strtoul + #else +diff --git a/grub-core/kern/corecmd.c b/grub-core/kern/corecmd.c +index 62d434ba9..b639bc3ae 100644 +--- a/grub-core/kern/corecmd.c ++++ b/grub-core/kern/corecmd.c +@@ -135,6 +135,14 @@ grub_core_cmd_ls (struct grub_command *cmd __attribute__ ((unused)), + if (! dev) + goto fail; + ++ if (dev->disk && ++ grub_disk_is_crypto (dev->disk) && ++ grub_file_filters[GRUB_FILE_FILTER_NOCAT]) ++ { ++ grub_error (GRUB_ERR_ACCESS_DENIED, N_("prohibited to browse encrypted content")); ++ goto fail; ++ } ++ + fs = grub_fs_probe (dev); + path = grub_strchr (argv[0], ')'); + if (! path) +diff --git a/grub-core/normal/completion.c b/grub-core/normal/completion.c +index 18cadfa85..d003ec37d 100644 +--- a/grub-core/normal/completion.c ++++ b/grub-core/normal/completion.c +@@ -259,6 +259,14 @@ complete_file (void) + goto fail; + } + ++ if (dev->disk && ++ grub_disk_is_crypto (dev->disk) && ++ grub_file_filters[GRUB_FILE_FILTER_NOCAT]) ++ { ++ grub_error (GRUB_ERR_ACCESS_DENIED, N_("prohibited to browse encrypted content")); ++ goto fail; ++ } ++ + fs = grub_fs_probe (dev); + if (! fs) + { +-- +2.42.1 + diff --git a/0004-Key-revocation-on-out-of-bound-file-access.patch b/0004-Key-revocation-on-out-of-bound-file-access.patch new file mode 100644 index 0000000..2a85d8d --- /dev/null +++ b/0004-Key-revocation-on-out-of-bound-file-access.patch @@ -0,0 +1,91 @@ +From 6547d22fc9e20720d1a896be82b2d50d842f86b0 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Mon, 20 Nov 2023 09:25:53 +0800 +Subject: [PATCH 4/4] Key revocation on out of bound file access + +After successful disk unlocking, grub now takes on the responsibility of +safeguarding passwords or TPM keys exclusively within authenticated +cryptodisk files. Any attempt to access boot-related files outside this +trust realm triggers immediate key revocation, preventing potential +compromise by out of bound access. + +This patch strengthens security measures by restricting grub's access to +system boot files, except for essential internal processes like memdisk +and procfs, ensuring key protection against potential breaches due to +inadvertent customizations in grub.cfg. + +Signed-Off-by Michael Chang +--- + grub-core/commands/crypttab.c | 36 +++++++++++++++++++++++++++++++++++ + include/grub/file.h | 1 + + 2 files changed, 37 insertions(+) + +diff --git a/grub-core/commands/crypttab.c b/grub-core/commands/crypttab.c +index d3acc4b59..e09296c57 100644 +--- a/grub-core/commands/crypttab.c ++++ b/grub-core/commands/crypttab.c +@@ -121,6 +121,41 @@ grub_cryptokey_tpmkey_discard (void) + grub_cryptokey_discard(); + } + ++static grub_file_t ++grub_distrust_open (grub_file_t io, ++ enum grub_file_type type __attribute__ ((unused))) ++{ ++ grub_disk_t disk = io->device->disk; ++ ++ if (io->device->disk && ++ (io->device->disk->dev->id == GRUB_DISK_DEVICE_MEMDISK_ID ++ || io->device->disk->dev->id == GRUB_DISK_DEVICE_PROCFS_ID)) ++ return io; ++ ++ /* Ensure second stage files is in a protected location or grub won't hand ++ * over the key and discards it */ ++ switch (type & GRUB_FILE_TYPE_MASK) ++ { ++ case GRUB_FILE_TYPE_ACPI_TABLE: ++ case GRUB_FILE_TYPE_CONFIG: ++ case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE: ++ case GRUB_FILE_TYPE_FONT: ++ case GRUB_FILE_TYPE_GRUB_MODULE: ++ case GRUB_FILE_TYPE_GRUB_MODULE_LIST: ++ case GRUB_FILE_TYPE_LINUX_KERNEL: ++ case GRUB_FILE_TYPE_LINUX_INITRD: ++ case GRUB_FILE_TYPE_LOADENV: ++ case GRUB_FILE_TYPE_THEME: ++ if (!disk || !grub_disk_is_crypto (disk)) ++ grub_cryptokey_discard (); ++ break; ++ default: ++ break; ++ } ++ ++ return io; ++} ++ + static grub_err_t + grub_cmd_crypttab_entry (grub_command_t cmd __attribute__ ((unused)), + int argc, char **argv) +@@ -153,6 +188,7 @@ GRUB_MOD_INIT(crypttab) + { + cmd = grub_register_command ("crypttab_entry", grub_cmd_crypttab_entry, + N_("VOLUME-NAME ENCRYPTED-DEVICE KEY-FILE") , N_("No description")); ++ grub_file_filter_register (GRUB_FILE_FILTER_DISTRUST, grub_distrust_open); + grub_dl_set_persistent (mod); + } + +diff --git a/include/grub/file.h b/include/grub/file.h +index fcfd32ce2..daf23a9c9 100644 +--- a/include/grub/file.h ++++ b/include/grub/file.h +@@ -185,6 +185,7 @@ extern grub_disk_read_hook_t EXPORT_VAR(grub_file_progress_hook); + /* Filters with lower ID are executed first. */ + typedef enum grub_file_filter_id + { ++ GRUB_FILE_FILTER_DISTRUST, + GRUB_FILE_FILTER_NOCAT, + GRUB_FILE_FILTER_VERIFY, + GRUB_FILE_FILTER_GZIO, +-- +2.42.1 + diff --git a/grub2.changes b/grub2.changes index 8fa9959..f4d8de7 100644 --- a/grub2.changes +++ b/grub2.changes @@ -1,3 +1,13 @@ +------------------------------------------------------------------- +Wed Nov 22 09:25:23 UTC 2023 - Michael Chang + +- Fix unattended boot with TPM2 allows downgrading kernel and rootfs, also + enhancing the overall security posture (bsc#1216680) + * 0001-Improve-TPM-key-protection-on-boot-interruptions.patch + * 0002-Restrict-file-access-on-cryptodisk-print.patch + * 0003-Restrict-ls-and-auto-file-completion-on-cryptodisk-p.patch + * 0004-Key-revocation-on-out-of-bound-file-access.patch + ------------------------------------------------------------------- Tue Nov 21 06:52:08 UTC 2023 - Michael Chang diff --git a/grub2.spec b/grub2.spec index 011744e..d36e5dd 100644 --- a/grub2.spec +++ b/grub2.spec @@ -393,6 +393,10 @@ Patch200: 0001-kern-ieee1275-init-Restrict-high-memory-in-presence-.patch Patch201: 0001-fs-xfs-Incorrect-short-form-directory-data-boundary-.patch Patch202: 0002-fs-xfs-Fix-XFS-directory-extent-parsing.patch Patch203: 0003-fs-xfs-add-large-extent-counters-incompat-feature-su.patch +Patch204: 0001-Improve-TPM-key-protection-on-boot-interruptions.patch +Patch205: 0002-Restrict-file-access-on-cryptodisk-print.patch +Patch206: 0003-Restrict-ls-and-auto-file-completion-on-cryptodisk-p.patch +Patch207: 0004-Key-revocation-on-out-of-bound-file-access.patch Requires: gettext-runtime %if 0%{?suse_version} >= 1140