From c262268bec3c3737d376947d687e64ff47e172e7 Mon Sep 17 00:00:00 2001 From: eabdullin Date: Mon, 15 Sep 2025 12:02:18 +0000 Subject: [PATCH] import CS grub2-2.06-113.el9 --- .../0458-fs-Remove-trailing-whitespaces.patch | 1684 ++++++++++ ...s-xfs-Fix-memory-leaks-in-XFS-module.patch | 50 + ...-short-form-directory-data-boundary-.patch | 51 + ...xfs-Fix-XFS-directory-extent-parsing.patch | 171 ++ ...-extent-counters-incompat-feature-su.patch | 119 + ...n-continuous-data-blocks-in-director.patch | 57 + ...-extent-counters-incompat-feature-su.patch | 48 + ...mkimage-Create-new-ELF-note-for-SBAT.patch | 167 + ...-SBAT-metadata-into-ELF-note-for-Pow.patch | 45 + ...pended-sig-sync-d-with-upstream-code.patch | 2720 +++++++++++++++++ ...ee1275-Platform-Keystore-PKS-Support.patch | 200 ++ ...the-DB-and-DBX-secure-boot-variables.patch | 686 +++++ ...creation-of-trusted-and-distrusted-l.patch | 764 +++++ ...e-verifying-the-kernel-use-trusted-a.patch | 250 ++ ...pc_ieee1275-set-use_static_keys-flag.patch | 107 + ...ds-the-default-DB-keys-from-ELF-Note.patch | 108 + ...grub-command-s-trusted-and-distruste.patch | 660 ++++ SOURCES/0475-appendedsig-documentation.patch | 210 ++ ...ode-command-for-getting-setting-the-.patch | 301 ++ ...pe-kernel-option-characters-properly.patch | 45 + ...variable-is-escaped-before-consideri.patch | 26 + ...oot-Detect-DDF-container-similar-to-.patch | 86 + ...e-memory-attributes-for-the-kernel-P.patch | 342 +++ SOURCES/20-grub.install | 3 +- SOURCES/gen_grub_cfgstub | 29 + SOURCES/grub.macros | 3 + SOURCES/grub.patches | 23 + SOURCES/sbat.csv.in | 3 +- SPECS/grub2.spec | 56 +- 29 files changed, 9000 insertions(+), 14 deletions(-) create mode 100644 SOURCES/0458-fs-Remove-trailing-whitespaces.patch create mode 100644 SOURCES/0459-fs-xfs-Fix-memory-leaks-in-XFS-module.patch create mode 100644 SOURCES/0460-fs-xfs-Incorrect-short-form-directory-data-boundary-.patch create mode 100644 SOURCES/0461-fs-xfs-Fix-XFS-directory-extent-parsing.patch create mode 100644 SOURCES/0462-fs-xfs-Add-large-extent-counters-incompat-feature-su.patch create mode 100644 SOURCES/0463-fs-xfs-Handle-non-continuous-data-blocks-in-director.patch create mode 100644 SOURCES/0464-fs-xfs-fix-large-extent-counters-incompat-feature-su.patch create mode 100644 SOURCES/0465-grub-mkimage-Create-new-ELF-note-for-SBAT.patch create mode 100644 SOURCES/0466-grub-mkimage-Add-SBAT-metadata-into-ELF-note-for-Pow.patch create mode 100644 SOURCES/0467-appended-sig-sync-d-with-upstream-code.patch create mode 100644 SOURCES/0468-ieee1275-Platform-Keystore-PKS-Support.patch create mode 100644 SOURCES/0469-ieee1275-Read-the-DB-and-DBX-secure-boot-variables.patch create mode 100644 SOURCES/0470-appendedsig-The-creation-of-trusted-and-distrusted-l.patch create mode 100644 SOURCES/0471-appendedsig-While-verifying-the-kernel-use-trusted-a.patch create mode 100644 SOURCES/0472-powerpc_ieee1275-set-use_static_keys-flag.patch create mode 100644 SOURCES/0473-appendedsig-Reads-the-default-DB-keys-from-ELF-Note.patch create mode 100644 SOURCES/0474-appendedsig-The-grub-command-s-trusted-and-distruste.patch create mode 100644 SOURCES/0475-appendedsig-documentation.patch create mode 100644 SOURCES/0476-efi-Add-efitextmode-command-for-getting-setting-the-.patch create mode 100644 SOURCES/0477-10_linux.in-escape-kernel-option-characters-properly.patch create mode 100644 SOURCES/0478-blscfg-check-if-variable-is-escaped-before-consideri.patch create mode 100644 SOURCES/0479-osdep-linux-getroot-Detect-DDF-container-similar-to-.patch create mode 100644 SOURCES/0480-Set-correctly-the-memory-attributes-for-the-kernel-P.patch create mode 100644 SOURCES/gen_grub_cfgstub diff --git a/SOURCES/0458-fs-Remove-trailing-whitespaces.patch b/SOURCES/0458-fs-Remove-trailing-whitespaces.patch new file mode 100644 index 0000000..90ccaf6 --- /dev/null +++ b/SOURCES/0458-fs-Remove-trailing-whitespaces.patch @@ -0,0 +1,1684 @@ +From 98d2aaea5e8d117563e70e0bf45e3d7f6d165e77 Mon Sep 17 00:00:00 2001 +From: Elyes Haouas +Date: Fri, 4 Mar 2022 07:41:59 +0100 +Subject: [PATCH 458/464] fs: Remove trailing whitespaces + +Signed-off-by: Elyes Haouas +Reviewed-by: Daniel Kiper +--- + grub-core/fs/affs.c | 4 +- + grub-core/fs/archelp.c | 4 +- + grub-core/fs/bfs.c | 10 +- + grub-core/fs/cpio_common.c | 2 +- + grub-core/fs/fat.c | 6 +- + grub-core/fs/fshelp.c | 6 +- + grub-core/fs/hfs.c | 14 +- + grub-core/fs/hfsplus.c | 8 +- + grub-core/fs/hfspluscomp.c | 6 +- + grub-core/fs/iso9660.c | 12 +- + grub-core/fs/minix.c | 6 +- + grub-core/fs/nilfs2.c | 8 +- + grub-core/fs/ntfs.c | 8 +- + grub-core/fs/reiserfs.c | 2 +- + grub-core/fs/romfs.c | 8 +- + grub-core/fs/squash4.c | 26 ++-- + grub-core/fs/udf.c | 2 +- + grub-core/fs/ufs.c | 4 +- + grub-core/fs/xfs.c | 2 +- + grub-core/fs/zfs/zfs.c | 224 ++++++++++++++++---------------- + grub-core/fs/zfs/zfs_fletcher.c | 12 +- + grub-core/fs/zfs/zfs_sha256.c | 14 +- + grub-core/fs/zfs/zfscrypt.c | 14 +- + 23 files changed, 201 insertions(+), 201 deletions(-) + +diff --git a/grub-core/fs/affs.c b/grub-core/fs/affs.c +index 0133528eaf5b..b9cea9237bc8 100644 +--- a/grub-core/fs/affs.c ++++ b/grub-core/fs/affs.c +@@ -346,7 +346,7 @@ grub_affs_create_node (grub_fshelp_node_t dir, + if (len > sizeof (fil->name)) + len = sizeof (fil->name); + *grub_latin1_to_utf8 (name_u8, fil->name, len) = '\0'; +- ++ + (*node)->di = *fil; + for (nest = 0; nest < 8; nest++) + { +@@ -409,7 +409,7 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir, + node = orig_node = grub_zalloc (sizeof (*node)); + if (!node) + return 1; +- ++ + *node = *dir; + if (hook (".", GRUB_FSHELP_DIR, node, hook_data)) + return 1; +diff --git a/grub-core/fs/archelp.c b/grub-core/fs/archelp.c +index 6491f74f957d..ab634307e838 100644 +--- a/grub-core/fs/archelp.c ++++ b/grub-core/fs/archelp.c +@@ -77,7 +77,7 @@ handle_symlink (struct grub_archelp_data *data, + || !arcops->get_link_target) + return GRUB_ERR_NONE; + flen = grub_strlen (fn); +- if (grub_memcmp (*name, fn, flen) != 0 ++ if (grub_memcmp (*name, fn, flen) != 0 + || ((*name)[flen] != 0 && (*name)[flen] != '/')) + return GRUB_ERR_NONE; + rest = *name + flen; +@@ -258,7 +258,7 @@ grub_archelp_open (struct grub_archelp_data *data, + grub_uint32_t mode; + grub_int32_t mtime; + int restart; +- ++ + if (arcops->find_file (data, &fn, &mtime, &mode)) + goto fail; + +diff --git a/grub-core/fs/bfs.c b/grub-core/fs/bfs.c +index 760c6229af09..9ed1fd763df7 100644 +--- a/grub-core/fs/bfs.c ++++ b/grub-core/fs/bfs.c +@@ -531,13 +531,13 @@ iterate_in_b_tree (grub_disk_t disk, + err = read_b_node (disk, sb, ino, + node_off, + &node, +- &key_data, ++ &key_data, + &keylen_idx, + &key_values); + + if (err) + return 0; +- ++ + for (i = 0; i < grub_bfs_to_cpu_treehead (node->count_keys); i++) + { + char c; +@@ -683,7 +683,7 @@ find_in_b_tree (grub_disk_t disk, + level--; + grub_free (node); + continue; +- } ++ } + } + else if (level != 0 + && i + 1 < grub_bfs_to_cpu_treehead (node->count_keys)) +@@ -828,7 +828,7 @@ mount (grub_disk_t disk, struct grub_bfs_superblock *sb) + grub_err_t err; + err = grub_disk_read (disk, SUPERBLOCK, 0, sizeof (*sb), sb); + if (err == GRUB_ERR_OUT_OF_RANGE) +- return grub_error (GRUB_ERR_BAD_FS, ++ return grub_error (GRUB_ERR_BAD_FS, + #ifdef MODE_AFS + "not an AFS filesystem" + #else +@@ -844,7 +844,7 @@ mount (grub_disk_t disk, struct grub_bfs_superblock *sb) + || (grub_bfs_to_cpu32 (sb->bsize) + != (1U << grub_bfs_to_cpu32 (sb->log2_bsize))) + || grub_bfs_to_cpu32 (sb->log2_bsize) < GRUB_DISK_SECTOR_BITS) +- return grub_error (GRUB_ERR_BAD_FS, ++ return grub_error (GRUB_ERR_BAD_FS, + #ifdef MODE_AFS + "not an AFS filesystem" + #else +diff --git a/grub-core/fs/cpio_common.c b/grub-core/fs/cpio_common.c +index e6c51a6af399..45ac119a8f87 100644 +--- a/grub-core/fs/cpio_common.c ++++ b/grub-core/fs/cpio_common.c +@@ -139,7 +139,7 @@ grub_cpio_get_link_target (struct grub_archelp_data *data) + if (!ret) + return NULL; + +- err = grub_disk_read (data->disk, 0, data->dofs, data->size, ++ err = grub_disk_read (data->disk, 0, data->dofs, data->size, + ret); + if (err) + { +diff --git a/grub-core/fs/fat.c b/grub-core/fs/fat.c +index 1cf355af42cf..6e62b915dd1c 100644 +--- a/grub-core/fs/fat.c ++++ b/grub-core/fs/fat.c +@@ -246,7 +246,7 @@ grub_fat_mount (grub_disk_t disk) + #ifdef MODE_EXFAT + if (grub_memcmp ((const char *) bpb.oem_name, "EXFAT ", + sizeof (bpb.oem_name)) != 0) +- goto fail; ++ goto fail; + #endif + + /* Get the sizes of logical sectors and clusters. */ +@@ -321,7 +321,7 @@ grub_fat_mount (grub_disk_t disk) + #endif + + #ifdef MODE_EXFAT +- data->cluster_sector = (grub_le_to_cpu32 (bpb.cluster_offset) ++ data->cluster_sector = (grub_le_to_cpu32 (bpb.cluster_offset) + << data->logical_sector_bits); + data->num_clusters = (grub_le_to_cpu32 (bpb.cluster_count) + << data->logical_sector_bits); +@@ -694,7 +694,7 @@ grub_fat_iterate_dir_next (grub_fshelp_node_t node, + { + int j; + for (j = 0; j < 15; j++) +- ctxt->unibuf[slots * 15 + j] ++ ctxt->unibuf[slots * 15 + j] + = grub_le_to_cpu16 (sec.type_specific.file_name.str[j]); + slots++; + } +diff --git a/grub-core/fs/fshelp.c b/grub-core/fs/fshelp.c +index a2d0d297a520..cb41934b4fec 100644 +--- a/grub-core/fs/fshelp.c ++++ b/grub-core/fs/fshelp.c +@@ -215,7 +215,7 @@ find_file (char *currpath, + break; + + push_node (ctx, foundnode, foundtype); +- ++ + /* Read in the symlink and follow it. */ + if (ctx->currnode->type == GRUB_FSHELP_SYMLINK) + { +@@ -326,7 +326,7 @@ grub_fshelp_find_file (const char *path, grub_fshelp_node_t rootnode, + enum grub_fshelp_filetype expecttype) + { + return grub_fshelp_find_file_real (path, rootnode, foundnode, +- iterate_dir, NULL, ++ iterate_dir, NULL, + read_symlink, expecttype); + + } +@@ -339,7 +339,7 @@ grub_fshelp_find_file_lookup (const char *path, grub_fshelp_node_t rootnode, + enum grub_fshelp_filetype expecttype) + { + return grub_fshelp_find_file_real (path, rootnode, foundnode, +- NULL, lookup_file, ++ NULL, lookup_file, + read_symlink, expecttype); + + } +diff --git a/grub-core/fs/hfs.c b/grub-core/fs/hfs.c +index 3a98944434b1..ce7581dd5f1c 100644 +--- a/grub-core/fs/hfs.c ++++ b/grub-core/fs/hfs.c +@@ -883,7 +883,7 @@ grub_hfs_iterate_dir_it_dir (struct grub_hfs_node *hnd __attribute ((unused)), + { + struct grub_hfs_catalog_key *ckey = rec->key; + struct grub_hfs_iterate_dir_node_found_ctx *ctx = hook_arg; +- ++ + /* Stop when the entries do not match anymore. */ + if (ckey->parent_dir != ctx->dir_be) + return 1; +@@ -1077,7 +1077,7 @@ macroman_to_utf8 (char *to, const grub_uint8_t *from, grub_size_t len, + { + *optr++ = ':'; + continue; +- } ++ } + if (!(*iptr & 0x80)) + { + *optr++ = *iptr; +@@ -1094,7 +1094,7 @@ utf8_to_macroman (grub_uint8_t *to, const char *from) + grub_uint8_t *end = to + 31; + grub_uint8_t *optr = to; + const char *iptr = from; +- ++ + while (*iptr && optr < end) + { + int i, clen; +@@ -1104,7 +1104,7 @@ utf8_to_macroman (grub_uint8_t *to, const char *from) + *optr++ = '/'; + iptr++; + continue; +- } ++ } + if (!(*iptr & 0x80)) + { + *optr++ = *iptr++; +@@ -1165,7 +1165,7 @@ lookup_file (grub_fshelp_node_t dir, + *foundnode = grub_malloc (sizeof (struct grub_fshelp_node)); + if (!*foundnode) + return grub_errno; +- ++ + (*foundnode)->inode = grub_be_to_cpu32 (fdrec.dir.dirid); + (*foundnode)->fdrec = fdrec; + (*foundnode)->data = dir->data; +@@ -1266,7 +1266,7 @@ grub_hfs_dir (grub_device_t device, const char *path, grub_fs_dir_hook_t hook, + .hook_data = hook_data + }; + grub_fshelp_node_t found = NULL; +- ++ + grub_dl_ref (my_mod); + + data = grub_hfs_mount (device->disk); +@@ -1295,7 +1295,7 @@ grub_hfs_open (struct grub_file *file, const char *name) + { + struct grub_hfs_data *data; + grub_fshelp_node_t found = NULL; +- ++ + grub_dl_ref (my_mod); + + data = grub_hfs_mount (file->device->disk); +diff --git a/grub-core/fs/hfsplus.c b/grub-core/fs/hfsplus.c +index d5f90007ba53..f49082f4ce30 100644 +--- a/grub-core/fs/hfsplus.c ++++ b/grub-core/fs/hfsplus.c +@@ -19,7 +19,7 @@ + + /* HFS+ is documented at http://developer.apple.com/technotes/tn/tn1150.html */ + +-#define grub_fshelp_node grub_hfsplus_file ++#define grub_fshelp_node grub_hfsplus_file + #include + #include + #include +@@ -146,7 +146,7 @@ grub_hfsplus_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) + { + struct grub_hfsplus_btnode *nnode = 0; + grub_disk_addr_t blksleft = fileblock; +- struct grub_hfsplus_extent *extents = node->compressed ++ struct grub_hfsplus_extent *extents = node->compressed + ? &node->resource_extents[0] : &node->extents[0]; + + while (1) +@@ -477,7 +477,7 @@ grub_hfsplus_cmp_extkey (struct grub_hfsplus_key *keya, + + if (extkey_a->type < extkey_b->type) + return -1; +- ++ + akey = grub_be_to_cpu32 (extkey_a->start); + if (akey > extkey_b->start) + return 1; +@@ -568,7 +568,7 @@ grub_hfsplus_btree_search (struct grub_hfsplus_btree *btree, + struct grub_hfsplus_key_internal *key, + int (*compare_keys) (struct grub_hfsplus_key *keya, + struct grub_hfsplus_key_internal *keyb), +- struct grub_hfsplus_btnode **matchnode, ++ struct grub_hfsplus_btnode **matchnode, + grub_off_t *keyoffset) + { + grub_uint64_t currnode; +diff --git a/grub-core/fs/hfspluscomp.c b/grub-core/fs/hfspluscomp.c +index 4965ef19a7b7..b3240a052c51 100644 +--- a/grub-core/fs/hfspluscomp.c ++++ b/grub-core/fs/hfspluscomp.c +@@ -179,7 +179,7 @@ hfsplus_read_compressed_real (struct grub_hfsplus_file *node, + return len0; + } + +-static grub_err_t ++static grub_err_t + hfsplus_open_compressed_real (struct grub_hfsplus_file *node) + { + grub_err_t err; +@@ -311,8 +311,8 @@ hfsplus_open_compressed_real (struct grub_hfsplus_file *node) + + GRUB_MOD_INIT(hfspluscomp) + { +- grub_hfsplus_open_compressed = hfsplus_open_compressed_real; +- grub_hfsplus_read_compressed = hfsplus_read_compressed_real; ++ grub_hfsplus_open_compressed = hfsplus_open_compressed_real; ++ grub_hfsplus_read_compressed = hfsplus_read_compressed_real; + } + + GRUB_MOD_FINI(hfspluscomp) +diff --git a/grub-core/fs/iso9660.c b/grub-core/fs/iso9660.c +index 0c0aae5976f5..9bd2cac797b5 100644 +--- a/grub-core/fs/iso9660.c ++++ b/grub-core/fs/iso9660.c +@@ -181,7 +181,7 @@ static grub_err_t + iso9660_to_unixtime (const struct grub_iso9660_date *i, grub_int64_t *nix) + { + struct grub_datetime datetime; +- ++ + if (! i->year[0] && ! i->year[1] + && ! i->year[2] && ! i->year[3] + && ! i->month[0] && ! i->month[1] +@@ -198,7 +198,7 @@ iso9660_to_unixtime (const struct grub_iso9660_date *i, grub_int64_t *nix) + datetime.hour = (i->hour[0] - '0') * 10 + (i->hour[1] - '0'); + datetime.minute = (i->minute[0] - '0') * 10 + (i->minute[1] - '0'); + datetime.second = (i->second[0] - '0') * 10 + (i->second[1] - '0'); +- ++ + if (!grub_datetime2unixtime (&datetime, nix)) + return grub_error (GRUB_ERR_BAD_NUMBER, "incorrect date"); + *nix -= i->offset * 60 * 15; +@@ -216,7 +216,7 @@ iso9660_to_unixtime2 (const struct grub_iso9660_date2 *i, grub_int64_t *nix) + datetime.hour = i->hour; + datetime.minute = i->minute; + datetime.second = i->second; +- ++ + if (!grub_datetime2unixtime (&datetime, nix)) + return 0; + *nix -= i->offset * 60 * 15; +@@ -502,7 +502,7 @@ grub_iso9660_mount (grub_disk_t disk) + static char * + grub_iso9660_read_symlink (grub_fshelp_node_t node) + { +- return node->have_symlink ++ return node->have_symlink + ? grub_strdup (node->symlink + + (node->have_dirents) * sizeof (node->dirents[0]) + - sizeof (node->dirents)) : grub_strdup (""); +@@ -552,7 +552,7 @@ add_part (struct iterate_dir_ctx *ctx, + ctx->symlink = new; + + grub_memcpy (ctx->symlink + size, part, len2); +- ctx->symlink[size + len2] = 0; ++ ctx->symlink[size + len2] = 0; + } + + static grub_err_t +@@ -1119,7 +1119,7 @@ grub_iso9660_uuid (grub_device_t device, char **uuid) + } + + /* Get writing time of filesystem. */ +-static grub_err_t ++static grub_err_t + grub_iso9660_mtime (grub_device_t device, grub_int64_t *timebuf) + { + struct grub_iso9660_data *data; +diff --git a/grub-core/fs/minix.c b/grub-core/fs/minix.c +index fc7fa80d931e..2faf1f1b00ab 100644 +--- a/grub-core/fs/minix.c ++++ b/grub-core/fs/minix.c +@@ -99,10 +99,10 @@ struct grub_minix_sblock + grub_uint32_t max_file_size; + grub_uint32_t zones; + grub_uint16_t magic; +- ++ + grub_uint16_t pad2; + grub_uint16_t block_size; +- grub_uint8_t disk_version; ++ grub_uint8_t disk_version; + }; + #else + struct grub_minix_sblock +@@ -352,7 +352,7 @@ grub_minix_read_inode (struct grub_minix_data *data, grub_minix_ino_t ino) + int offs = (ino % (GRUB_DISK_SECTOR_SIZE + / sizeof (struct grub_minix_inode)) + * sizeof (struct grub_minix_inode)); +- ++ + grub_disk_read (data->disk, block, offs, + sizeof (struct grub_minix_inode), &data->inode); + +diff --git a/grub-core/fs/nilfs2.c b/grub-core/fs/nilfs2.c +index dd10c08f34d8..26e6077ff262 100644 +--- a/grub-core/fs/nilfs2.c ++++ b/grub-core/fs/nilfs2.c +@@ -1,5 +1,5 @@ +-/* +- * nilfs2.c - New Implementation of Log filesystem ++/* ++ * nilfs2.c - New Implementation of Log filesystem + * + * Written by Jiro SEKIBA + * +@@ -681,12 +681,12 @@ grub_nilfs2_read_checkpoint (struct grub_nilfs2_data *data, + grub_disk_t disk = data->disk; + unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE (data)); + +- /* Assume sizeof(struct grub_nilfs2_cpfile_header) < ++ /* Assume sizeof(struct grub_nilfs2_cpfile_header) < + sizeof(struct grub_nilfs2_checkpoint). + */ + blockno = grub_divmod64 (cpno, NILFS2_BLOCK_SIZE (data) / + sizeof (struct grub_nilfs2_checkpoint), &offset); +- ++ + pptr = grub_nilfs2_bmap_lookup (data, &data->sroot.sr_cpfile, blockno, 1); + if (pptr == (grub_uint64_t) - 1) + { +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index a59fbd0df6de..0e8064952acf 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -17,7 +17,7 @@ + * along with this program. If not, see . + */ + +-#define grub_fshelp_node grub_ntfs_file ++#define grub_fshelp_node grub_ntfs_file + + #include + #include +@@ -33,7 +33,7 @@ GRUB_MOD_LICENSE ("GPLv3+"); + + static grub_dl_t my_mod; + +-#define grub_fshelp_node grub_ntfs_file ++#define grub_fshelp_node grub_ntfs_file + + static inline grub_uint16_t + u16at (void *ptr, grub_size_t ofs) +@@ -837,7 +837,7 @@ grub_ntfs_read_symlink (grub_fshelp_node_t node) + && grub_isalpha (buf[4])) + { + grub_memmove (buf, buf + 6, end - buf + 1 - 6); +- end -= 6; ++ end -= 6; + } + return buf; + } +@@ -1130,7 +1130,7 @@ grub_ntfs_dir_iter (const char *filename, enum grub_fshelp_filetype filetype, + grub_memset (&info, 0, sizeof (info)); + info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR); + info.mtimeset = 1; +- info.mtime = grub_divmod64 (node->mtime, 10000000, 0) ++ info.mtime = grub_divmod64 (node->mtime, 10000000, 0) + - 86400ULL * 365 * (1970 - 1601) + - 86400ULL * ((1970 - 1601) / 4) + 86400ULL * ((1970 - 1601) / 100); + grub_free (node); +diff --git a/grub-core/fs/reiserfs.c b/grub-core/fs/reiserfs.c +index 84aadfae990b..ca47e0a43faa 100644 +--- a/grub-core/fs/reiserfs.c ++++ b/grub-core/fs/reiserfs.c +@@ -776,7 +776,7 @@ grub_reiserfs_iterate_dir (grub_fshelp_node_t item, + char *entry_name; + char *entry_name_end = 0; + char c; +- ++ + if (!(entry_state & GRUB_REISERFS_VISIBLE_MASK)) + continue; + +diff --git a/grub-core/fs/romfs.c b/grub-core/fs/romfs.c +index 6ee46991150e..eafab03b25b8 100644 +--- a/grub-core/fs/romfs.c ++++ b/grub-core/fs/romfs.c +@@ -113,7 +113,7 @@ grub_romfs_mount (grub_device_t dev) + { + grub_error (GRUB_ERR_BAD_FS, "not romfs"); + return NULL; +- } ++ } + err = do_checksum (&sb, sizeof (sb) < grub_be_to_cpu32 (sb.sb.total_size) ? + sizeof (sb) : grub_be_to_cpu32 (sb.sb.total_size)); + if (err) +@@ -272,7 +272,7 @@ grub_romfs_iterate_dir (grub_fshelp_node_t dir, + while (1) + { + char buf[16]; +- err = grub_disk_read (dir->data->disk, ++ err = grub_disk_read (dir->data->disk, + laddr >> GRUB_DISK_SECTOR_BITS, + laddr & (GRUB_DISK_SECTOR_SIZE - 1), + 16, buf); +@@ -299,7 +299,7 @@ grub_romfs_iterate_dir (grub_fshelp_node_t dir, + node->data_addr = grub_be_to_cpu32 (node->file.spec); + filetype = GRUB_FSHELP_DIR; + } +- ++ + break; + } + } +@@ -403,7 +403,7 @@ grub_romfs_read (grub_file_t file, char *buf, grub_size_t len) + data->data->disk->read_hook_data = file->read_hook_data; + grub_disk_read (data->data->disk, + (data->data_addr + file->offset) >> GRUB_DISK_SECTOR_BITS, +- (data->data_addr + file->offset) & (GRUB_DISK_SECTOR_SIZE - 1), ++ (data->data_addr + file->offset) & (GRUB_DISK_SECTOR_SIZE - 1), + len, buf); + data->data->disk->read_hook = NULL; + +diff --git a/grub-core/fs/squash4.c b/grub-core/fs/squash4.c +index 5239cdd5c46d..e0c9bb3b5a6b 100644 +--- a/grub-core/fs/squash4.c ++++ b/grub-core/fs/squash4.c +@@ -210,7 +210,7 @@ struct grub_fshelp_node + struct grub_squash_data *data; + struct grub_squash_inode ino; + grub_size_t stsize; +- struct ++ struct + { + grub_disk_addr_t ino_chunk; + grub_uint16_t ino_offset; +@@ -243,7 +243,7 @@ read_chunk (struct grub_squash_data *data, void *buf, grub_size_t len, + csize = SQUASH_CHUNK_SIZE - offset; + if (csize > len) + csize = len; +- ++ + if (grub_le_to_cpu16 (d) & SQUASH_CHUNK_UNCOMPRESSED) + { + grub_disk_addr_t a = chunk_start + 2 + offset; +@@ -256,7 +256,7 @@ read_chunk (struct grub_squash_data *data, void *buf, grub_size_t len, + else + { + char *tmp; +- grub_size_t bsize = grub_le_to_cpu16 (d) & ~SQUASH_CHUNK_FLAGS; ++ grub_size_t bsize = grub_le_to_cpu16 (d) & ~SQUASH_CHUNK_FLAGS; + grub_disk_addr_t a = chunk_start + 2; + tmp = grub_malloc (bsize); + if (!tmp) +@@ -339,7 +339,7 @@ xz_decompress (char *inbuf, grub_size_t insize, grub_off_t off, + while (len) + { + enum xz_ret xzret; +- ++ + buf.out_pos = 0; + + xzret = xz_dec_run (data->xzdec, &buf); +@@ -399,9 +399,9 @@ squash_mount (grub_disk_t disk) + return NULL; + } + +- err = grub_disk_read (disk, ++ err = grub_disk_read (disk, + grub_le_to_cpu64 (sb.unk1offset) +- >> GRUB_DISK_SECTOR_BITS, ++ >> GRUB_DISK_SECTOR_BITS, + grub_le_to_cpu64 (sb.unk1offset) + & (GRUB_DISK_SECTOR_SIZE - 1), sizeof (frag), &frag); + if (grub_errno == GRUB_ERR_OUT_OF_RANGE) +@@ -448,7 +448,7 @@ squash_mount (grub_disk_t disk) + } + + data->blksz = grub_le_to_cpu32 (data->sb.block_size); +- for (data->log2_blksz = 0; ++ for (data->log2_blksz = 0; + (1U << data->log2_blksz) < data->blksz; + data->log2_blksz++); + +@@ -649,7 +649,7 @@ make_root_node (struct grub_squash_data *data, struct grub_fshelp_node *root) + root->stack[0].ino_chunk = grub_le_to_cpu32 (data->sb.root_ino_chunk); + root->stack[0].ino_offset = grub_cpu_to_le16 (data->sb.root_ino_offset); + return read_chunk (data, &root->ino, sizeof (root->ino), +- grub_le_to_cpu64 (data->sb.inodeoffset) ++ grub_le_to_cpu64 (data->sb.inodeoffset) + + root->stack[0].ino_chunk, + root->stack[0].ino_offset); + } +@@ -771,7 +771,7 @@ grub_squash_open (struct grub_file *file, const char *name) + } + + static grub_ssize_t +-direct_read (struct grub_squash_data *data, ++direct_read (struct grub_squash_data *data, + struct grub_squash_cache_inode *ino, + grub_off_t off, char *buf, grub_size_t len) + { +@@ -888,7 +888,7 @@ direct_read (struct grub_squash_data *data, + grub_free (block); + } + else +- err = grub_disk_read (data->disk, ++ err = grub_disk_read (data->disk, + (ino->cumulated_block_sizes[i] + a + boff) + >> GRUB_DISK_SECTOR_BITS, + (ino->cumulated_block_sizes[i] + a + boff) +@@ -952,7 +952,7 @@ grub_squash_read (grub_file_t file, char *buf, grub_size_t len) + } + else + off -= direct_len; +- ++ + err = read_chunk (data, &frag, sizeof (frag), + data->fragments, sizeof (frag) * fragment); + if (err) +@@ -963,7 +963,7 @@ grub_squash_read (grub_file_t file, char *buf, grub_size_t len) + b = grub_le_to_cpu32 (ino->ino.long_file.offset) + off; + else + b = grub_le_to_cpu32 (ino->ino.file.offset) + off; +- ++ + /* FIXME: cache uncompressed chunks. */ + if (compressed) + { +@@ -1019,7 +1019,7 @@ grub_squash_mtime (grub_device_t dev, grub_int64_t *tm) + *tm = grub_le_to_cpu32 (data->sb.creation_time); + squash_unmount (data); + return GRUB_ERR_NONE; +-} ++} + + static struct grub_fs grub_squash_fs = + { +diff --git a/grub-core/fs/udf.c b/grub-core/fs/udf.c +index c0c31ae9c9be..1ece034a0fc3 100644 +--- a/grub-core/fs/udf.c ++++ b/grub-core/fs/udf.c +@@ -568,7 +568,7 @@ grub_udf_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) + (buf + sizeof (struct grub_udf_aed)); + continue; + } +- ++ + if (filebytes < adlen) + { + grub_uint32_t ad_block_num = ad->block.block_num; +diff --git a/grub-core/fs/ufs.c b/grub-core/fs/ufs.c +index 22b669b4c6a3..8b5adbd48d43 100644 +--- a/grub-core/fs/ufs.c ++++ b/grub-core/fs/ufs.c +@@ -569,7 +569,7 @@ grub_ufs_find_file (struct grub_ufs_data *data, const char *path) + { + dirino = data->ino; + grub_ufs_read_inode (data, grub_ufs_to_cpu32 (dirent.ino), 0); +- ++ + if ((INODE_MODE(data) & GRUB_UFS_ATTR_TYPE) + == GRUB_UFS_ATTR_LNK) + { +@@ -614,7 +614,7 @@ grub_ufs_mount (grub_disk_t disk) + && ((data->sblock.bsize & (data->sblock.bsize - 1)) == 0) + && data->sblock.ino_per_group != 0) + { +- for (data->log2_blksz = 0; ++ for (data->log2_blksz = 0; + (1U << data->log2_blksz) < grub_ufs_to_cpu32 (data->sblock.bsize); + data->log2_blksz++); + +diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c +index cc50febd2b79..17bf01f31ddb 100644 +--- a/grub-core/fs/xfs.c ++++ b/grub-core/fs/xfs.c +@@ -943,7 +943,7 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + tag, which is not used by GRUB. So it can be overwritten. */ + filename[direntry->len] = '\0'; + +- if (iterate_dir_call_hook (grub_be_to_cpu64(direntry->inode), ++ if (iterate_dir_call_hook (grub_be_to_cpu64(direntry->inode), + filename, &ctx)) + { + grub_free (dirblock); +diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c +index da014b123191..48d4c0b18a45 100644 +--- a/grub-core/fs/zfs/zfs.c ++++ b/grub-core/fs/zfs/zfs.c +@@ -176,7 +176,7 @@ typedef struct decomp_entry + /* + * Signature for checksum functions. + */ +-typedef void zio_checksum_t(const void *data, grub_uint64_t size, ++typedef void zio_checksum_t(const void *data, grub_uint64_t size, + grub_zfs_endian_t endian, zio_cksum_t *zcp); + + /* +@@ -297,7 +297,7 @@ check_feature(const char *name, grub_uint64_t val, struct grub_zfs_dir_ctx *ctx) + static grub_err_t + check_mos_features(dnode_phys_t *mosmdn_phys,grub_zfs_endian_t endian,struct grub_zfs_data* data ); + +-static grub_err_t ++static grub_err_t + zlib_decompress (void *s, void *d, + grub_size_t slen, grub_size_t dlen) + { +@@ -310,7 +310,7 @@ zlib_decompress (void *s, void *d, + return grub_errno; + } + +-static grub_err_t ++static grub_err_t + zle_decompress (void *s, void *d, + grub_size_t slen, grub_size_t dlen) + { +@@ -415,7 +415,7 @@ static zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS] = { + */ + static grub_err_t + zio_checksum_verify (zio_cksum_t zc, grub_uint32_t checksum, +- grub_zfs_endian_t endian, ++ grub_zfs_endian_t endian, + char *buf, grub_size_t size) + { + zio_eck_t *zec = (zio_eck_t *) (buf + size) - 1; +@@ -425,14 +425,14 @@ zio_checksum_verify (zio_cksum_t zc, grub_uint32_t checksum, + if (checksum >= ZIO_CHECKSUM_FUNCTIONS || ci->ci_func == NULL) + { + grub_dprintf ("zfs", "unknown checksum function %d\n", checksum); +- return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "unknown checksum function %d", checksum); + } + + if (ci->ci_eck) + { +- expected_cksum = zec->zec_cksum; +- zec->zec_cksum = zc; ++ expected_cksum = zec->zec_cksum; ++ zec->zec_cksum = zc; + ci->ci_func (buf, size, endian, &actual_cksum); + zec->zec_cksum = expected_cksum; + zc = expected_cksum; +@@ -445,14 +445,14 @@ zio_checksum_verify (zio_cksum_t zc, grub_uint32_t checksum, + { + grub_dprintf ("zfs", "checksum %s verification failed\n", ci->ci_name); + grub_dprintf ("zfs", "actual checksum %016llx %016llx %016llx %016llx\n", +- (unsigned long long) actual_cksum.zc_word[0], ++ (unsigned long long) actual_cksum.zc_word[0], + (unsigned long long) actual_cksum.zc_word[1], +- (unsigned long long) actual_cksum.zc_word[2], ++ (unsigned long long) actual_cksum.zc_word[2], + (unsigned long long) actual_cksum.zc_word[3]); + grub_dprintf ("zfs", "expected checksum %016llx %016llx %016llx %016llx\n", +- (unsigned long long) zc.zc_word[0], ++ (unsigned long long) zc.zc_word[0], + (unsigned long long) zc.zc_word[1], +- (unsigned long long) zc.zc_word[2], ++ (unsigned long long) zc.zc_word[2], + (unsigned long long) zc.zc_word[3]); + return grub_error (GRUB_ERR_BAD_FS, N_("checksum verification failed")); + } +@@ -485,17 +485,17 @@ vdev_uberblock_compare (uberblock_t * ub1, uberblock_t * ub2) + else + ub2_endian = GRUB_ZFS_BIG_ENDIAN; + +- if (grub_zfs_to_cpu64 (ub1->ub_txg, ub1_endian) ++ if (grub_zfs_to_cpu64 (ub1->ub_txg, ub1_endian) + < grub_zfs_to_cpu64 (ub2->ub_txg, ub2_endian)) + return -1; +- if (grub_zfs_to_cpu64 (ub1->ub_txg, ub1_endian) ++ if (grub_zfs_to_cpu64 (ub1->ub_txg, ub1_endian) + > grub_zfs_to_cpu64 (ub2->ub_txg, ub2_endian)) + return 1; + +- if (grub_zfs_to_cpu64 (ub1->ub_timestamp, ub1_endian) ++ if (grub_zfs_to_cpu64 (ub1->ub_timestamp, ub1_endian) + < grub_zfs_to_cpu64 (ub2->ub_timestamp, ub2_endian)) + return -1; +- if (grub_zfs_to_cpu64 (ub1->ub_timestamp, ub1_endian) ++ if (grub_zfs_to_cpu64 (ub1->ub_timestamp, ub1_endian) + > grub_zfs_to_cpu64 (ub2->ub_timestamp, ub2_endian)) + return 1; + +@@ -573,7 +573,7 @@ find_bestub (uberblock_phys_t * ub_array, + grub_errno = GRUB_ERR_NONE; + continue; + } +- if (ubbest == NULL ++ if (ubbest == NULL + || vdev_uberblock_compare (&(ubptr->ubp_uberblock), + &(ubbest->ubp_uberblock)) > 0) + ubbest = ubptr; +@@ -594,10 +594,10 @@ get_psize (blkptr_t * bp, grub_zfs_endian_t endian) + static grub_uint64_t + dva_get_offset (const dva_t *dva, grub_zfs_endian_t endian) + { +- grub_dprintf ("zfs", "dva=%llx, %llx\n", +- (unsigned long long) dva->dva_word[0], ++ grub_dprintf ("zfs", "dva=%llx, %llx\n", ++ (unsigned long long) dva->dva_word[0], + (unsigned long long) dva->dva_word[1]); +- return grub_zfs_to_cpu64 ((dva)->dva_word[1], ++ return grub_zfs_to_cpu64 ((dva)->dva_word[1], + endian) << SPA_MINBLOCKSHIFT; + } + +@@ -722,7 +722,7 @@ fill_vdev_info_real (struct grub_zfs_data *data, + if (!fill->children) + { + fill->n_children = nelm; +- ++ + fill->children = grub_calloc (fill->n_children, + sizeof (fill->children[0])); + if (!fill->children) +@@ -846,7 +846,7 @@ nvlist_next_nvpair (const char *nvl, const char *nvpair) + { + /* skip over header, nvl_version and nvl_nvflag */ + nvpair = nvl + 4 * 3; +- } ++ } + else + { + /* skip to the next nvpair */ +@@ -880,10 +880,10 @@ nvlist_next_nvpair (const char *nvl, const char *nvpair) + name_len = grub_be_to_cpu32 (grub_get_unaligned32 (nvp)); + nvp += 4; + +- nvp = nvp + ((name_len + 3) & ~3); // align +- if (nvp + 4 >= nvl + VDEV_PHYS_SIZE ++ nvp = nvp + ((name_len + 3) & ~3); // align ++ if (nvp + 4 >= nvl + VDEV_PHYS_SIZE + || encode_size < 0 +- || nvp + 4 + encode_size > nvl + VDEV_PHYS_SIZE) ++ || nvp + 4 + encode_size > nvl + VDEV_PHYS_SIZE) + { + grub_dprintf ("zfs", "nvlist overflow\n"); + grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist"); +@@ -903,7 +903,7 @@ nvpair_name (const char *nvp, char **buf, grub_size_t *buflen) + { + /* skip over encode/decode size */ + nvp += 4 * 2; +- ++ + *buf = (char *) (nvp + 4); + *buflen = grub_be_to_cpu32 (grub_get_unaligned32 (nvp)); + +@@ -950,7 +950,7 @@ nvpair_value (const char *nvp,char **val, + + /* skip over name */ + nvp = nvp + ((name_len + 3) & ~3); /* align */ +- ++ + /* skip over type */ + nvp += 4; + nelm = grub_be_to_cpu32 (grub_get_unaligned32 (nvp)); +@@ -964,7 +964,7 @@ nvpair_value (const char *nvp,char **val, + *size_out = encode_size; + if (nelm_out) + *nelm_out = nelm; +- ++ + return 1; + } + +@@ -1190,7 +1190,7 @@ scan_disk (grub_device_t dev, struct grub_zfs_data *data, + desc.vdev_phys_sector + = label * (sizeof (vdev_label_t) >> SPA_MINBLOCKSHIFT) + + ((VDEV_SKIP_SIZE + VDEV_BOOT_HEADER_SIZE) >> SPA_MINBLOCKSHIFT) +- + (label < VDEV_LABELS / 2 ? 0 : ++ + (label < VDEV_LABELS / 2 ? 0 : + ALIGN_DOWN (grub_disk_native_sectors (dev->disk), sizeof (vdev_label_t)) + - VDEV_LABELS * (sizeof (vdev_label_t) >> SPA_MINBLOCKSHIFT)); + +@@ -1236,7 +1236,7 @@ scan_disk (grub_device_t dev, struct grub_zfs_data *data, + grub_free (bh); + return GRUB_ERR_NONE; + } +- ++ + grub_free (ub_array); + grub_free (bh); + +@@ -1276,7 +1276,7 @@ scan_devices_iter (const char *name, void *hook_data) + + if (!inserted) + grub_device_close (dev); +- ++ + return 0; + } + +@@ -1393,7 +1393,7 @@ recovery (grub_uint8_t *bufs[4], grub_size_t s, const int nbufs, + for (i = 0; i < nbufs; i++) + { + grub_uint8_t mul; +- for (j = i; j < nbufs; j++) ++ for (j = i; j < nbufs; j++) + if (matrix1[i][j]) + break; + if (j == nbufs) +@@ -1460,7 +1460,7 @@ recovery (grub_uint8_t *bufs[4], grub_size_t s, const int nbufs, + } + default: + return grub_error (GRUB_ERR_BUG, "too big matrix"); +- } ++ } + } + + static grub_err_t +@@ -1517,7 +1517,7 @@ read_device (grub_uint64_t offset, struct grub_zfs_device_desc *desc, + int idx, orig_idx; + + if (desc->nparity < 1 || desc->nparity > 3) +- return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "raidz%d is not supported", desc->nparity); + + if (desc->n_children <= desc->nparity || desc->n_children < 1) +@@ -1666,7 +1666,7 @@ read_device (grub_uint64_t offset, struct grub_zfs_device_desc *desc, + len -= csize; + idx--; + } +- for (i = 0; i < failed_devices ++ for (i = 0; i < failed_devices + && recovery_len[i] == recovery_len[0]; + i++); + /* Since the chunks have variable length handle the last block +@@ -1789,7 +1789,7 @@ zio_read_gang (blkptr_t * bp, grub_zfs_endian_t endian, dva_t * dva, void *buf, + * Read in a block of raw data to buf. + */ + static grub_err_t +-zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian, void *buf, ++zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian, void *buf, + struct grub_zfs_data *data) + { + int i, psize; +@@ -1857,7 +1857,7 @@ decode_embedded_bp_compressed(const blkptr_t *bp, void *buf) + * and put the uncompressed data in buf. + */ + static grub_err_t +-zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf, ++zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf, + grub_size_t *size, struct grub_zfs_data *data) + { + grub_size_t lsize, psize; +@@ -1943,7 +1943,7 @@ zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf, + if (encrypted) + { + if (!grub_zfs_decrypt) +- err = grub_error (GRUB_ERR_BAD_FS, ++ err = grub_error (GRUB_ERR_BAD_FS, + N_("module `%s' isn't loaded"), + "zfscrypt"); + else +@@ -1967,7 +1967,7 @@ zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf, + endian)); + return grub_error (GRUB_ERR_BAD_FS, "no key found in keychain"); + } +- grub_dprintf ("zfs", "using key %u (%" PRIxGRUB_UINT64_T ++ grub_dprintf ("zfs", "using key %u (%" PRIxGRUB_UINT64_T + ", %p) for txg %" PRIxGRUB_UINT64_T "\n", + besti, data->subvol.keyring[besti].txg, + data->subvol.keyring[besti].cipher, +@@ -2015,7 +2015,7 @@ zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf, + * + */ + static grub_err_t +-dmu_read (dnode_end_t * dn, grub_uint64_t blkid, void **buf, ++dmu_read (dnode_end_t * dn, grub_uint64_t blkid, void **buf, + grub_zfs_endian_t *endian_out, struct grub_zfs_data *data) + { + int level; +@@ -2045,8 +2045,8 @@ dmu_read (dnode_end_t * dn, grub_uint64_t blkid, void **buf, + + if (BP_IS_HOLE (bp)) + { +- grub_size_t size = grub_zfs_to_cpu16 (dn->dn.dn_datablkszsec, +- dn->endian) ++ grub_size_t size = grub_zfs_to_cpu16 (dn->dn.dn_datablkszsec, ++ dn->endian) + << SPA_MINBLOCKSHIFT; + *buf = grub_malloc (size); + if (!*buf) +@@ -2110,7 +2110,7 @@ mzap_lookup (mzap_phys_t * zapobj, grub_zfs_endian_t endian, + } + + static int +-mzap_iterate (mzap_phys_t * zapobj, grub_zfs_endian_t endian, int objsize, ++mzap_iterate (mzap_phys_t * zapobj, grub_zfs_endian_t endian, int objsize, + int (*hook) (const char *name, grub_uint64_t val, + struct grub_zfs_dir_ctx *ctx), + struct grub_zfs_dir_ctx *ctx) +@@ -2124,7 +2124,7 @@ mzap_iterate (mzap_phys_t * zapobj, grub_zfs_endian_t endian, int objsize, + grub_dprintf ("zfs", "zap: name = %s, value = %llx, cd = %x\n", + mzap_ent[i].mze_name, (long long)mzap_ent[i].mze_value, + (int)mzap_ent[i].mze_cd); +- if (hook (mzap_ent[i].mze_name, ++ if (hook (mzap_ent[i].mze_name, + grub_zfs_to_cpu64 (mzap_ent[i].mze_value, endian), ctx)) + return 1; + } +@@ -2185,12 +2185,12 @@ name_cmp (const char *s1, const char *s2, grub_size_t n, + + if (!case_insensitive) + return grub_memcmp (t1, t2, n); +- ++ + while (n--) + { + if (grub_toupper (*t1) != grub_toupper (*t2)) + return (int) grub_toupper (*t1) - (int) grub_toupper (*t2); +- ++ + t1++; + t2++; + } +@@ -2228,7 +2228,7 @@ zap_leaf_array_equal (zap_leaf_phys_t * l, grub_zfs_endian_t endian, + + /* XXX */ + static grub_err_t +-zap_leaf_array_get (zap_leaf_phys_t * l, grub_zfs_endian_t endian, int blksft, ++zap_leaf_array_get (zap_leaf_phys_t * l, grub_zfs_endian_t endian, int blksft, + int chunk, grub_size_t array_len, char *buf) + { + grub_size_t bseen = 0; +@@ -2292,7 +2292,7 @@ zap_leaf_lookup (zap_leaf_phys_t * l, grub_zfs_endian_t endian, + + grub_dprintf ("zfs", "fzap: length %d\n", (int) le->le_name_length); + +- if (zap_leaf_array_equal (l, endian, blksft, ++ if (zap_leaf_array_equal (l, endian, blksft, + grub_zfs_to_cpu16 (le->le_name_chunk,endian), + grub_zfs_to_cpu16 (le->le_name_length, endian), + name, case_insensitive)) +@@ -2341,7 +2341,7 @@ fzap_lookup (dnode_end_t * zap_dnode, zap_phys_t * zap, + { + void *l; + grub_uint64_t hash, idx, blkid; +- int blksft = zfs_log2 (grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec, ++ int blksft = zfs_log2 (grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec, + zap_dnode->endian) << DNODE_SHIFT); + grub_err_t err; + grub_zfs_endian_t leafendian; +@@ -2354,7 +2354,7 @@ fzap_lookup (dnode_end_t * zap_dnode, zap_phys_t * zap, + + /* get block id from index */ + if (zap->zap_ptrtbl.zt_numblks != 0) +- return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "external pointer tables not supported"); + idx = ZAP_HASH_IDX (hash, zap->zap_ptrtbl.zt_shift); + blkid = grub_zfs_to_cpu64 (((grub_uint64_t *) zap)[idx + (1 << (blksft - 3 - 1))], zap_dnode->endian); +@@ -2386,7 +2386,7 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap, + void *l_in; + grub_uint64_t idx, idx2, blkid; + grub_uint16_t chunk; +- int blksft = zfs_log2 (grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec, ++ int blksft = zfs_log2 (grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec, + zap_dnode->endian) << DNODE_SHIFT); + grub_err_t err; + grub_zfs_endian_t endian; +@@ -2398,7 +2398,7 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap, + /* get block id from index */ + if (zap->zap_ptrtbl.zt_numblks != 0) + { +- grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "external pointer tables not supported"); + return 0; + } +@@ -2542,7 +2542,7 @@ zap_lookup (dnode_end_t * zap_dnode, const char *name, grub_uint64_t *val, + grub_dprintf ("zfs", "micro zap\n"); + err = mzap_lookup (zapbuf, endian, size, name, val, + case_insensitive); +- grub_dprintf ("zfs", "returned %d\n", err); ++ grub_dprintf ("zfs", "returned %d\n", err); + grub_free (zapbuf); + return err; + } +@@ -2552,7 +2552,7 @@ zap_lookup (dnode_end_t * zap_dnode, const char *name, grub_uint64_t *val, + /* this is a fat zap */ + err = fzap_lookup (zap_dnode, zapbuf, name, val, data, + case_insensitive); +- grub_dprintf ("zfs", "returned %d\n", err); ++ grub_dprintf ("zfs", "returned %d\n", err); + grub_free (zapbuf); + return err; + } +@@ -2585,7 +2585,7 @@ zap_iterate_u64_transform (const void *name, + } + + static int +-zap_iterate_u64 (dnode_end_t * zap_dnode, ++zap_iterate_u64 (dnode_end_t * zap_dnode, + int (*hook) (const char *name, grub_uint64_t val, + struct grub_zfs_dir_ctx *ctx), + struct grub_zfs_data *data, struct grub_zfs_dir_ctx *ctx) +@@ -2632,7 +2632,7 @@ zap_iterate_u64 (dnode_end_t * zap_dnode, + } + + static int +-zap_iterate (dnode_end_t * zap_dnode, ++zap_iterate (dnode_end_t * zap_dnode, + grub_size_t nameelemlen, + int (*hook) (const void *name, grub_size_t namelen, + const void *val_in, +@@ -2692,7 +2692,7 @@ dnode_get (dnode_end_t * mdn, grub_uint64_t objnum, grub_uint8_t type, + grub_err_t err; + grub_zfs_endian_t endian; + +- blksz = grub_zfs_to_cpu16 (mdn->dn.dn_datablkszsec, ++ blksz = grub_zfs_to_cpu16 (mdn->dn.dn_datablkszsec, + mdn->endian) << SPA_MINBLOCKSHIFT; + epbs = zfs_log2 (blksz) - DNODE_SHIFT; + +@@ -2703,18 +2703,18 @@ dnode_get (dnode_end_t * mdn, grub_uint64_t objnum, grub_uint8_t type, + blkid = objnum >> epbs; + idx = objnum & ((1 << epbs) - 1); + +- if (data->dnode_buf != NULL && grub_memcmp (data->dnode_mdn, mdn, +- sizeof (*mdn)) == 0 ++ if (data->dnode_buf != NULL && grub_memcmp (data->dnode_mdn, mdn, ++ sizeof (*mdn)) == 0 + && objnum >= data->dnode_start && objnum < data->dnode_end) + { + grub_memmove (&(buf->dn), &(data->dnode_buf)[idx], DNODE_SIZE); + buf->endian = data->dnode_endian; +- if (type && buf->dn.dn_type != type) +- return grub_error(GRUB_ERR_BAD_FS, "incorrect dnode type"); ++ if (type && buf->dn.dn_type != type) ++ return grub_error(GRUB_ERR_BAD_FS, "incorrect dnode type"); + return GRUB_ERR_NONE; + } + +- grub_dprintf ("zfs", "endian = %d, blkid=%llx\n", mdn->endian, ++ grub_dprintf ("zfs", "endian = %d, blkid=%llx\n", mdn->endian, + (unsigned long long) blkid); + err = dmu_read (mdn, blkid, &dnbuf, &endian, data); + if (err) +@@ -2740,8 +2740,8 @@ dnode_get (dnode_end_t * mdn, grub_uint64_t objnum, grub_uint8_t type, + + grub_memmove (&(buf->dn), (dnode_phys_t *) dnbuf + idx, DNODE_SIZE); + buf->endian = endian; +- if (type && buf->dn.dn_type != type) +- return grub_error(GRUB_ERR_BAD_FS, "incorrect dnode type"); ++ if (type && buf->dn.dn_type != type) ++ return grub_error(GRUB_ERR_BAD_FS, "incorrect dnode type"); + + return GRUB_ERR_NONE; + } +@@ -2765,7 +2765,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + struct dnode_chain + { + struct dnode_chain *next; +- dnode_end_t dn; ++ dnode_end_t dn; + }; + struct dnode_chain *dnode_path = 0, *dn_new, *root; + +@@ -2775,7 +2775,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + dn_new->next = 0; + dnode_path = root = dn_new; + +- err = dnode_get (&subvol->mdn, MASTER_NODE_OBJ, DMU_OT_MASTER_NODE, ++ err = dnode_get (&subvol->mdn, MASTER_NODE_OBJ, DMU_OT_MASTER_NODE, + &(dnode_path->dn), data); + if (err) + { +@@ -2826,7 +2826,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + grub_free (dn_new); + return grub_errno; + } +- ++ + while (1) + { + /* skip leading slashes */ +@@ -2852,7 +2852,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + } + else + { +- err = grub_error (GRUB_ERR_FILE_NOT_FOUND, ++ err = grub_error (GRUB_ERR_FILE_NOT_FOUND, + "can't resolve .."); + break; + } +@@ -2903,7 +2903,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + { + grub_size_t block; + grub_size_t blksz; +- blksz = (grub_zfs_to_cpu16 (dnode_path->dn.dn.dn_datablkszsec, ++ blksz = (grub_zfs_to_cpu16 (dnode_path->dn.dn.dn_datablkszsec, + dnode_path->dn.endian) + << SPA_MINBLOCKSHIFT); + +@@ -2942,7 +2942,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + if (err) + break; + free_symval = 1; +- } ++ } + + if (grub_add (sym_sz, grub_strlen (oldpath), &sz) || + grub_add (sz, 1, &sz)) +@@ -2967,9 +2967,9 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + if (free_symval) + grub_free (sym_value); + path [sym_sz] = 0; +- grub_memcpy (path + grub_strlen (path), oldpath, ++ grub_memcpy (path + grub_strlen (path), oldpath, + grub_strlen (oldpath) + 1); +- ++ + grub_free (oldpathbuf); + if (path[0] != '/') + { +@@ -2989,7 +2989,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + void *sahdrp; + int hdrsize; + grub_size_t sz; +- ++ + if (dnode_path->dn.dn.dn_bonuslen != 0) + { + sahdrp = DN_BONUS (&dnode_path->dn.dn); +@@ -2997,7 +2997,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + else if (dnode_path->dn.dn.dn_flags & DNODE_FLAG_SPILL_BLKPTR) + { + blkptr_t *bp = &dnode_path->dn.dn.dn_spill; +- ++ + err = zio_read (bp, dnode_path->dn.endian, &sahdrp, NULL, data); + if (err) + break; +@@ -3016,7 +3016,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + dnode_path->dn.endian) >> 12) & 0xf) == 0xa) + { + char *sym_value = (char *) sahdrp + hdrsize + SA_SYMLINK_OFFSET; +- grub_size_t sym_sz = ++ grub_size_t sym_sz = + grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp + + hdrsize + + SA_SIZE_OFFSET), +@@ -3039,9 +3039,9 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + } + grub_memcpy (path, sym_value, sym_sz); + path [sym_sz] = 0; +- grub_memcpy (path + grub_strlen (path), oldpath, ++ grub_memcpy (path + grub_strlen (path), oldpath, + grub_strlen (oldpath) + 1); +- ++ + grub_free (oldpathbuf); + if (path[0] != '/') + { +@@ -3142,7 +3142,7 @@ get_filesystem_dnode (dnode_end_t * mosmdn, char *fsname, + + grub_dprintf ("zfs", "endian = %d\n", mosmdn->endian); + +- err = dnode_get (mosmdn, DMU_POOL_DIRECTORY_OBJECT, ++ err = dnode_get (mosmdn, DMU_POOL_DIRECTORY_OBJECT, + DMU_OT_OBJECT_DIRECTORY, mdn, data); + if (err) + return err; +@@ -3165,7 +3165,7 @@ get_filesystem_dnode (dnode_end_t * mosmdn, char *fsname, + { + grub_uint64_t childobj; + char *cname, ch; +- ++ + while (*fsname == '/') + fsname++; + +@@ -3327,7 +3327,7 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol, + filename = ptr_slash; + else + filename = "/"; +- grub_dprintf ("zfs", "fsname = '%s' snapname='%s' filename = '%s'\n", ++ grub_dprintf ("zfs", "fsname = '%s' snapname='%s' filename = '%s'\n", + fsname, snapname, filename); + } + grub_dprintf ("zfs", "alive\n"); +@@ -3413,7 +3413,7 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol, + + snapobj = grub_zfs_to_cpu64 (((dsl_dataset_phys_t *) DN_BONUS (&subvol->mdn.dn))->ds_snapnames_zapobj, subvol->mdn.endian); + +- err = dnode_get (&(data->mos), snapobj, ++ err = dnode_get (&(data->mos), snapobj, + DMU_OT_DSL_DS_SNAP_MAP, &subvol->mdn, data); + if (!err) + err = zap_lookup (&subvol->mdn, snapname, &headobj, data, 0); +@@ -3431,13 +3431,13 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol, + subvol->obj = headobj; + + make_mdn (&subvol->mdn, data); +- ++ + grub_dprintf ("zfs", "endian = %d\n", subvol->mdn.endian); + + if (*isfs) + { + grub_free (fsname); +- grub_free (snapname); ++ grub_free (snapname); + return GRUB_ERR_NONE; + } + err = dnode_get_path (subvol, filename, dn, data); +@@ -3457,9 +3457,9 @@ nvlist_find_value (const char *nvlist_in, const char *name, + char *nvp_name; + + /* Verify if the 1st and 2nd byte in the nvlist are valid. */ +- /* NOTE: independently of what endianness header announces all ++ /* NOTE: independently of what endianness header announces all + subsequent values are big-endian. */ +- if (nvlist[0] != NV_ENCODE_XDR || (nvlist[1] != NV_LITTLE_ENDIAN ++ if (nvlist[0] != NV_ENCODE_XDR || (nvlist[1] != NV_LITTLE_ENDIAN + && nvlist[1] != NV_BIG_ENDIAN)) + { + grub_dprintf ("zfs", "incorrect nvlist header\n"); +@@ -3580,13 +3580,13 @@ get_nvlist_size (const char *beg, const char *limit) + { + const char *ptr; + grub_uint32_t encode_size; +- ++ + ptr = beg + 8; + + while (ptr < limit + && (encode_size = grub_be_to_cpu32 (grub_get_unaligned32 (ptr)))) + ptr += encode_size; /* goto the next nvpair */ +- ptr += 8; ++ ptr += 8; + return (ptr > limit) ? -1 : (ptr - beg); + } + +@@ -3733,8 +3733,8 @@ zfs_mount (grub_device_t dev) + } + + ub = &(data->current_uberblock); +- ub_endian = (grub_zfs_to_cpu64 (ub->ub_magic, +- GRUB_ZFS_LITTLE_ENDIAN) == UBERBLOCK_MAGIC ++ ub_endian = (grub_zfs_to_cpu64 (ub->ub_magic, ++ GRUB_ZFS_LITTLE_ENDIAN) == UBERBLOCK_MAGIC + ? GRUB_ZFS_LITTLE_ENDIAN : GRUB_ZFS_BIG_ENDIAN); + + err = zio_read (&ub->ub_rootbp, ub_endian, +@@ -3787,7 +3787,7 @@ grub_zfs_fetch_nvlist (grub_device_t dev, char **nvlist) + return err; + } + +-static grub_err_t ++static grub_err_t + zfs_label (grub_device_t device, char **label) + { + char *nvlist; +@@ -3799,7 +3799,7 @@ zfs_label (grub_device_t device, char **label) + return grub_errno; + + err = zfs_fetch_nvlist (data->device_original, &nvlist); +- if (err) ++ if (err) + { + zfs_unmount (data); + return err; +@@ -3811,7 +3811,7 @@ zfs_label (grub_device_t device, char **label) + return grub_errno; + } + +-static grub_err_t ++static grub_err_t + zfs_uuid (grub_device_t device, char **uuid) + { + struct grub_zfs_data *data; +@@ -3829,7 +3829,7 @@ zfs_uuid (grub_device_t device, char **uuid) + return GRUB_ERR_NONE; + } + +-static grub_err_t ++static grub_err_t + zfs_mtime (grub_device_t device, grub_int64_t *mt) + { + struct grub_zfs_data *data; +@@ -3843,8 +3843,8 @@ zfs_mtime (grub_device_t device, grub_int64_t *mt) + return grub_errno; + + ub = &(data->current_uberblock); +- ub_endian = (grub_zfs_to_cpu64 (ub->ub_magic, +- GRUB_ZFS_LITTLE_ENDIAN) == UBERBLOCK_MAGIC ++ ub_endian = (grub_zfs_to_cpu64 (ub->ub_magic, ++ GRUB_ZFS_LITTLE_ENDIAN) == UBERBLOCK_MAGIC + ? GRUB_ZFS_LITTLE_ENDIAN : GRUB_ZFS_BIG_ENDIAN); + + *mt = grub_zfs_to_cpu64 (ub->ub_timestamp, ub_endian); +@@ -3882,7 +3882,7 @@ grub_zfs_open (struct grub_file *file, const char *fsfilename) + } + + /* We found the dnode for this file. Verify if it is a plain file. */ +- if (data->dnode.dn.dn_type != DMU_OT_PLAIN_FILE_CONTENTS) ++ if (data->dnode.dn.dn_type != DMU_OT_PLAIN_FILE_CONTENTS) + { + zfs_unmount (data); + return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a regular file")); +@@ -3957,7 +3957,7 @@ grub_zfs_read (grub_file_t file, char *buf, grub_size_t len) + return len; + } + +- blksz = grub_zfs_to_cpu16 (data->dnode.dn.dn_datablkszsec, ++ blksz = grub_zfs_to_cpu16 (data->dnode.dn.dn_datablkszsec, + data->dnode.endian) << SPA_MINBLOCKSHIFT; + + if (blksz == 0) +@@ -4050,11 +4050,11 @@ fill_fs_info (struct grub_dirhook_info *info, + dnode_end_t dn; + grub_uint64_t objnum; + grub_uint64_t headobj; +- ++ + grub_memset (info, 0, sizeof (*info)); +- ++ + info->dir = 1; +- ++ + if (mdn.dn.dn_type == DMU_OT_DSL_DIR) + { + headobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&mdn.dn))->dd_head_dataset_obj, mdn.endian); +@@ -4069,28 +4069,28 @@ fill_fs_info (struct grub_dirhook_info *info, + err = make_mdn (&mdn, data); + if (err) + return err; +- err = dnode_get (&mdn, MASTER_NODE_OBJ, DMU_OT_MASTER_NODE, ++ err = dnode_get (&mdn, MASTER_NODE_OBJ, DMU_OT_MASTER_NODE, + &dn, data); + if (err) + { + grub_dprintf ("zfs", "failed here\n"); + return err; + } +- ++ + err = zap_lookup (&dn, ZFS_ROOT_OBJ, &objnum, data, 0); + if (err) + { + grub_dprintf ("zfs", "failed here\n"); + return err; + } +- ++ + err = dnode_get (&mdn, objnum, 0, &dn, data); + if (err) + { + grub_dprintf ("zfs", "failed here\n"); + return err; + } +- ++ + if (dn.dn.dn_bonustype == DMU_OT_SA) + { + void *sahdrp; +@@ -4176,15 +4176,15 @@ iterate_zap (const char *name, grub_uint64_t val, struct grub_zfs_dir_ctx *ctx) + info.mtime = grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp + hdrsize + SA_MTIME_OFFSET), dn.endian); + info.case_insensitive = ctx->data->subvol.case_insensitive; + } +- ++ + if (dn.dn.dn_bonustype == DMU_OT_ZNODE) +- { ++ { + info.mtimeset = 1; + info.mtime = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dn.dn))->zp_mtime[0], + dn.endian); + } + info.dir = (dn.dn.dn_type == DMU_OT_DIRECTORY_CONTENTS); +- grub_dprintf ("zfs", "type=%d, name=%s\n", ++ grub_dprintf ("zfs", "type=%d, name=%s\n", + (int)dn.dn.dn_type, (char *)name); + return ctx->hook (name, &info, ctx->hook_data); + } +@@ -4285,7 +4285,7 @@ grub_zfs_dir (grub_device_t device, const char *path, + + if (isfs) + { +- grub_uint64_t childobj, headobj; ++ grub_uint64_t childobj, headobj; + grub_uint64_t snapobj; + dnode_end_t dn; + struct grub_dirhook_info info; +@@ -4313,7 +4313,7 @@ grub_zfs_dir (grub_device_t device, const char *path, + } + + zap_iterate_u64 (&dn, iterate_zap_fs, data, &ctx); +- ++ + err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, &dn, data); + if (err) + { +@@ -4355,8 +4355,8 @@ check_feature (const char *name, grub_uint64_t val, + return 0; + if (name[0] == 0) + return 0; +- for (i = 0; spa_feature_names[i] != NULL; i++) +- if (grub_strcmp (name, spa_feature_names[i]) == 0) ++ for (i = 0; spa_feature_names[i] != NULL; i++) ++ if (grub_strcmp (name, spa_feature_names[i]) == 0) + return 0; + return 1; + } +@@ -4369,7 +4369,7 @@ check_feature (const char *name, grub_uint64_t val, + * 0: Success. + * errnum: Failure. + */ +- ++ + static grub_err_t + check_mos_features(dnode_phys_t *mosmdn_phys,grub_zfs_endian_t endian,struct grub_zfs_data* data ) + { +@@ -4394,7 +4394,7 @@ check_mos_features(dnode_phys_t *mosmdn_phys,grub_zfs_endian_t endian,struct gru + errnum = zap_lookup(&dn, DMU_POOL_FEATURES_FOR_READ, &objnum, data,0); + if (errnum != 0) + return errnum; +- ++ + errnum = dnode_get(&mosmdn, objnum, DMU_OTN_ZAP_METADATA, &dn, data); + if (errnum != 0) + return errnum; +diff --git a/grub-core/fs/zfs/zfs_fletcher.c b/grub-core/fs/zfs/zfs_fletcher.c +index 7d27b053dc7a..ad3be6705479 100644 +--- a/grub-core/fs/zfs/zfs_fletcher.c ++++ b/grub-core/fs/zfs/zfs_fletcher.c +@@ -39,14 +39,14 @@ + #include + + void +-fletcher_2(const void *buf, grub_uint64_t size, grub_zfs_endian_t endian, ++fletcher_2(const void *buf, grub_uint64_t size, grub_zfs_endian_t endian, + zio_cksum_t *zcp) + { + const grub_uint64_t *ip = buf; + const grub_uint64_t *ipend = ip + (size / sizeof (grub_uint64_t)); + grub_uint64_t a0, b0, a1, b1; +- +- for (a0 = b0 = a1 = b1 = 0; ip < ipend; ip += 2) ++ ++ for (a0 = b0 = a1 = b1 = 0; ip < ipend; ip += 2) + { + a0 += grub_zfs_to_cpu64 (ip[0], endian); + a1 += grub_zfs_to_cpu64 (ip[1], endian); +@@ -61,14 +61,14 @@ fletcher_2(const void *buf, grub_uint64_t size, grub_zfs_endian_t endian, + } + + void +-fletcher_4 (const void *buf, grub_uint64_t size, grub_zfs_endian_t endian, ++fletcher_4 (const void *buf, grub_uint64_t size, grub_zfs_endian_t endian, + zio_cksum_t *zcp) + { + const grub_uint32_t *ip = buf; + const grub_uint32_t *ipend = ip + (size / sizeof (grub_uint32_t)); + grub_uint64_t a, b, c, d; +- +- for (a = b = c = d = 0; ip < ipend; ip++) ++ ++ for (a = b = c = d = 0; ip < ipend; ip++) + { + a += grub_zfs_to_cpu32 (ip[0], endian);; + b += a; +diff --git a/grub-core/fs/zfs/zfs_sha256.c b/grub-core/fs/zfs/zfs_sha256.c +index a181f076c54c..f042fa61ab89 100644 +--- a/grub-core/fs/zfs/zfs_sha256.c ++++ b/grub-core/fs/zfs/zfs_sha256.c +@@ -116,23 +116,23 @@ zio_checksum_SHA256(const void *buf, grub_uint64_t size, + grub_uint8_t pad[128]; + unsigned padsize = size & 63; + unsigned i; +- ++ + for (i = 0; i < size - padsize; i += 64) + SHA256Transform(H, (grub_uint8_t *)buf + i); +- ++ + for (i = 0; i < padsize; i++) + pad[i] = ((grub_uint8_t *)buf)[i]; +- ++ + for (pad[padsize++] = 0x80; (padsize & 63) != 56; padsize++) + pad[padsize] = 0; +- ++ + for (i = 0; i < 8; i++) + pad[padsize++] = (size << 3) >> (56 - 8 * i); +- ++ + for (i = 0; i < padsize && i <= 64; i += 64) + SHA256Transform(H, pad + i); +- +- zcp->zc_word[0] = grub_cpu_to_zfs64 ((grub_uint64_t)H[0] << 32 | H[1], ++ ++ zcp->zc_word[0] = grub_cpu_to_zfs64 ((grub_uint64_t)H[0] << 32 | H[1], + endian); + zcp->zc_word[1] = grub_cpu_to_zfs64 ((grub_uint64_t)H[2] << 32 | H[3], + endian); +diff --git a/grub-core/fs/zfs/zfscrypt.c b/grub-core/fs/zfs/zfscrypt.c +index de3b015f5827..da30e9ab33dd 100644 +--- a/grub-core/fs/zfs/zfscrypt.c ++++ b/grub-core/fs/zfs/zfscrypt.c +@@ -46,7 +46,7 @@ + GRUB_MOD_LICENSE ("GPLv3+"); + + /* +- Mostly based on following article: ++ Mostly based on following article: + https://blogs.oracle.com/darren/entry/zfs_encryption_what_is_on + */ + +@@ -179,7 +179,7 @@ grub_gcm_mul (grub_uint8_t *a, const grub_uint8_t *b) + grub_crypto_xor (res, res, bs, 16); + grub_gcm_mul_x (bs); + } +- ++ + grub_memcpy (a, res, 16); + } + +@@ -275,7 +275,7 @@ algo_decrypt (grub_crypto_cipher_handle_t cipher, grub_uint64_t algo, + } + + static grub_err_t +-grub_zfs_decrypt_real (grub_crypto_cipher_handle_t cipher, ++grub_zfs_decrypt_real (grub_crypto_cipher_handle_t cipher, + grub_uint64_t algo, + void *nonce, + char *buf, grub_size_t size, +@@ -286,7 +286,7 @@ grub_zfs_decrypt_real (grub_crypto_cipher_handle_t cipher, + unsigned i; + grub_uint32_t sw[4]; + gcry_err_code_t err; +- ++ + grub_memcpy (sw, nonce, 16); + if (endian != GRUB_ZFS_BIG_ENDIAN) + for (i = 0; i < 4; i++) +@@ -302,7 +302,7 @@ grub_zfs_decrypt_real (grub_crypto_cipher_handle_t cipher, + sw + 1, 3, 12); + if (err) + return grub_crypto_gcry_error (err); +- ++ + for (i = 0; i < 3; i++) + if (grub_zfs_to_cpu32 (expected_mac[i], endian) + != grub_be_to_cpu32 (mac[i])) +@@ -362,7 +362,7 @@ grub_zfs_load_key_real (const struct grub_zfs_key *key, + grub_crypto_cipher_close (cipher); + continue; + } +- ++ + err = grub_crypto_cipher_set_key (cipher, wrap_key_real, + keylen); + if (err) +@@ -371,7 +371,7 @@ grub_zfs_load_key_real (const struct grub_zfs_key *key, + grub_crypto_cipher_close (cipher); + continue; + } +- ++ + err = algo_decrypt (cipher, algo, decrypted, key->unknown_purpose_key, 32, + mac, key->unknown_purpose_nonce, 2, 16); + if (err || (grub_crypto_memcmp (mac, key->unknown_purpose_key + 32, 16) +-- +2.46.1 + diff --git a/SOURCES/0459-fs-xfs-Fix-memory-leaks-in-XFS-module.patch b/SOURCES/0459-fs-xfs-Fix-memory-leaks-in-XFS-module.patch new file mode 100644 index 0000000..5ddda66 --- /dev/null +++ b/SOURCES/0459-fs-xfs-Fix-memory-leaks-in-XFS-module.patch @@ -0,0 +1,50 @@ +From 1ff9d36ec874d5702be3815e74a71db7764c56ee Mon Sep 17 00:00:00 2001 +From: "t.feng" +Date: Tue, 29 Nov 2022 17:14:15 +0800 +Subject: [PATCH 459/464] fs/xfs: Fix memory leaks in XFS module + +Signed-off-by: t.feng +Reviewed-by: Daniel Kiper +--- + grub-core/fs/xfs.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c +index 17bf01f31ddb..8cf41d07c2ee 100644 +--- a/grub-core/fs/xfs.c ++++ b/grub-core/fs/xfs.c +@@ -599,7 +599,10 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) + if (grub_disk_read (node->data->disk, + GRUB_XFS_FSB_TO_BLOCK (node->data, get_fsb (keys, i - 1 + recoffset)) << (node->data->sblock.log2_bsize - GRUB_DISK_SECTOR_BITS), + 0, node->data->bsize, leaf)) +- return 0; ++ { ++ grub_free (leaf); ++ return 0; ++ } + + if ((!node->data->hascrc && + grub_strncmp ((char *) leaf->magic, "BMAP", 4)) || +@@ -790,6 +793,7 @@ static int iterate_dir_call_hook (grub_uint64_t ino, const char *filename, + if (err) + { + grub_print_error (); ++ grub_free (fdiro); + return 0; + } + +@@ -907,7 +911,10 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + blk << dirblk_log2, + dirblk_size, dirblock, 0); + if (numread != dirblk_size) +- return 0; ++ { ++ grub_free (dirblock); ++ return 0; ++ } + + entries = (grub_be_to_cpu32 (tail->leaf_count) + - grub_be_to_cpu32 (tail->leaf_stale)); +-- +2.46.1 + diff --git a/SOURCES/0460-fs-xfs-Incorrect-short-form-directory-data-boundary-.patch b/SOURCES/0460-fs-xfs-Incorrect-short-form-directory-data-boundary-.patch new file mode 100644 index 0000000..d69e977 --- /dev/null +++ b/SOURCES/0460-fs-xfs-Incorrect-short-form-directory-data-boundary-.patch @@ -0,0 +1,51 @@ +From 270099a784d7dc0d251a8be1fed57e55f4dd4f8f Mon Sep 17 00:00:00 2001 +From: Lidong Chen +Date: Thu, 28 Sep 2023 22:33:44 +0000 +Subject: [PATCH 460/464] fs/xfs: Incorrect short form directory data boundary + check + +After parsing of the current entry, the entry pointer is advanced +to the next entry at the end of the "for" loop. In case where the +last entry is at the end of the data boundary, the advanced entry +pointer can point off the data boundary. The subsequent boundary +check for the advanced entry pointer can cause a failure. + +The fix is to include the boundary check into the "for" loop +condition. + +Signed-off-by: Lidong Chen +Reviewed-by: Daniel Kiper +Tested-by: Sebastian Andrzej Siewior +Tested-by: Marta Lewandowska +--- + grub-core/fs/xfs.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c +index 8cf41d07c2ee..a779eb6b8334 100644 +--- a/grub-core/fs/xfs.c ++++ b/grub-core/fs/xfs.c +@@ -836,7 +836,8 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + if (iterate_dir_call_hook (parent, "..", &ctx)) + return 1; + +- for (i = 0; i < head->count; i++) ++ for (i = 0; i < head->count && ++ (grub_uint8_t *) de < ((grub_uint8_t *) dir + grub_xfs_fshelp_size (dir->data)); i++) + { + grub_uint64_t ino; + grub_uint8_t *inopos = grub_xfs_inline_de_inopos(dir->data, de); +@@ -871,10 +872,6 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + de->name[de->len] = c; + + de = grub_xfs_inline_next_de(dir->data, head, de); +- +- if ((grub_uint8_t *) de >= (grub_uint8_t *) dir + grub_xfs_fshelp_size (dir->data)) +- return grub_error (GRUB_ERR_BAD_FS, "invalid XFS directory entry"); +- + } + break; + } +-- +2.46.1 + diff --git a/SOURCES/0461-fs-xfs-Fix-XFS-directory-extent-parsing.patch b/SOURCES/0461-fs-xfs-Fix-XFS-directory-extent-parsing.patch new file mode 100644 index 0000000..17bd068 --- /dev/null +++ b/SOURCES/0461-fs-xfs-Fix-XFS-directory-extent-parsing.patch @@ -0,0 +1,171 @@ +From e5d18ae1b2b0ff58ce720dad90b3539aa2f28ee1 Mon Sep 17 00:00:00 2001 +From: Jon DeVree +Date: Tue, 17 Oct 2023 23:03:47 -0400 +Subject: [PATCH 461/464] fs/xfs: Fix XFS directory extent parsing + +The XFS directory entry parsing code has never been completely correct +for extent based directories. The parser correctly handles the case +where the directory is contained in a single extent, but then mistakenly +assumes the data blocks for the multiple extent case are each identical +to the single extent case. The difference in the format of the data +blocks between the two cases is tiny enough that its gone unnoticed for +a very long time. + +A recent change introduced some additional bounds checking into the XFS +parser. Like GRUB's existing parser, it is correct for the single extent +case but incorrect for the multiple extent case. When parsing a directory +with multiple extents, this new bounds checking is sometimes (but not +always) tripped and triggers an "invalid XFS directory entry" error. This +probably would have continued to go unnoticed but the /boot/grub/ +directory is large enough that it often has multiple extents. + +The difference between the two cases is that when there are multiple +extents, the data blocks do not contain a trailer nor do they contain +any leaf information. That information is stored in a separate set of +extents dedicated to just the leaf information. These extents come after +the directory entry extents and are not included in the inode size. So +the existing parser already ignores the leaf extents. + +The only reason to read the trailer/leaf information at all is so that +the parser can avoid misinterpreting that data as directory entries. So +this updates the parser as follows: + +For the single extent case the parser doesn't change much: +1. Read the size of the leaf information from the trailer +2. Set the end pointer for the parser to the start of the leaf + information. (The previous bounds checking set the end pointer to the + start of the trailer, so this is actually a small improvement.) +3. Set the entries variable to the expected number of directory entries. + +For the multiple extent case: +1. Set the end pointer to the end of the block. +2. Do not set up the entries variable. Figuring out how many entries are + in each individual block is complex and does not seem worth it when + it appears to be safe to just iterate over the entire block. + +The bounds check itself was also dependent upon the faulty XFS parser +because it accidentally used "filename + length - 1". Presumably this +was able to pass the fuzzer because in the old parser there was always +8 bytes of slack space between the tail pointer and the actual end of +the block. Since this is no longer the case the bounds check needs to be +updated to "filename + length + 1" in order to prevent a regression in +the handling of corrupt fliesystems. + +Notes: +* When there is only one extent there will only ever be one block. If + more than one block is required then XFS will always switch to holding + leaf information in a separate extent. +* B-tree based directories seems to be parsed properly by the same code + that handles multiple extents. This is unlikely to ever occur within + /boot though because its only used when there are an extremely large + number of directory entries. + +Fixes: ef7850c75 (fs/xfs: Fix issues found while fuzzing the XFS filesystem) +Fixes: b2499b29c (Adds support for the XFS filesystem.) +Fixes: https://savannah.gnu.org/bugs/?64376 + +Signed-off-by: Jon DeVree +Reviewed-by: Daniel Kiper +Tested-by: Sebastian Andrzej Siewior +Tested-by: Marta Lewandowska +--- + grub-core/fs/xfs.c | 52 +++++++++++++++++++++++++++++++++------------- + 1 file changed, 38 insertions(+), 14 deletions(-) + +diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c +index a779eb6b8334..e178ffcdc290 100644 +--- a/grub-core/fs/xfs.c ++++ b/grub-core/fs/xfs.c +@@ -223,6 +223,12 @@ struct grub_xfs_inode + /* Size of struct grub_xfs_inode v2, up to unused4 member included. */ + #define XFS_V2_INODE_SIZE (XFS_V3_INODE_SIZE - 76) + ++struct grub_xfs_dir_leaf_entry ++{ ++ grub_uint32_t hashval; ++ grub_uint32_t address; ++} GRUB_PACKED; ++ + struct grub_xfs_dirblock_tail + { + grub_uint32_t leaf_count; +@@ -900,9 +906,8 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + { + struct grub_xfs_dir2_entry *direntry = + grub_xfs_first_de(dir->data, dirblock); +- int entries; +- struct grub_xfs_dirblock_tail *tail = +- grub_xfs_dir_tail(dir->data, dirblock); ++ int entries = -1; ++ char *end = dirblock + dirblk_size; + + numread = grub_xfs_read_file (dir, 0, 0, + blk << dirblk_log2, +@@ -913,14 +918,27 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + return 0; + } + +- entries = (grub_be_to_cpu32 (tail->leaf_count) +- - grub_be_to_cpu32 (tail->leaf_stale)); ++ /* ++ * Leaf and tail information are only in the data block if the number ++ * of extents is 1. ++ */ ++ if (dir->inode.nextents == grub_cpu_to_be32_compile_time (1)) ++ { ++ struct grub_xfs_dirblock_tail *tail = grub_xfs_dir_tail (dir->data, dirblock); ++ ++ end = (char *) tail; ++ ++ /* Subtract the space used by leaf nodes. */ ++ end -= grub_be_to_cpu32 (tail->leaf_count) * sizeof (struct grub_xfs_dir_leaf_entry); + +- if (!entries) +- continue; ++ entries = grub_be_to_cpu32 (tail->leaf_count) - grub_be_to_cpu32 (tail->leaf_stale); ++ ++ if (!entries) ++ continue; ++ } + + /* Iterate over all entries within this block. */ +- while ((char *)direntry < (char *)tail) ++ while ((char *) direntry < (char *) end) + { + grub_uint8_t *freetag; + char *filename; +@@ -940,7 +958,7 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + } + + filename = (char *)(direntry + 1); +- if (filename + direntry->len - 1 > (char *) tail) ++ if (filename + direntry->len + 1 > (char *) end) + return grub_error (GRUB_ERR_BAD_FS, "invalid XFS directory entry"); + + /* The byte after the filename is for the filetype, padding, or +@@ -954,11 +972,17 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + return 1; + } + +- /* Check if last direntry in this block is +- reached. */ +- entries--; +- if (!entries) +- break; ++ /* ++ * The expected number of directory entries is only tracked for the ++ * single extent case. ++ */ ++ if (dir->inode.nextents == grub_cpu_to_be32_compile_time (1)) ++ { ++ /* Check if last direntry in this block is reached. */ ++ entries--; ++ if (!entries) ++ break; ++ } + + /* Select the next directory entry. */ + direntry = grub_xfs_next_de(dir->data, direntry); +-- +2.46.1 + diff --git a/SOURCES/0462-fs-xfs-Add-large-extent-counters-incompat-feature-su.patch b/SOURCES/0462-fs-xfs-Add-large-extent-counters-incompat-feature-su.patch new file mode 100644 index 0000000..6e96fc4 --- /dev/null +++ b/SOURCES/0462-fs-xfs-Add-large-extent-counters-incompat-feature-su.patch @@ -0,0 +1,119 @@ +From 16ff7f17e65503ed53758ccc0245c1fabd444fb2 Mon Sep 17 00:00:00 2001 +From: Anthony Iliopoulos +Date: Thu, 26 Oct 2023 11:53:39 +0200 +Subject: [PATCH 462/464] fs/xfs: Add large extent counters incompat feature + support + +XFS introduced 64-bit extent counters for inodes via a series of +upstream commits and the feature was marked as stable in v6.5 via +commit 61d7e8274cd8 (xfs: drop EXPERIMENTAL tag for large extent +counts). + +Further, xfsprogs release v6.5.0 switched this feature on by default +in mkfs.xfs via commit e5b18d7d1d96 (mkfs: enable large extent counts +by default). + +Filesystems formatted with large extent count support, nrext64=1, are +thus currently not recognizable by GRUB, since this is an incompat +feature. Add the required support so that those filesystems and inodes +with large extent counters can be read by GRUB. + +Signed-off-by: Anthony Iliopoulos +Reviewed-by: Andrey Albershteyn +Reviewed-by: Daniel Kiper +Tested-by: Marta Lewandowska +Tested-by: Sebastian Andrzej Siewior +--- + grub-core/fs/xfs.c | 30 +++++++++++++++++++++++++----- + 1 file changed, 25 insertions(+), 5 deletions(-) + +diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c +index e178ffcdc290..70c9f449b133 100644 +--- a/grub-core/fs/xfs.c ++++ b/grub-core/fs/xfs.c +@@ -79,6 +79,8 @@ GRUB_MOD_LICENSE ("GPLv3+"); + /* Inode flags2 flags */ + #define XFS_DIFLAG2_BIGTIME_BIT 3 + #define XFS_DIFLAG2_BIGTIME (1 << XFS_DIFLAG2_BIGTIME_BIT) ++#define XFS_DIFLAG2_NREXT64_BIT 4 ++#define XFS_DIFLAG2_NREXT64 (1 << XFS_DIFLAG2_NREXT64_BIT) + + /* incompat feature flags */ + #define XFS_SB_FEAT_INCOMPAT_FTYPE (1 << 0) /* filetype in dirent */ +@@ -86,6 +88,7 @@ GRUB_MOD_LICENSE ("GPLv3+"); + #define XFS_SB_FEAT_INCOMPAT_META_UUID (1 << 2) /* metadata UUID */ + #define XFS_SB_FEAT_INCOMPAT_BIGTIME (1 << 3) /* large timestamps */ + #define XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR (1 << 4) /* needs xfs_repair */ ++#define XFS_SB_FEAT_INCOMPAT_NREXT64 (1 << 5) /* large extent counters */ + + /* + * Directory entries with ftype are explicitly handled by GRUB code. +@@ -101,7 +104,8 @@ GRUB_MOD_LICENSE ("GPLv3+"); + XFS_SB_FEAT_INCOMPAT_SPINODES | \ + XFS_SB_FEAT_INCOMPAT_META_UUID | \ + XFS_SB_FEAT_INCOMPAT_BIGTIME | \ +- XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR) ++ XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR | \ ++ XFS_SB_FEAT_INCOMPAT_NREXT64) + + struct grub_xfs_sblock + { +@@ -203,7 +207,8 @@ struct grub_xfs_inode + grub_uint16_t mode; + grub_uint8_t version; + grub_uint8_t format; +- grub_uint8_t unused2[26]; ++ grub_uint8_t unused2[18]; ++ grub_uint64_t nextents_big; + grub_uint64_t atime; + grub_uint64_t mtime; + grub_uint64_t ctime; +@@ -547,11 +552,26 @@ get_fsb (const void *keys, int idx) + return grub_be_to_cpu64 (grub_get_unaligned64 (p)); + } + ++static int ++grub_xfs_inode_has_large_extent_counts (const struct grub_xfs_inode *inode) ++{ ++ return inode->version >= 3 && ++ (inode->flags2 & grub_cpu_to_be64_compile_time (XFS_DIFLAG2_NREXT64)); ++} ++ ++static grub_uint64_t ++grub_xfs_get_inode_nextents (struct grub_xfs_inode *inode) ++{ ++ return (grub_xfs_inode_has_large_extent_counts (inode)) ? ++ grub_be_to_cpu64 (inode->nextents_big) : ++ grub_be_to_cpu32 (inode->nextents); ++} ++ + static grub_disk_addr_t + grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) + { + struct grub_xfs_btree_node *leaf = 0; +- int ex, nrec; ++ grub_uint64_t ex, nrec; + struct grub_xfs_extent *exts; + grub_uint64_t ret = 0; + +@@ -576,7 +596,7 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) + / (2 * sizeof (grub_uint64_t)); + do + { +- int i; ++ grub_uint64_t i; + grub_addr_t keys_end, data_end; + + if (grub_mul (sizeof (grub_uint64_t), nrec, &keys_end) || +@@ -634,7 +654,7 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) + grub_addr_t exts_end = 0; + grub_addr_t data_end = 0; + +- nrec = grub_be_to_cpu32 (node->inode.nextents); ++ nrec = grub_xfs_get_inode_nextents (&node->inode); + exts = (struct grub_xfs_extent *) grub_xfs_inode_data(&node->inode); + + if (grub_mul (sizeof (struct grub_xfs_extent), nrec, &exts_end) || +-- +2.46.1 + diff --git a/SOURCES/0463-fs-xfs-Handle-non-continuous-data-blocks-in-director.patch b/SOURCES/0463-fs-xfs-Handle-non-continuous-data-blocks-in-director.patch new file mode 100644 index 0000000..dcbdc8a --- /dev/null +++ b/SOURCES/0463-fs-xfs-Handle-non-continuous-data-blocks-in-director.patch @@ -0,0 +1,57 @@ +From 300b38fdf7036bf3b2f6244456e1adb3f9c1c359 Mon Sep 17 00:00:00 2001 +From: Jon DeVree +Date: Sun, 11 Feb 2024 10:34:58 -0500 +Subject: [PATCH 463/464] fs/xfs: Handle non-continuous data blocks in + directory extents + +The directory extent list does not have to be a continuous list of data +blocks. When GRUB tries to read a non-existant member of the list, +grub_xfs_read_file() will return a block of zero'ed memory. Checking for +a zero'ed magic number is sufficient to skip this non-existant data block. + +Prior to commit 07318ee7e (fs/xfs: Fix XFS directory extent parsing) +this was handled as a subtle side effect of reading the (non-existant) +tail data structure. Since the block was zero'ed the computation of the +number of directory entries in the block would return 0 as well. + +Fixes: 07318ee7e (fs/xfs: Fix XFS directory extent parsing) +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2254370 + +Signed-off-by: Jon DeVree +Reviewed-By: Vladimir Serbinenko +Reviewed-by: Daniel Kiper +--- + grub-core/fs/xfs.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c +index 70c9f449b133..ab1281497472 100644 +--- a/grub-core/fs/xfs.c ++++ b/grub-core/fs/xfs.c +@@ -928,6 +928,7 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + grub_xfs_first_de(dir->data, dirblock); + int entries = -1; + char *end = dirblock + dirblk_size; ++ grub_uint32_t magic; + + numread = grub_xfs_read_file (dir, 0, 0, + blk << dirblk_log2, +@@ -938,6 +939,15 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + return 0; + } + ++ /* ++ * If this data block isn't actually part of the extent list then ++ * grub_xfs_read_file() returns a block of zeros. So, if the magic ++ * number field is all zeros then this block should be skipped. ++ */ ++ magic = *(grub_uint32_t *)(void *) dirblock; ++ if (!magic) ++ continue; ++ + /* + * Leaf and tail information are only in the data block if the number + * of extents is 1. +-- +2.46.1 + diff --git a/SOURCES/0464-fs-xfs-fix-large-extent-counters-incompat-feature-su.patch b/SOURCES/0464-fs-xfs-fix-large-extent-counters-incompat-feature-su.patch new file mode 100644 index 0000000..6e509a0 --- /dev/null +++ b/SOURCES/0464-fs-xfs-fix-large-extent-counters-incompat-feature-su.patch @@ -0,0 +1,48 @@ +From 6c6b8bebde2261aac2fbe7abd6d03008a5e06ce9 Mon Sep 17 00:00:00 2001 +From: Eric Sandeen +Date: Wed, 4 Dec 2024 07:50:28 -0600 +Subject: [PATCH 464/464] fs/xfs: fix large extent counters incompat feature + support + +When large extent counter / NREXT64 support was added to grub, it missed +a couple of direct reads of nextents which need to be changed to the new +NREXT64-aware helper as well. Without this, we'll have mis-reads of some +directories with this feature enabled. + +(The large extent counter fix likely raced on merge with +07318ee7e ("fs/xfs: Fix XFS directory extent parsing") which added the new +direct nextents reads just prior, causing this issue.) + +Fixes: aa7c1322671e ("fs/xfs: Add large extent counters incompat feature support") +Signed-off-by: Eric Sandeen +Reviewed-by: Anthony Iliopoulos +Reviewed-by: Jon DeVree +--- + grub-core/fs/xfs.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c +index ab1281497472..c60db73613c5 100644 +--- a/grub-core/fs/xfs.c ++++ b/grub-core/fs/xfs.c +@@ -952,7 +952,7 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + * Leaf and tail information are only in the data block if the number + * of extents is 1. + */ +- if (dir->inode.nextents == grub_cpu_to_be32_compile_time (1)) ++ if (grub_xfs_get_inode_nextents(&dir->inode) == 1) + { + struct grub_xfs_dirblock_tail *tail = grub_xfs_dir_tail (dir->data, dirblock); + +@@ -1006,7 +1006,7 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + * The expected number of directory entries is only tracked for the + * single extent case. + */ +- if (dir->inode.nextents == grub_cpu_to_be32_compile_time (1)) ++ if (grub_xfs_get_inode_nextents(&dir->inode) == 1) + { + /* Check if last direntry in this block is reached. */ + entries--; +-- +2.46.1 + diff --git a/SOURCES/0465-grub-mkimage-Create-new-ELF-note-for-SBAT.patch b/SOURCES/0465-grub-mkimage-Create-new-ELF-note-for-SBAT.patch new file mode 100644 index 0000000..8d315f7 --- /dev/null +++ b/SOURCES/0465-grub-mkimage-Create-new-ELF-note-for-SBAT.patch @@ -0,0 +1,167 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sudhakar Kuppusamy +Date: Wed, 23 Oct 2024 17:54:32 +0530 +Subject: [PATCH] grub-mkimage: Create new ELF note for SBAT + +In order to store the SBAT data we create a new ELF note. The string +".sbat", zero-padded to 4 byte alignment, shall be entered in the name +field. The string "SBAT"'s ASCII values, 0x53424154, should be entered +in the type field. + +Signed-off-by: Daniel Axtens +Signed-off-by: Sudhakar Kuppusamy +Reviewed-by: Daniel Kiper +--- + include/grub/util/mkimage.h | 4 ++-- + util/grub-mkimagexx.c | 48 +++++++++++++++++++++++++++++++++++++++++++-- + util/mkimage.c | 5 +++-- + 3 files changed, 51 insertions(+), 6 deletions(-) + +diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h +index 6f1da89b9b65..881e3031f41f 100644 +--- a/include/grub/util/mkimage.h ++++ b/include/grub/util/mkimage.h +@@ -51,12 +51,12 @@ grub_mkimage_load_image64 (const char *kernel_path, + const struct grub_install_image_target_desc *image_target); + void + grub_mkimage_generate_elf32 (const struct grub_install_image_target_desc *image_target, +- int note, size_t appsig_size, char **core_img, size_t *core_size, ++ int note, size_t appsig_size, char *sbat, char **core_img, size_t *core_size, + Elf32_Addr target_addr, + struct grub_mkimage_layout *layout); + void + grub_mkimage_generate_elf64 (const struct grub_install_image_target_desc *image_target, +- int note, size_t appsig_size, char **core_img, size_t *core_size, ++ int note, size_t appsig_size, char *sbat, char **core_img, size_t *core_size, + Elf64_Addr target_addr, + struct grub_mkimage_layout *layout); + +diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c +index 393119486d3f..3609015673ec 100644 +--- a/util/grub-mkimagexx.c ++++ b/util/grub-mkimagexx.c +@@ -115,6 +115,14 @@ struct section_metadata + const char *strtab; + }; + ++#define GRUB_SBAT_NOTE_NAME ".sbat" ++#define GRUB_SBAT_NOTE_TYPE 0x53424154 /* "SBAT" */ ++ ++struct grub_sbat_note { ++ Elf32_Nhdr header; ++ char name[ALIGN_UP(sizeof(GRUB_SBAT_NOTE_NAME), 4)]; ++}; ++ + static int + is_relocatable (const struct grub_install_image_target_desc *image_target) + { +@@ -216,7 +224,7 @@ grub_arm_reloc_jump24 (grub_uint32_t *target, Elf32_Addr sym_addr) + + void + SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc *image_target, +- int note, size_t appsig_size, char **core_img, size_t *core_size, ++ int note, size_t appsig_size, char *sbat, char **core_img, size_t *core_size, + Elf_Addr target_addr, + struct grub_mkimage_layout *layout) + { +@@ -225,10 +233,17 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc + Elf_Ehdr *ehdr; + Elf_Phdr *phdr; + Elf_Shdr *shdr; +- int header_size, footer_size = 0; ++ int header_size, footer_size = 0, footer_offset = 0; + int phnum = 1; + int shnum = 4; + int string_size = sizeof (".text") + sizeof ("mods") + 1; ++ char *footer; ++ ++ if (sbat) ++ { ++ phnum++; ++ footer_size += ALIGN_UP (sizeof (struct grub_sbat_note) + layout->sbat_size, 4); ++ } + + if (appsig_size) + { +@@ -262,6 +277,7 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc + ehdr = (void *) elf_img; + phdr = (void *) (elf_img + sizeof (*ehdr)); + shdr = (void *) (elf_img + sizeof (*ehdr) + phnum * sizeof (*phdr)); ++ footer = elf_img + program_size + header_size; + memcpy (ehdr->e_ident, ELFMAG, SELFMAG); + ehdr->e_ident[EI_CLASS] = ELFCLASSXX; + if (!image_target->bigendian) +@@ -434,6 +450,8 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc + phdr->p_filesz = grub_host_to_target32 (XEN_NOTE_SIZE); + phdr->p_memsz = 0; + phdr->p_offset = grub_host_to_target32 (header_size + program_size); ++ footer = ptr; ++ footer_offset = XEN_NOTE_SIZE; + } + + if (image_target->id == IMAGE_XEN_PVH) +@@ -467,6 +485,8 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc + phdr->p_filesz = grub_host_to_target32 (XEN_PVH_NOTE_SIZE); + phdr->p_memsz = 0; + phdr->p_offset = grub_host_to_target32 (header_size + program_size); ++ footer = ptr; ++ footer_offset = XEN_PVH_NOTE_SIZE; + } + + if (note) +@@ -497,6 +517,30 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc + phdr->p_filesz = grub_host_to_target32 (note_size); + phdr->p_memsz = 0; + phdr->p_offset = grub_host_to_target32 (header_size + program_size); ++ footer = (elf_img + program_size + header_size + note_size); ++ footer_offset += note_size; ++ } ++ ++ if (sbat) ++ { ++ int note_size = ALIGN_UP (sizeof (struct grub_sbat_note) + layout->sbat_size, 4); ++ struct grub_sbat_note *note_ptr = (struct grub_sbat_note *) footer; ++ ++ note_ptr->header.n_namesz = grub_host_to_target32 (sizeof (GRUB_SBAT_NOTE_NAME)); ++ note_ptr->header.n_descsz = grub_host_to_target32 (ALIGN_UP(layout->sbat_size, 4)); ++ note_ptr->header.n_type = grub_host_to_target32 (GRUB_SBAT_NOTE_TYPE); ++ memcpy (note_ptr->name, GRUB_SBAT_NOTE_NAME, sizeof (GRUB_SBAT_NOTE_NAME)); ++ memcpy ((char *)(note_ptr + 1), sbat, layout->sbat_size); ++ ++ phdr++; ++ phdr->p_type = grub_host_to_target32 (PT_NOTE); ++ phdr->p_flags = grub_host_to_target32 (PF_R); ++ phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof); ++ phdr->p_vaddr = 0; ++ phdr->p_paddr = 0; ++ phdr->p_filesz = grub_host_to_target32 (note_size); ++ phdr->p_memsz = 0; ++ phdr->p_offset = grub_host_to_target32 (header_size + program_size + footer_offset); + } + + if (appsig_size) { +diff --git a/util/mkimage.c b/util/mkimage.c +index 9ba1a8988f19..358db8378422 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -1811,6 +1811,7 @@ grub_install_generate_image (const char *dir, const char *prefix, + case IMAGE_I386_IEEE1275: + { + grub_uint64_t target_addr; ++ char *sbat = NULL; + if (image_target->id == IMAGE_LOONGSON_ELF) + { + if (comp == GRUB_COMPRESSION_NONE) +@@ -1822,10 +1823,10 @@ grub_install_generate_image (const char *dir, const char *prefix, + else + target_addr = image_target->link_addr; + if (image_target->voidp_sizeof == 4) +- grub_mkimage_generate_elf32 (image_target, note, appsig_size, &core_img, ++ grub_mkimage_generate_elf32 (image_target, note, appsig_size, sbat, &core_img, + &core_size, target_addr, &layout); + else +- grub_mkimage_generate_elf64 (image_target, note, appsig_size, &core_img, ++ grub_mkimage_generate_elf64 (image_target, note, appsig_size, sbat, &core_img, + &core_size, target_addr, &layout); + } + break; diff --git a/SOURCES/0466-grub-mkimage-Add-SBAT-metadata-into-ELF-note-for-Pow.patch b/SOURCES/0466-grub-mkimage-Add-SBAT-metadata-into-ELF-note-for-Pow.patch new file mode 100644 index 0000000..6b1a227 --- /dev/null +++ b/SOURCES/0466-grub-mkimage-Add-SBAT-metadata-into-ELF-note-for-Pow.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sudhakar Kuppusamy +Date: Wed, 23 Oct 2024 17:54:33 +0530 +Subject: [PATCH] grub-mkimage: Add SBAT metadata into ELF note for PowerPC + targets + +The SBAT metadata is read from CSV file and transformed into an ELF note +with the -s option. + +Signed-off-by: Daniel Axtens +Signed-off-by: Sudhakar Kuppusamy +Reviewed-by: Daniel Kiper +--- + util/mkimage.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/util/mkimage.c b/util/mkimage.c +index 358db8378422..eaa382b2a120 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -941,8 +941,8 @@ grub_install_generate_image (const char *dir, const char *prefix, + total_module_size += dtb_size + sizeof (struct grub_module_header); + } + +- if (sbat_path != NULL && image_target->id != IMAGE_EFI) +- grub_util_error (_(".sbat section can be embedded into EFI images only")); ++ if (sbat_path != NULL && (image_target->id != IMAGE_EFI && image_target->id != IMAGE_PPC)) ++ grub_util_error (_("SBAT data can be added only to EFI or powerpc-ieee1275 images")); + + if (disable_shim_lock) + total_module_size += sizeof (struct grub_module_header); +@@ -1812,6 +1812,13 @@ grub_install_generate_image (const char *dir, const char *prefix, + { + grub_uint64_t target_addr; + char *sbat = NULL; ++ if (sbat_path != NULL) ++ { ++ sbat_size = grub_util_get_image_size (sbat_path); ++ sbat = xmalloc (sbat_size); ++ grub_util_load_image (sbat_path, sbat); ++ layout.sbat_size = sbat_size; ++ } + if (image_target->id == IMAGE_LOONGSON_ELF) + { + if (comp == GRUB_COMPRESSION_NONE) diff --git a/SOURCES/0467-appended-sig-sync-d-with-upstream-code.patch b/SOURCES/0467-appended-sig-sync-d-with-upstream-code.patch new file mode 100644 index 0000000..e27e6c6 --- /dev/null +++ b/SOURCES/0467-appended-sig-sync-d-with-upstream-code.patch @@ -0,0 +1,2720 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nicolas Frayer +Date: Wed, 21 May 2025 15:43:44 -0400 +Subject: [PATCH] appended/sig: sync'd with upstream code + +Signed-off-by: Nicolas Frayer +--- + grub-core/commands/appendedsig/appendedsig.c | 479 +++++++++--------- + grub-core/commands/appendedsig/appendedsig.h | 50 +- + grub-core/commands/appendedsig/asn1util.c | 34 +- + grub-core/commands/appendedsig/pkcs7.c | 389 +++++++++----- + grub-core/commands/appendedsig/x509.c | 727 ++++++++++++--------------- + 5 files changed, 853 insertions(+), 826 deletions(-) + +diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c +index bf8b18b..f4eefe5 100644 +--- a/grub-core/commands/appendedsig/appendedsig.c ++++ b/grub-core/commands/appendedsig/appendedsig.c +@@ -1,6 +1,7 @@ + /* + * GRUB -- GRand Unified Bootloader +- * Copyright (C) 2020-2021 IBM Corporation. ++ * Copyright (C) 2020, 2021, 2022 Free Software Foundation, Inc. ++ * Copyright (C) 2020, 2021, 2022 IBM Corporation + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -46,24 +47,21 @@ const char magic[] = "~Module signature appended~\n"; + */ + struct module_signature + { +- grub_uint8_t algo; /* Public-key crypto algorithm [0] */ +- grub_uint8_t hash; /* Digest algorithm [0] */ +- grub_uint8_t id_type; /* Key identifier type [PKEY_ID_PKCS7] */ +- grub_uint8_t signer_len; /* Length of signer's name [0] */ +- grub_uint8_t key_id_len; /* Length of key identifier [0] */ ++ grub_uint8_t algo; /* Public-key crypto algorithm [0] */ ++ grub_uint8_t hash; /* Digest algorithm [0] */ ++ grub_uint8_t id_type; /* Key identifier type [PKEY_ID_PKCS7] */ ++ grub_uint8_t signer_len; /* Length of signer's name [0] */ ++ grub_uint8_t key_id_len; /* Length of key identifier [0] */ + grub_uint8_t __pad[3]; +- grub_uint32_t sig_len; /* Length of signature data */ ++ grub_uint32_t sig_len; /* Length of signature data */ + } GRUB_PACKED; + +- + /* This represents an entire, parsed, appended signature */ + struct grub_appended_signature + { +- grub_size_t signature_len; /* Length of PKCS#7 data + +- * metadata + magic */ +- +- struct module_signature sig_metadata; /* Module signature metadata */ +- struct pkcs7_signedData pkcs7; /* Parsed PKCS#7 data */ ++ grub_size_t signature_len; /* Length of PKCS#7 data + metadata + magic */ ++ struct module_signature sig_metadata; /* Module signature metadata */ ++ struct pkcs7_signedData pkcs7; /* Parsed PKCS#7 data */ + }; + + /* Trusted certificates for verifying appended signatures */ +@@ -90,143 +88,154 @@ struct x509_certificate *grub_trusted_key; + */ + extern gcry_pk_spec_t _gcry_pubkey_spec_rsa; + +-static int check_sigs = 0; ++static enum ++{ ++ check_sigs_no = 0, ++ check_sigs_enforce = 1, ++ check_sigs_forced = 2 ++} check_sigs = check_sigs_no; + + static const char * + grub_env_read_sec (struct grub_env_var *var __attribute__ ((unused)), + const char *val __attribute__ ((unused))) + { +- if (check_sigs == 2) ++ if (check_sigs == check_sigs_forced) + return "forced"; +- else if (check_sigs == 1) ++ else if (check_sigs == check_sigs_enforce) + return "enforce"; + else + return "no"; + } + + static char * +-grub_env_write_sec (struct grub_env_var *var __attribute__((unused)), +- const char *val) ++grub_env_write_sec (struct grub_env_var *var __attribute__ ((unused)), const char *val) + { + /* Do not allow the value to be changed if set to forced */ +- if (check_sigs == 2) ++ if (check_sigs == check_sigs_forced) + return grub_strdup ("forced"); + + if ((*val == '2') || (*val == 'f')) +- check_sigs = 2; ++ check_sigs = check_sigs_forced; + else if ((*val == '1') || (*val == 'e')) +- check_sigs = 1; ++ check_sigs = check_sigs_enforce; + else if ((*val == '0') || (*val == 'n')) +- check_sigs = 0; ++ check_sigs = check_sigs_no; + + return grub_strdup (grub_env_read_sec (NULL, NULL)); + } + ++static grub_err_t ++file_read_all (grub_file_t file, grub_uint8_t **buf, grub_size_t *len) ++{ ++ grub_off_t full_file_size; ++ grub_size_t file_size, total_read_size = 0; ++ grub_ssize_t read_size; ++ ++ full_file_size = grub_file_size (file); ++ if (full_file_size == GRUB_FILE_SIZE_UNKNOWN) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("Cannot read a file of unknown size into a buffer")); ++ ++ if (full_file_size > GRUB_SIZE_MAX) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("File is too large to read: %" PRIuGRUB_UINT64_T " bytes"), ++ full_file_size); ++ ++ file_size = (grub_size_t) full_file_size; ++ ++ *buf = grub_malloc (file_size); ++ if (!*buf) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ N_("Could not allocate file data buffer size %" PRIuGRUB_SIZE), ++ file_size); ++ ++ while (total_read_size < file_size) ++ { ++ read_size = grub_file_read (file, *buf + total_read_size, file_size - total_read_size); ++ ++ if (read_size < 0) ++ { ++ grub_free (*buf); ++ return grub_errno; ++ } ++ else if (read_size == 0) ++ { ++ grub_free (*buf); ++ return grub_error (GRUB_ERR_IO, ++ N_("Could not read full file size " ++ "(%" PRIuGRUB_SIZE "), only %" PRIuGRUB_SIZE " bytes read"), ++ file_size, total_read_size); ++ } ++ ++ total_read_size += read_size; ++ } ++ *len = file_size; ++ return GRUB_ERR_NONE; ++} ++ + static grub_err_t + read_cert_from_file (grub_file_t f, struct x509_certificate *certificate) + { + grub_err_t err; +- grub_uint8_t *buf = NULL; +- grub_ssize_t read_size; +- grub_off_t total_read_size = 0; +- grub_off_t file_size = grub_file_size (f); ++ grub_uint8_t *buf; ++ grub_size_t file_size; + +- +- if (file_size == GRUB_FILE_SIZE_UNKNOWN) +- return grub_error (GRUB_ERR_BAD_ARGUMENT, +- N_("Cannot parse a certificate file of unknown size")); +- +- buf = grub_zalloc (file_size); +- if (!buf) +- return grub_error (GRUB_ERR_OUT_OF_MEMORY, +- N_("Could not allocate buffer for certificate file contents")); +- +- while (total_read_size < file_size) +- { +- read_size = +- grub_file_read (f, &buf[total_read_size], +- file_size - total_read_size); +- if (read_size < 0) +- { +- err = grub_error (GRUB_ERR_READ_ERROR, +- N_("Error reading certificate file")); +- goto cleanup_buf; +- } +- total_read_size += read_size; +- } +- +- err = certificate_import (buf, total_read_size, certificate); ++ err = file_read_all (f, &buf, &file_size); + if (err != GRUB_ERR_NONE) +- goto cleanup_buf; ++ return err; + +- return GRUB_ERR_NONE; +- +-cleanup_buf: ++ err = parse_x509_certificate (buf, file_size, certificate); + grub_free (buf); ++ + return err; + } + + static grub_err_t +-extract_appended_signature (grub_uint8_t * buf, grub_size_t bufsize, +- struct grub_appended_signature *sig) ++extract_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize, ++ struct grub_appended_signature *sig) + { +- grub_err_t err; + grub_size_t pkcs7_size; + grub_size_t remaining_len; +- grub_uint8_t *appsigdata = buf + bufsize - grub_strlen (magic); ++ const grub_uint8_t *appsigdata = buf + bufsize - grub_strlen (magic); + + if (bufsize < grub_strlen (magic)) +- return grub_error (GRUB_ERR_BAD_SIGNATURE, +- N_("File too short for signature magic")); ++ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("File too short for signature magic")); + + if (grub_memcmp (appsigdata, (grub_uint8_t *) magic, grub_strlen (magic))) +- return grub_error (GRUB_ERR_BAD_SIGNATURE, +- N_("Missing or invalid signature magic")); ++ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("Missing or invalid signature magic")); + + remaining_len = bufsize - grub_strlen (magic); + + if (remaining_len < sizeof (struct module_signature)) +- return grub_error (GRUB_ERR_BAD_SIGNATURE, +- N_("File too short for signature metadata")); ++ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("File too short for signature metadata")); + + appsigdata -= sizeof (struct module_signature); + + /* extract the metadata */ +- grub_memcpy (&(sig->sig_metadata), appsigdata, +- sizeof (struct module_signature)); ++ grub_memcpy (&(sig->sig_metadata), appsigdata, sizeof (struct module_signature)); + + remaining_len -= sizeof (struct module_signature); + + if (sig->sig_metadata.id_type != 2) + return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("Wrong signature type")); + +-#ifdef GRUB_TARGET_WORDS_BIGENDIAN +- pkcs7_size = sig->sig_metadata.sig_len; +-#else +- pkcs7_size = __builtin_bswap32 (sig->sig_metadata.sig_len); +-#endif ++ pkcs7_size = grub_be_to_cpu32 (sig->sig_metadata.sig_len); + + if (pkcs7_size > remaining_len) +- return grub_error (GRUB_ERR_BAD_SIGNATURE, +- N_("File too short for PKCS#7 message")); ++ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("File too short for PKCS#7 message")); + + grub_dprintf ("appendedsig", "sig len %" PRIuGRUB_SIZE "\n", pkcs7_size); + +- sig->signature_len = +- grub_strlen (magic) + sizeof (struct module_signature) + pkcs7_size; ++ sig->signature_len = grub_strlen (magic) + sizeof (struct module_signature) + pkcs7_size; + + /* rewind pointer and parse pkcs7 data */ + appsigdata -= pkcs7_size; + +- err = parse_pkcs7_signedData (appsigdata, pkcs7_size, &sig->pkcs7); +- if (err != GRUB_ERR_NONE) +- return err; +- +- return GRUB_ERR_NONE; ++ return parse_pkcs7_signedData (appsigdata, pkcs7_size, &sig->pkcs7); + } + + static grub_err_t +-grub_verify_appended_signature (grub_uint8_t * buf, grub_size_t bufsize) ++grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize) + { + grub_err_t err = GRUB_ERR_NONE; + grub_size_t datasize; +@@ -236,10 +245,11 @@ grub_verify_appended_signature (grub_uint8_t * buf, grub_size_t bufsize) + gcry_err_code_t rc; + struct x509_certificate *pk; + struct grub_appended_signature sig; ++ struct pkcs7_signerInfo *si; ++ int i; + + if (!grub_trusted_key) +- return grub_error (GRUB_ERR_BAD_SIGNATURE, +- N_("No trusted keys to verify against")); ++ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("No trusted keys to verify against")); + + err = extract_appended_signature (buf, bufsize, &sig); + if (err != GRUB_ERR_NONE) +@@ -247,67 +257,78 @@ grub_verify_appended_signature (grub_uint8_t * buf, grub_size_t bufsize) + + datasize = bufsize - sig.signature_len; + +- context = grub_zalloc (sig.pkcs7.hash->contextsize); +- if (!context) +- return grub_errno; +- +- sig.pkcs7.hash->init (context); +- sig.pkcs7.hash->write (context, buf, datasize); +- sig.pkcs7.hash->final (context); +- hash = sig.pkcs7.hash->read (context); +- grub_dprintf ("appendedsig", +- "data size %" PRIxGRUB_SIZE ", hash %02x%02x%02x%02x...\n", +- datasize, hash[0], hash[1], hash[2], hash[3]); +- +- err = GRUB_ERR_BAD_SIGNATURE; +- for (pk = grub_trusted_key; pk; pk = pk->next) ++ for (i = 0; i < sig.pkcs7.signerInfo_count; i++) + { +- rc = grub_crypto_rsa_pad (&hashmpi, hash, sig.pkcs7.hash, pk->mpis[0]); +- if (rc) +- { +- err = grub_error (GRUB_ERR_BAD_SIGNATURE, +- N_("Error padding hash for RSA verification: %d"), +- rc); +- goto cleanup; +- } +- +- rc = _gcry_pubkey_spec_rsa.verify (0, hashmpi, &sig.pkcs7.sig_mpi, +- pk->mpis, NULL, NULL); +- gcry_mpi_release (hashmpi); +- +- if (rc == 0) +- { +- grub_dprintf ("appendedsig", "verify with key '%s' succeeded\n", +- pk->subject); +- err = GRUB_ERR_NONE; +- break; +- } +- +- grub_dprintf ("appendedsig", "verify with key '%s' failed with %d\n", +- pk->subject, rc); ++ /* ++ * This could be optimised in a couple of ways: ++ * - we could only compute hashes once per hash type ++ * - we could track signer information and only verify where IDs match ++ * For now we do the naive O(trusted keys * pkcs7 signers) approach. ++ */ ++ si = &sig.pkcs7.signerInfos[i]; ++ context = grub_zalloc (si->hash->contextsize); ++ if (!context) ++ return grub_errno; ++ ++ si->hash->init (context); ++ si->hash->write (context, buf, datasize); ++ si->hash->final (context); ++ hash = si->hash->read (context); ++ ++ grub_dprintf ("appendedsig", "data size %" PRIxGRUB_SIZE ", signer %d hash %02x%02x%02x%02x...\n", ++ datasize, i, hash[0], hash[1], hash[2], hash[3]); ++ ++ err = GRUB_ERR_BAD_SIGNATURE; ++ for (pk = grub_trusted_key; pk; pk = pk->next) ++ { ++ rc = grub_crypto_rsa_pad (&hashmpi, hash, si->hash, pk->mpis[0]); ++ if (rc) ++ { ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, ++ N_("Error padding hash for RSA verification: %d"), rc); ++ grub_free (context); ++ goto cleanup; ++ } ++ ++ rc = _gcry_pubkey_spec_rsa.verify (0, hashmpi, &si->sig_mpi, pk->mpis, NULL, NULL); ++ gcry_mpi_release (hashmpi); ++ ++ if (rc == 0) ++ { ++ grub_dprintf ("appendedsig", "verify signer %d with key '%s' succeeded\n", ++ i, pk->subject); ++ err = GRUB_ERR_NONE; ++ break; ++ } ++ ++ grub_dprintf ("appendedsig", "verify signer %d with key '%s' failed with %d\n", ++ i, pk->subject, rc); ++ } ++ ++ grub_free (context); ++ ++ if (err == GRUB_ERR_NONE) ++ break; + } + + /* If we didn't verify, provide a neat message */ + if (err != GRUB_ERR_NONE) +- err = grub_error (GRUB_ERR_BAD_SIGNATURE, +- N_("Failed to verify signature against a trusted key")); ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, ++ N_("Failed to verify signature against a trusted key")); + + cleanup: +- grub_free (context); + pkcs7_signedData_release (&sig.pkcs7); + + return err; + } + + static grub_err_t +-grub_cmd_verify_signature (grub_command_t cmd __attribute__((unused)), +- int argc, char **args) ++grub_cmd_verify_signature (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) + { + grub_file_t f; + grub_err_t err = GRUB_ERR_NONE; + grub_uint8_t *data; +- grub_ssize_t read_size; +- grub_off_t file_size, total_read_size = 0; ++ grub_size_t file_size; + + if (argc < 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); +@@ -321,35 +342,14 @@ grub_cmd_verify_signature (grub_command_t cmd __attribute__((unused)), + goto cleanup; + } + +- file_size = grub_file_size (f); +- if (file_size == GRUB_FILE_SIZE_UNKNOWN) +- return grub_error (GRUB_ERR_BAD_ARGUMENT, +- N_("Cannot verify the signature of a file of unknown size")); +- +- data = grub_malloc (file_size); +- if (!data) +- return grub_error (GRUB_ERR_OUT_OF_MEMORY, +- N_("Could not allocate data buffer size %" +- PRIuGRUB_UINT64_T " for verification"), file_size); +- +- while (total_read_size < file_size) +- { +- read_size = +- grub_file_read (f, &data[total_read_size], +- file_size - total_read_size); +- if (read_size < 0) +- { +- err = grub_error (GRUB_ERR_READ_ERROR, +- N_("Error reading file to verify")); +- goto cleanup_data; +- } +- total_read_size += read_size; +- } ++ err = file_read_all (f, &data, &file_size); ++ if (err != GRUB_ERR_NONE) ++ goto cleanup; + + err = grub_verify_appended_signature (data, file_size); + +-cleanup_data: + grub_free (data); ++ + cleanup: + if (f) + grub_file_close (f); +@@ -357,8 +357,7 @@ cleanup: + } + + static grub_err_t +-grub_cmd_distrust (grub_command_t cmd __attribute__((unused)), +- int argc, char **args) ++grub_cmd_distrust (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) + { + unsigned long cert_num, i; + struct x509_certificate *cert, *prev; +@@ -373,7 +372,7 @@ grub_cmd_distrust (grub_command_t cmd __attribute__((unused)), + + if (cert_num < 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, +- N_("Certificate number too small - numbers start at 1")); ++ N_("Certificate number too small - numbers start at 1")); + + if (cert_num == 1) + { +@@ -390,25 +389,24 @@ grub_cmd_distrust (grub_command_t cmd __attribute__((unused)), + while (cert) + { + if (i == cert_num) +- { +- prev->next = cert->next; +- certificate_release (cert); +- grub_free (cert); +- return GRUB_ERR_NONE; +- } ++ { ++ prev->next = cert->next; ++ certificate_release (cert); ++ grub_free (cert); ++ return GRUB_ERR_NONE; ++ } + i++; + prev = cert; + cert = cert->next; + } + + return grub_error (GRUB_ERR_BAD_ARGUMENT, +- N_("No certificate number %d found - only %d certificates in the store"), +- cert_num, i - 1); ++ N_("No certificate number %lu found - only %lu certificates in the store"), ++ cert_num, i - 1); + } + + static grub_err_t +-grub_cmd_trust (grub_command_t cmd __attribute__((unused)), +- int argc, char **args) ++grub_cmd_trust (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) + { + grub_file_t certf; + struct x509_certificate *cert = NULL; +@@ -417,17 +415,13 @@ grub_cmd_trust (grub_command_t cmd __attribute__((unused)), + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); + +- certf = grub_file_open (args[0], +- GRUB_FILE_TYPE_CERTIFICATE_TRUST +- | GRUB_FILE_TYPE_NO_DECOMPRESS); ++ certf = grub_file_open (args[0], GRUB_FILE_TYPE_CERTIFICATE_TRUST | GRUB_FILE_TYPE_NO_DECOMPRESS); + if (!certf) + return grub_errno; + +- + cert = grub_zalloc (sizeof (struct x509_certificate)); + if (!cert) +- return grub_error (GRUB_ERR_OUT_OF_MEMORY, +- N_("Could not allocate memory for certificate")); ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("Could not allocate memory for certificate")); + + err = read_cert_from_file (certf, cert); + grub_file_close (certf); +@@ -436,8 +430,7 @@ grub_cmd_trust (grub_command_t cmd __attribute__((unused)), + grub_free (cert); + return err; + } +- grub_dprintf ("appendedsig", "Loaded certificate with CN: %s\n", +- cert->subject); ++ grub_dprintf ("appendedsig", "Loaded certificate with CN: %s\n", cert->subject); + + cert->next = grub_trusted_key; + grub_trusted_key = cert; +@@ -446,9 +439,8 @@ grub_cmd_trust (grub_command_t cmd __attribute__((unused)), + } + + static grub_err_t +-grub_cmd_list (grub_command_t cmd __attribute__((unused)), +- int argc __attribute__((unused)), +- char **args __attribute__((unused))) ++grub_cmd_list (grub_command_t cmd __attribute__ ((unused)), int argc __attribute__ ((unused)), ++ char **args __attribute__ ((unused))) + { + struct x509_certificate *cert; + int cert_num = 1; +@@ -460,26 +452,23 @@ grub_cmd_list (grub_command_t cmd __attribute__((unused)), + + grub_printf (N_("\tSerial: ")); + for (i = 0; i < cert->serial_len - 1; i++) +- { +- grub_printf ("%02x:", cert->serial[i]); +- } ++ { ++ grub_printf ("%02x:", cert->serial[i]); ++ } + grub_printf ("%02x\n", cert->serial[cert->serial_len - 1]); + + grub_printf ("\tCN: %s\n\n", cert->subject); + cert_num++; +- + } + + return GRUB_ERR_NONE; + } + + static grub_err_t +-appendedsig_init (grub_file_t io __attribute__((unused)), +- enum grub_file_type type, +- void **context __attribute__((unused)), +- enum grub_verify_flags *flags) ++appendedsig_init (grub_file_t io __attribute__ ((unused)), enum grub_file_type type, ++ void **context __attribute__ ((unused)), enum grub_verify_flags *flags) + { +- if (!check_sigs) ++ if (check_sigs == check_sigs_no) + { + *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; + return GRUB_ERR_NONE; +@@ -487,48 +476,47 @@ appendedsig_init (grub_file_t io __attribute__((unused)), + + switch (type & GRUB_FILE_TYPE_MASK) + { +- case GRUB_FILE_TYPE_CERTIFICATE_TRUST: +- /* +- * This is a certificate to add to trusted keychain. +- * +- * This needs to be verified or blocked. Ideally we'd write an x509 +- * verifier, but we lack the hubris required to take this on. Instead, +- * require that it have an appended signature. +- */ ++ case GRUB_FILE_TYPE_CERTIFICATE_TRUST: ++ /* ++ * This is a certificate to add to trusted keychain. ++ * ++ * This needs to be verified or blocked. Ideally we'd write an x509 ++ * verifier, but we lack the hubris required to take this on. Instead, ++ * require that it have an appended signature. ++ */ + +- /* Fall through */ ++ /* Fall through */ + +- case GRUB_FILE_TYPE_LINUX_KERNEL: +- case GRUB_FILE_TYPE_GRUB_MODULE: +- /* +- * Appended signatures are only defined for ELF binaries. +- * Out of an abundance of caution, we only verify Linux kernels and +- * GRUB modules at this point. +- */ +- *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK; +- return GRUB_ERR_NONE; ++ case GRUB_FILE_TYPE_LINUX_KERNEL: ++ case GRUB_FILE_TYPE_GRUB_MODULE: ++ /* ++ * Appended signatures are only defined for ELF binaries. ++ * Out of an abundance of caution, we only verify Linux kernels and ++ * GRUB modules at this point. ++ */ ++ *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK; ++ return GRUB_ERR_NONE; + +- case GRUB_FILE_TYPE_ACPI_TABLE: +- case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE: +- /* +- * It is possible to use appended signature verification without +- * lockdown - like the PGP verifier. When combined with an embedded +- * config file in a signed grub binary, this could still be a meaningful +- * secure-boot chain - so long as it isn't subverted by something like a +- * rouge ACPI table or DT image. Defer them explicitly. +- */ +- *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH; +- return GRUB_ERR_NONE; ++ case GRUB_FILE_TYPE_ACPI_TABLE: ++ case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE: ++ /* ++ * It is possible to use appended signature verification without ++ * lockdown - like the PGP verifier. When combined with an embedded ++ * config file in a signed grub binary, this could still be a meaningful ++ * secure-boot chain - so long as it isn't subverted by something like a ++ * rouge ACPI table or DT image. Defer them explicitly. ++ */ ++ *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH; ++ return GRUB_ERR_NONE; + +- default: +- *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; +- return GRUB_ERR_NONE; ++ default: ++ *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; ++ return GRUB_ERR_NONE; + } + } + + static grub_err_t +-appendedsig_write (void *ctxt __attribute__((unused)), +- void *buf, grub_size_t size) ++appendedsig_write (void *ctxt __attribute__ ((unused)), void *buf, grub_size_t size) + { + return grub_verify_appended_signature (buf, size); + } +@@ -547,10 +535,7 @@ pseudo_read (struct grub_file *file, char *buf, grub_size_t len) + } + + /* Filesystem descriptor. */ +-static struct grub_fs pseudo_fs = { +- .name = "pseudo", +- .fs_read = pseudo_read +-}; ++static struct grub_fs pseudo_fs = { .name = "pseudo", .fs_read = pseudo_read }; + + static grub_command_t cmd_verify, cmd_list, cmd_distrust, cmd_trust; + +@@ -561,19 +546,15 @@ GRUB_MOD_INIT (appendedsig) + + /* If in lockdown, immediately enter forced mode */ + if (grub_is_lockdown () == GRUB_LOCKDOWN_ENABLED) +- check_sigs = 2; ++ check_sigs = check_sigs_forced; + + grub_trusted_key = NULL; +- +- grub_register_variable_hook ("check_appended_signatures", +- grub_env_read_sec, +- grub_env_write_sec); ++ grub_register_variable_hook ("check_appended_signatures", grub_env_read_sec, grub_env_write_sec); + grub_env_export ("check_appended_signatures"); + + rc = asn1_init (); + if (rc) +- grub_fatal ("Error initing ASN.1 data structures: %d: %s\n", rc, +- asn1_strerror (rc)); ++ grub_fatal ("Error initing ASN.1 data structures: %d: %s\n", rc, asn1_strerror (rc)); + + FOR_MODULES (header) + { +@@ -581,7 +562,7 @@ GRUB_MOD_INIT (appendedsig) + struct x509_certificate *pk = NULL; + grub_err_t err; + +- /* Not an ELF module, skip. */ ++ /* Not an X.509 certificate, skip. */ + if (header->type != OBJ_TYPE_X509_PUBKEY) + continue; + +@@ -590,15 +571,12 @@ GRUB_MOD_INIT (appendedsig) + pseudo_file.size = header->size - sizeof (struct grub_module_header); + pseudo_file.data = (char *) header + sizeof (struct grub_module_header); + +- grub_dprintf ("appendedsig", +- "Found an x509 key, size=%" PRIuGRUB_UINT64_T "\n", +- pseudo_file.size); ++ grub_dprintf ("appendedsig", "Found an x509 key, size=%" PRIuGRUB_UINT64_T "\n", ++ pseudo_file.size); + + pk = grub_zalloc (sizeof (struct x509_certificate)); + if (!pk) +- { +- grub_fatal ("Out of memory loading initial certificates"); +- } ++ grub_fatal ("Out of memory loading initial certificates"); + + err = read_cert_from_file (&pseudo_file, pk); + if (err != GRUB_ERR_NONE) +@@ -610,21 +588,16 @@ GRUB_MOD_INIT (appendedsig) + grub_trusted_key = pk; + } + +- cmd_trust = +- grub_register_command ("trust_certificate", grub_cmd_trust, +- N_("X509_CERTIFICATE"), +- N_("Add X509_CERTIFICATE to trusted certificates.")); +- cmd_list = +- grub_register_command ("list_certificates", grub_cmd_list, 0, +- N_("Show the list of trusted x509 certificates.")); +- cmd_verify = +- grub_register_command ("verify_appended", grub_cmd_verify_signature, +- N_("FILE"), +- N_("Verify FILE against the trusted x509 certificates.")); +- cmd_distrust = +- grub_register_command ("distrust_certificate", grub_cmd_distrust, +- N_("CERT_NUMBER"), +- N_("Remove CERT_NUMBER (as listed by list_certificates) from trusted certificates.")); ++ cmd_trust = grub_register_command ("trust_certificate", grub_cmd_trust, N_("X509_CERTIFICATE"), ++ N_("Add X509_CERTIFICATE to trusted certificates.")); ++ cmd_list = grub_register_command ("list_certificates", grub_cmd_list, 0, ++ N_("Show the list of trusted x509 certificates.")); ++ cmd_verify = grub_register_command ("verify_appended", grub_cmd_verify_signature, N_("FILE"), ++ N_("Verify FILE against the trusted x509 certificates.")); ++ cmd_distrust = grub_register_command ("distrust_certificate", grub_cmd_distrust, ++ N_("CERT_NUMBER"), ++ N_("Remove CERT_NUMBER (as listed by list_certificates)" ++ " from trusted certificates.")); + + grub_verifier_register (&grub_appendedsig_verifier); + grub_dl_set_persistent (mod); +diff --git a/grub-core/commands/appendedsig/appendedsig.h b/grub-core/commands/appendedsig/appendedsig.h +index 9792ef3..3f4d700 100644 +--- a/grub-core/commands/appendedsig/appendedsig.h ++++ b/grub-core/commands/appendedsig/appendedsig.h +@@ -1,6 +1,7 @@ + /* + * GRUB -- GRand Unified Bootloader +- * Copyright (C) 2020 IBM Corporation. ++ * Copyright (C) 2020, 2022 Free Software Foundation, Inc. ++ * Copyright (C) 2020, 2022 IBM Corporation + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -26,85 +27,84 @@ extern asn1_node _gnutls_pkix_asn; + + /* + * One or more x509 certificates. +- * + * We do limited parsing: extracting only the serial, CN and RSA public key. + */ + struct x509_certificate + { + struct x509_certificate *next; +- + grub_uint8_t *serial; + grub_size_t serial_len; +- + char *subject; + grub_size_t subject_len; +- + /* We only support RSA public keys. This encodes [modulus, publicExponent] */ + gcry_mpi_t mpis[2]; + }; + ++/* ++ * A PKCS#7 signedData signerInfo. ++ */ ++struct pkcs7_signerInfo ++{ ++ const gcry_md_spec_t *hash; ++ gcry_mpi_t sig_mpi; ++}; ++ + /* + * A PKCS#7 signedData message. +- * + * We make no attempt to match intelligently, so we don't save any info about +- * the signer. We also support only 1 signerInfo, so we only store a single +- * MPI for the signature. ++ * the signer. + */ + struct pkcs7_signedData + { +- const gcry_md_spec_t *hash; +- gcry_mpi_t sig_mpi; ++ int signerInfo_count; ++ struct pkcs7_signerInfo *signerInfos; + }; + +- + /* Do libtasn1 init */ +-int asn1_init (void); ++int ++asn1_init (void); + + /* + * Import a DER-encoded certificate at 'data', of size 'size'. +- * + * Place the results into 'results', which must be already allocated. + */ + grub_err_t +-certificate_import (void *data, grub_size_t size, +- struct x509_certificate *results); ++parse_x509_certificate (const void *data, grub_size_t size, struct x509_certificate *results); + + /* + * Release all the storage associated with the x509 certificate. + * If the caller dynamically allocated the certificate, it must free it. + * The caller is also responsible for maintenance of the linked list. + */ +-void certificate_release (struct x509_certificate *cert); ++void ++certificate_release (struct x509_certificate *cert); + + /* + * Parse a PKCS#7 message, which must be a signedData message. +- * + * The message must be in 'sigbuf' and of size 'data_size'. The result is + * placed in 'msg', which must already be allocated. + */ + grub_err_t +-parse_pkcs7_signedData (void *sigbuf, grub_size_t data_size, +- struct pkcs7_signedData *msg); ++parse_pkcs7_signedData (const void *sigbuf, grub_size_t data_size, struct pkcs7_signedData *msg); + + /* + * Release all the storage associated with the PKCS#7 message. + * If the caller dynamically allocated the message, it must free it. + */ +-void pkcs7_signedData_release (struct pkcs7_signedData *msg); ++void ++pkcs7_signedData_release (struct pkcs7_signedData *msg); + + /* + * Read a value from an ASN1 node, allocating memory to store it. +- * + * It will work for anything where the size libtasn1 returns is right: + * - Integers + * - Octet strings + * - DER encoding of other structures + * It will _not_ work for things where libtasn1 size requires adjustment: +- * - Strings that require an extra NULL byte at the end ++ * - Strings that require an extra null byte at the end + * - Bit strings because libtasn1 returns the length in bits, not bytes. + * + * If the function returns a non-NULL value, the caller must free it. + */ +-void *grub_asn1_allocate_and_read (asn1_node node, const char *name, +- const char *friendly_name, +- int *content_size); ++void * ++grub_asn1_allocate_and_read (asn1_node node, const char *name, const char *friendly_name, int *content_size); +diff --git a/grub-core/commands/appendedsig/asn1util.c b/grub-core/commands/appendedsig/asn1util.c +index eff095a..06c3b61 100644 +--- a/grub-core/commands/appendedsig/asn1util.c ++++ b/grub-core/commands/appendedsig/asn1util.c +@@ -1,6 +1,7 @@ + /* + * GRUB -- GRand Unified Bootloader +- * Copyright (C) 2020 IBM Corporation. ++ * Copyright (C) 2020, 2022 Free Software Foundation, Inc. ++ * Copyright (C) 2020, 2022 IBM Corporation + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -21,19 +22,19 @@ + #include + #include + #include ++#include + #include + + #include "appendedsig.h" + +-asn1_node _gnutls_gnutls_asn = ASN1_TYPE_EMPTY; +-asn1_node _gnutls_pkix_asn = ASN1_TYPE_EMPTY; ++asn1_node _gnutls_gnutls_asn = NULL; ++asn1_node _gnutls_pkix_asn = NULL; + +-extern const ASN1_ARRAY_TYPE gnutls_asn1_tab[]; +-extern const ASN1_ARRAY_TYPE pkix_asn1_tab[]; ++extern const asn1_static_node gnutls_asn1_tab[]; ++extern const asn1_static_node pkix_asn1_tab[]; + + /* + * Read a value from an ASN1 node, allocating memory to store it. +- * + * It will work for anything where the size libtasn1 returns is right: + * - Integers + * - Octet strings +@@ -41,12 +42,10 @@ extern const ASN1_ARRAY_TYPE pkix_asn1_tab[]; + * It will _not_ work for things where libtasn1 size requires adjustment: + * - Strings that require an extra NULL byte at the end + * - Bit strings because libtasn1 returns the length in bits, not bytes. +- * + * If the function returns a non-NULL value, the caller must free it. + */ + void * +-grub_asn1_allocate_and_read (asn1_node node, const char *name, +- const char *friendly_name, int *content_size) ++grub_asn1_allocate_and_read (asn1_node node, const char *name, const char *friendly_name, int *content_size) + { + int result; + grub_uint8_t *tmpstr = NULL; +@@ -56,9 +55,8 @@ grub_asn1_allocate_and_read (asn1_node node, const char *name, + if (result != ASN1_MEM_ERROR) + { + grub_snprintf (grub_errmsg, sizeof (grub_errmsg), +- _ +- ("Reading size of %s did not return expected status: %s"), +- friendly_name, asn1_strerror (result)); ++ _("Reading size of %s did not return expected status: %s"), ++ friendly_name, asn1_strerror (result)); + grub_errno = GRUB_ERR_BAD_FILE_TYPE; + return NULL; + } +@@ -67,7 +65,7 @@ grub_asn1_allocate_and_read (asn1_node node, const char *name, + if (tmpstr == NULL) + { + grub_snprintf (grub_errmsg, sizeof (grub_errmsg), +- "Could not allocate memory to store %s", friendly_name); ++ "Could not allocate memory to store %s", friendly_name); + grub_errno = GRUB_ERR_OUT_OF_MEMORY; + return NULL; + } +@@ -76,9 +74,8 @@ grub_asn1_allocate_and_read (asn1_node node, const char *name, + if (result != ASN1_SUCCESS) + { + grub_free (tmpstr); +- grub_snprintf (grub_errmsg, sizeof (grub_errmsg), +- "Error reading %s: %s", +- friendly_name, asn1_strerror (result)); ++ grub_snprintf (grub_errmsg, sizeof (grub_errmsg), "Error reading %s: %s", ++ friendly_name, asn1_strerror (result)); + grub_errno = GRUB_ERR_BAD_FILE_TYPE; + return NULL; + } +@@ -94,9 +91,8 @@ asn1_init (void) + int res; + res = asn1_array2tree (gnutls_asn1_tab, &_gnutls_gnutls_asn, NULL); + if (res != ASN1_SUCCESS) +- { +- return res; +- } ++ return res; ++ + res = asn1_array2tree (pkix_asn1_tab, &_gnutls_pkix_asn, NULL); + return res; + } +diff --git a/grub-core/commands/appendedsig/pkcs7.c b/grub-core/commands/appendedsig/pkcs7.c +index dc6afe2..31a5eab 100644 +--- a/grub-core/commands/appendedsig/pkcs7.c ++++ b/grub-core/commands/appendedsig/pkcs7.c +@@ -1,6 +1,7 @@ + /* + * GRUB -- GRand Unified Bootloader +- * Copyright (C) 2020 IBM Corporation. ++ * Copyright (C) 2020, 2022 Free Software Foundation, Inc. ++ * Copyright (C) 2020, 2022 IBM Corporation + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -20,24 +21,23 @@ + #include + #include + #include +- ++#include + + static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; + + /* + * RFC 5652 s 5.1 + */ +-const char *signedData_oid = "1.2.840.113549.1.7.2"; ++static const char *signedData_oid = "1.2.840.113549.1.7.2"; + + /* + * RFC 4055 s 2.1 + */ +-const char *sha256_oid = "2.16.840.1.101.3.4.2.1"; +-const char *sha512_oid = "2.16.840.1.101.3.4.2.3"; ++static const char *sha256_oid = "2.16.840.1.101.3.4.2.1"; ++static const char *sha512_oid = "2.16.840.1.101.3.4.2.3"; + + static grub_err_t +-process_content (grub_uint8_t * content, int size, +- struct pkcs7_signedData *msg) ++process_content (grub_uint8_t *content, int size, struct pkcs7_signedData *msg) + { + int res; + asn1_node signed_part; +@@ -45,32 +45,35 @@ process_content (grub_uint8_t * content, int size, + char algo_oid[MAX_OID_LEN]; + int algo_oid_size = sizeof (algo_oid); + int algo_count; ++ int signer_count; ++ int i; + char version; + int version_size = sizeof (version); + grub_uint8_t *result_buf; + int result_size = 0; + int crls_size = 0; + gcry_error_t gcry_err; ++ bool sha256_in_da, sha256_in_si, sha512_in_da, sha512_in_si; ++ char *da_path; ++ char *si_sig_path; ++ char *si_da_path; + +- res = asn1_create_element (_gnutls_pkix_asn, "PKIX1.pkcs-7-SignedData", +- &signed_part); ++ res = asn1_create_element (_gnutls_pkix_asn, "PKIX1.pkcs-7-SignedData", &signed_part); + if (res != ASN1_SUCCESS) +- { +- return grub_error (GRUB_ERR_OUT_OF_MEMORY, +- "Could not create ASN.1 structure for PKCS#7 signed part."); +- } ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not create ASN.1 structure for PKCS#7 signed part."); + + res = asn1_der_decoding2 (&signed_part, content, &size, +- ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ ASN1_DECODE_FLAG_STRICT_DER, asn1_error); + if (res != ASN1_SUCCESS) + { +- err = +- grub_error (GRUB_ERR_BAD_SIGNATURE, +- "Error reading PKCS#7 signed data: %s", asn1_error); ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Error reading PKCS#7 signed data: %s", asn1_error); + goto cleanup_signed_part; + } + +- /* SignedData ::= SEQUENCE { ++ /* ++ * SignedData ::= SEQUENCE { + * version CMSVersion, + * digestAlgorithms DigestAlgorithmIdentifiers, + * encapContentInfo EncapsulatedContentInfo, +@@ -83,19 +86,15 @@ process_content (grub_uint8_t * content, int size, + res = asn1_read_value (signed_part, "version", &version, &version_size); + if (res != ASN1_SUCCESS) + { +- err = +- grub_error (GRUB_ERR_BAD_SIGNATURE, +- "Error reading signedData version: %s", +- asn1_strerror (res)); ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error reading signedData version: %s", ++ asn1_strerror (res)); + goto cleanup_signed_part; + } + + if (version != 1) + { +- err = +- grub_error (GRUB_ERR_BAD_SIGNATURE, +- "Unexpected signature version v%d, only v1 supported", +- version); ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Unexpected signature version v%d, only v1 supported", version); + goto cleanup_signed_part; + } + +@@ -104,69 +103,96 @@ process_content (grub_uint8_t * content, int size, + * + * DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier + * DigestAlgorithmIdentifer is an X.509 AlgorithmIdentifier (10.1.1) +- * ++ * + * RFC 4055 s 2.1: + * sha256Identifier AlgorithmIdentifier ::= { id-sha256, NULL } + * sha512Identifier AlgorithmIdentifier ::= { id-sha512, NULL } + * + * We only support 1 element in the set, and we do not check parameters atm. + */ +- res = +- asn1_number_of_elements (signed_part, "digestAlgorithms", &algo_count); ++ res = asn1_number_of_elements (signed_part, "digestAlgorithms", &algo_count); + if (res != ASN1_SUCCESS) + { +- err = +- grub_error (GRUB_ERR_BAD_SIGNATURE, +- "Error counting number of digest algorithms: %s", +- asn1_strerror (res)); ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error counting number of digest algorithms: %s", ++ asn1_strerror (res)); + goto cleanup_signed_part; + } + +- if (algo_count != 1) ++ if (algo_count <= 0) + { +- err = +- grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, +- "Only 1 digest algorithm is supported"); ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "A minimum of 1 digest algorithm is required"); + goto cleanup_signed_part; + } + +- res = +- asn1_read_value (signed_part, "digestAlgorithms.?1.algorithm", algo_oid, +- &algo_oid_size); +- if (res != ASN1_SUCCESS) ++ if (algo_count > 2) + { +- err = +- grub_error (GRUB_ERR_BAD_SIGNATURE, +- "Error reading digest algorithm: %s", +- asn1_strerror (res)); ++ err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ "A maximum of 2 digest algorithms is supported"); + goto cleanup_signed_part; + } + +- if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0) +- { +- msg->hash = grub_crypto_lookup_md_by_name ("sha512"); +- } +- else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 0) +- { +- msg->hash = grub_crypto_lookup_md_by_name ("sha256"); +- } +- else +- { +- err = +- grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, +- "Only SHA-256 and SHA-512 hashes are supported, found OID %s", +- algo_oid); +- goto cleanup_signed_part; +- } ++ sha256_in_da = false; ++ sha512_in_da = false; + +- if (!msg->hash) ++ for (i = 0; i < algo_count; i++) + { +- err = +- grub_error (GRUB_ERR_BAD_SIGNATURE, +- "Hash algorithm for OID %s not loaded", algo_oid); +- goto cleanup_signed_part; ++ da_path = grub_xasprintf ("digestAlgorithms.?%d.algorithm", i + 1); ++ if (!da_path) ++ { ++ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not allocate path for digest algorithm " ++ "parsing path"); ++ goto cleanup_signed_part; ++ } ++ ++ algo_oid_size = sizeof (algo_oid); ++ res = asn1_read_value (signed_part, da_path, algo_oid, &algo_oid_size); ++ if (res != ASN1_SUCCESS) ++ { ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error reading digest algorithm: %s", ++ asn1_strerror (res)); ++ grub_free (da_path); ++ goto cleanup_signed_part; ++ } ++ ++ if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0) ++ { ++ if (!sha512_in_da) ++ sha512_in_da = true; ++ else ++ { ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "SHA-512 specified twice in digest algorithm list"); ++ grub_free (da_path); ++ goto cleanup_signed_part; ++ } ++ } ++ else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 0) ++ { ++ if (!sha256_in_da) ++ sha256_in_da = true; ++ else ++ { ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "SHA-256 specified twice in digest algorithm list"); ++ grub_free (da_path); ++ goto cleanup_signed_part; ++ } ++ } ++ else ++ { ++ err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "Only SHA-256 and SHA-512 hashes are supported, found OID %s", ++ algo_oid); ++ grub_free (da_path); ++ goto cleanup_signed_part; ++ } ++ ++ grub_free (da_path); + } + ++ /* at this point, at least one of sha{256,512}_in_da must be true */ ++ + /* + * We ignore the certificates, but we don't permit CRLs. + * A CRL entry might be revoking the certificate we're using, and we have +@@ -175,45 +201,179 @@ process_content (grub_uint8_t * content, int size, + res = asn1_read_value (signed_part, "crls", NULL, &crls_size); + if (res != ASN1_ELEMENT_NOT_FOUND) + { +- err = +- grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, +- "PKCS#7 messages with embedded CRLs are not supported"); ++ err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ "PKCS#7 messages with embedded CRLs are not supported"); + goto cleanup_signed_part; + } + +- /* read the signature */ +- result_buf = +- grub_asn1_allocate_and_read (signed_part, "signerInfos.?1.signature", +- "signature data", &result_size); +- if (!result_buf) ++ /* read the signatures */ ++ ++ res = asn1_number_of_elements (signed_part, "signerInfos", &signer_count); ++ if (res != ASN1_SUCCESS) + { +- err = grub_errno; ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error counting number of signers: %s", ++ asn1_strerror (res)); + goto cleanup_signed_part; + } + +- gcry_err = +- gcry_mpi_scan (&(msg->sig_mpi), GCRYMPI_FMT_USG, result_buf, result_size, +- NULL); +- if (gcry_err != GPG_ERR_NO_ERROR) ++ if (signer_count <= 0) + { +- err = +- grub_error (GRUB_ERR_BAD_SIGNATURE, +- "Error loading signature into MPI structure: %d", +- gcry_err); +- goto cleanup_result; ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, "A minimum of 1 signer is required"); ++ goto cleanup_signed_part; + } + +-cleanup_result: +- grub_free (result_buf); ++ msg->signerInfos = grub_calloc (signer_count, sizeof (struct pkcs7_signerInfo)); ++ if (!msg->signerInfos) ++ { ++ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not allocate space for %d signers", signer_count); ++ goto cleanup_signed_part; ++ } ++ ++ msg->signerInfo_count = 0; ++ for (i = 0; i < signer_count; i++) ++ { ++ si_da_path = grub_xasprintf ("signerInfos.?%d.digestAlgorithm.algorithm", i + 1); ++ if (!si_da_path) ++ { ++ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not allocate path for signer %d's digest algorithm parsing path", ++ i); ++ goto cleanup_signerInfos; ++ } ++ ++ algo_oid_size = sizeof (algo_oid); ++ res = asn1_read_value (signed_part, si_da_path, algo_oid, &algo_oid_size); ++ if (res != ASN1_SUCCESS) ++ { ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Error reading signer %d's digest algorithm: %s", i, ++ asn1_strerror (res)); ++ grub_free (si_da_path); ++ goto cleanup_signerInfos; ++ } ++ ++ grub_free (si_da_path); ++ ++ if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0) ++ { ++ if (!sha512_in_da) ++ { ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Signer %d claims a SHA-512 signature which was not specified in the outer DigestAlgorithms", ++ i); ++ goto cleanup_signerInfos; ++ } ++ else ++ { ++ sha512_in_si = true; ++ msg->signerInfos[i].hash = grub_crypto_lookup_md_by_name ("sha512"); ++ } ++ } ++ else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 0) ++ { ++ if (!sha256_in_da) ++ { ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Signer %d claims a SHA-256 signature which was not specified in the outer DigestAlgorithms", ++ i); ++ goto cleanup_signerInfos; ++ } ++ else ++ { ++ sha256_in_si = true; ++ msg->signerInfos[i].hash = grub_crypto_lookup_md_by_name ("sha256"); ++ } ++ } ++ else ++ { ++ err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ "Only SHA-256 and SHA-512 hashes are supported, found OID %s", ++ algo_oid); ++ goto cleanup_signerInfos; ++ } ++ ++ if (!msg->signerInfos[i].hash) ++ { ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Hash algorithm for signer %d (OID %s) not loaded", i, algo_oid); ++ goto cleanup_signerInfos; ++ } ++ ++ si_sig_path = grub_xasprintf ("signerInfos.?%d.signature", i + 1); ++ if (!si_sig_path) ++ { ++ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not allocate path for signer %d's signature parsing path", i); ++ goto cleanup_signerInfos; ++ } ++ ++ result_buf = grub_asn1_allocate_and_read (signed_part, si_sig_path, ++ "signature data", &result_size); ++ grub_free (si_sig_path); ++ ++ if (!result_buf) ++ { ++ err = grub_errno; ++ goto cleanup_signerInfos; ++ } ++ ++ gcry_err = gcry_mpi_scan (&(msg->signerInfos[i].sig_mpi), GCRYMPI_FMT_USG, ++ result_buf, result_size, NULL); ++ ++ grub_free (result_buf); ++ ++ if (gcry_err != GPG_ERR_NO_ERROR) ++ { ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Error loading signature %d into MPI structure: %d", ++ i, gcry_err); ++ goto cleanup_signerInfos; ++ } ++ ++ /* ++ * use msg->signerInfo_count to track fully populated signerInfos so we ++ * know how many we need to clean up ++ */ ++ msg->signerInfo_count++; ++ } ++ ++ /* ++ * Final consistency check of signerInfo.*.digestAlgorithm vs ++ * digestAlgorithms.*.algorithm. An algorithm must be present in both ++ * digestAlgorithms and signerInfo or in neither. We have already checked ++ * for an algorithm in signerInfo that is not in digestAlgorithms, here we ++ * check for algorithms in digestAlgorithms but not in signerInfos. ++ */ ++ if (sha512_in_da && !sha512_in_si) ++ { ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "SHA-512 specified in DigestAlgorithms but did not " ++ "appear in SignerInfos"); ++ goto cleanup_signerInfos; ++ } ++ ++ if (sha256_in_da && !sha256_in_si) ++ { ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "SHA-256 specified in DigestAlgorithms but did not " ++ "appear in SignerInfos"); ++ goto cleanup_signerInfos; ++ } ++ ++ asn1_delete_structure (&signed_part); ++ return GRUB_ERR_NONE; ++ ++cleanup_signerInfos: ++ for (i = 0; i < msg->signerInfo_count; i++) ++ gcry_mpi_release (msg->signerInfos[i].sig_mpi); ++ grub_free (msg->signerInfos); + cleanup_signed_part: + asn1_delete_structure (&signed_part); +- + return err; + } + + grub_err_t +-parse_pkcs7_signedData (void *sigbuf, grub_size_t data_size, +- struct pkcs7_signedData *msg) ++parse_pkcs7_signedData (const void *sigbuf, grub_size_t data_size, struct pkcs7_signedData *msg) + { + int res; + asn1_node content_info; +@@ -225,26 +385,23 @@ parse_pkcs7_signedData (void *sigbuf, grub_size_t data_size, + int size; + + if (data_size > GRUB_INT_MAX) +- return grub_error (GRUB_ERR_OUT_OF_RANGE, +- "Cannot parse a PKCS#7 message where data size > INT_MAX"); ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, "Cannot parse a PKCS#7 message " ++ "where data size > INT_MAX"); + size = (int) data_size; + +- res = asn1_create_element (_gnutls_pkix_asn, +- "PKIX1.pkcs-7-ContentInfo", &content_info); ++ res = asn1_create_element (_gnutls_pkix_asn, "PKIX1.pkcs-7-ContentInfo", &content_info); + if (res != ASN1_SUCCESS) +- { +- return grub_error (GRUB_ERR_OUT_OF_MEMORY, +- "Could not create ASN.1 structure for PKCS#7 data: %s", +- asn1_strerror (res)); +- } ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not create ASN.1 structure for PKCS#7 data: %s", ++ asn1_strerror (res)); + + res = asn1_der_decoding2 (&content_info, sigbuf, &size, +- ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ ASN1_DECODE_FLAG_STRICT_DER | ASN1_DECODE_FLAG_ALLOW_PADDING, ++ asn1_error); + if (res != ASN1_SUCCESS) + { +- err = +- grub_error (GRUB_ERR_BAD_SIGNATURE, +- "Error decoding PKCS#7 message DER: %s", asn1_error); ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Error decoding PKCS#7 message DER: %s", asn1_error); + goto cleanup; + } + +@@ -255,31 +412,24 @@ parse_pkcs7_signedData (void *sigbuf, grub_size_t data_size, + * + * ContentType ::= OBJECT IDENTIFIER + */ +- res = +- asn1_read_value (content_info, "contentType", content_oid, +- &content_oid_size); ++ res = asn1_read_value (content_info, "contentType", content_oid, &content_oid_size); + if (res != ASN1_SUCCESS) + { +- err = +- grub_error (GRUB_ERR_BAD_SIGNATURE, +- "Error reading PKCS#7 content type: %s", +- asn1_strerror (res)); ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, "Error reading PKCS#7 content type: %s", ++ asn1_strerror (res)); + goto cleanup; + } + + /* OID for SignedData defined in 5.1 */ + if (grub_strncmp (signedData_oid, content_oid, content_oid_size) != 0) + { +- err = +- grub_error (GRUB_ERR_BAD_SIGNATURE, +- "Unexpected content type in PKCS#7 message: OID %s", +- content_oid); ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Unexpected content type in PKCS#7 message: OID %s", content_oid); + goto cleanup; + } + +- content = +- grub_asn1_allocate_and_read (content_info, "content", +- "PKCS#7 message content", &content_size); ++ content = grub_asn1_allocate_and_read (content_info, "content", ++ "PKCS#7 message content", &content_size); + if (!content) + { + err = grub_errno; +@@ -301,5 +451,10 @@ cleanup: + void + pkcs7_signedData_release (struct pkcs7_signedData *msg) + { +- gcry_mpi_release (msg->sig_mpi); ++ grub_ssize_t i; ++ ++ for (i = 0; i < msg->signerInfo_count; i++) ++ gcry_mpi_release (msg->signerInfos[i].sig_mpi); ++ ++ grub_free (msg->signerInfos); + } +diff --git a/grub-core/commands/appendedsig/x509.c b/grub-core/commands/appendedsig/x509.c +index 42ec65c..eb87025 100644 +--- a/grub-core/commands/appendedsig/x509.c ++++ b/grub-core/commands/appendedsig/x509.c +@@ -1,6 +1,7 @@ + /* + * GRUB -- GRand Unified Bootloader +- * Copyright (C) 2020 IBM Corporation. ++ * Copyright (C) 2020, 2022 Free Software Foundation, Inc. ++ * Copyright (C) 2020, 2022 IBM Corporation + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -21,6 +22,7 @@ + #include + #include + #include ++#include + #include + + #include "appendedsig.h" +@@ -30,28 +32,30 @@ static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; + /* + * RFC 3279 2.3.1 RSA Keys + */ +-const char *rsaEncryption_oid = "1.2.840.113549.1.1.1"; ++static const char *rsaEncryption_oid = "1.2.840.113549.1.1.1"; + + /* + * RFC 5280 Appendix A + */ +-const char *commonName_oid = "2.5.4.3"; ++static const char *commonName_oid = "2.5.4.3"; + + /* + * RFC 5280 4.2.1.3 Key Usage + */ +-const char *keyUsage_oid = "2.5.29.15"; ++static const char *keyUsage_oid = "2.5.29.15"; ++ ++static const grub_uint8_t digitalSignatureUsage = 0x80; + + /* + * RFC 5280 4.2.1.9 Basic Constraints + */ +-const char *basicConstraints_oid = "2.5.29.19"; ++static const char *basicConstraints_oid = "2.5.29.19"; + + /* + * RFC 5280 4.2.1.12 Extended Key Usage + */ +-const char *extendedKeyUsage_oid = "2.5.29.37"; +-const char *codeSigningUsage_oid = "1.3.6.1.5.5.7.3.3"; ++static const char *extendedKeyUsage_oid = "2.5.29.37"; ++static const char *codeSigningUsage_oid = "1.3.6.1.5.5.7.3.3"; + + /* + * RFC 3279 2.3.1 +@@ -66,46 +70,37 @@ const char *codeSigningUsage_oid = "1.3.6.1.5.5.7.3.3"; + * exponent e. + */ + static grub_err_t +-grub_parse_rsa_pubkey (grub_uint8_t * der, int dersize, +- struct x509_certificate *certificate) ++grub_parse_rsa_pubkey (grub_uint8_t *der, int dersize, struct x509_certificate *certificate) + { + int result; +- asn1_node spk = ASN1_TYPE_EMPTY; ++ asn1_node spk = NULL; + grub_uint8_t *m_data, *e_data; + int m_size, e_size; + grub_err_t err = GRUB_ERR_NONE; + gcry_error_t gcry_err; + +- result = +- asn1_create_element (_gnutls_gnutls_asn, "GNUTLS.RSAPublicKey", &spk); ++ result = asn1_create_element (_gnutls_gnutls_asn, "GNUTLS.RSAPublicKey", &spk); + if (result != ASN1_SUCCESS) +- { +- return grub_error (GRUB_ERR_OUT_OF_MEMORY, +- "Cannot create storage for public key ASN.1 data"); +- } ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Cannot create storage for public key ASN.1 data"); + +- result = asn1_der_decoding2 (&spk, der, &dersize, +- ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ result = asn1_der_decoding2 (&spk, der, &dersize, ASN1_DECODE_FLAG_STRICT_DER, asn1_error); + if (result != ASN1_SUCCESS) + { +- err = +- grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Cannot decode certificate public key DER: %s", +- asn1_error); ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Cannot decode certificate public key DER: %s", asn1_error); + goto cleanup; + } + +- m_data = +- grub_asn1_allocate_and_read (spk, "modulus", "RSA modulus", &m_size); ++ m_data = grub_asn1_allocate_and_read (spk, "modulus", "RSA modulus", &m_size); + if (!m_data) + { + err = grub_errno; + goto cleanup; + } + +- e_data = +- grub_asn1_allocate_and_read (spk, "publicExponent", "RSA public exponent", +- &e_size); ++ e_data = grub_asn1_allocate_and_read (spk, "publicExponent", ++ "RSA public exponent", &e_size); + if (!e_data) + { + err = grub_errno; +@@ -115,30 +110,22 @@ grub_parse_rsa_pubkey (grub_uint8_t * der, int dersize, + /* + * convert m, e to mpi + * +- * nscanned is not set for FMT_USG, it's only set for FMT_PGP, ++ * nscanned is not set for FMT_USG, it's only set for FMT_PGP, + * so we can't verify it + */ +- gcry_err = +- gcry_mpi_scan (&certificate->mpis[0], GCRYMPI_FMT_USG, m_data, m_size, +- NULL); ++ gcry_err = gcry_mpi_scan (&certificate->mpis[0], GCRYMPI_FMT_USG, m_data, m_size, NULL); + if (gcry_err != GPG_ERR_NO_ERROR) + { +- err = +- grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Error loading RSA modulus into MPI structure: %d", +- gcry_err); ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error loading RSA modulus into MPI structure: %d", gcry_err); + goto cleanup_e_data; + } + +- gcry_err = +- gcry_mpi_scan (&certificate->mpis[1], GCRYMPI_FMT_USG, e_data, e_size, +- NULL); ++ gcry_err = gcry_mpi_scan (&certificate->mpis[1], GCRYMPI_FMT_USG, e_data, e_size, NULL); + if (gcry_err != GPG_ERR_NO_ERROR) + { +- err = +- grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Error loading RSA exponent into MPI structure: %d", +- gcry_err); ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error loading RSA exponent into MPI structure: %d", gcry_err); + goto cleanup_m_mpi; + } + +@@ -158,7 +145,6 @@ cleanup: + return err; + } + +- + /* + * RFC 5280: + * SubjectPublicKeyInfo ::= SEQUENCE { +@@ -170,17 +156,15 @@ cleanup: + */ + + static grub_err_t +-grub_x509_read_subject_public_key (asn1_node asn, +- struct x509_certificate *results) ++grub_x509_read_subject_public_key (asn1_node asn, struct x509_certificate *results) + { + int result; + grub_err_t err; + const char *algo_name = +- "tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm"; ++ "tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm"; + const char *params_name = +- "tbsCertificate.subjectPublicKeyInfo.algorithm.parameters"; +- const char *pk_name = +- "tbsCertificate.subjectPublicKeyInfo.subjectPublicKey"; ++ "tbsCertificate.subjectPublicKeyInfo.algorithm.parameters"; ++ const char *pk_name = "tbsCertificate.subjectPublicKeyInfo.subjectPublicKey"; + char algo_oid[MAX_OID_LEN]; + int algo_size = sizeof (algo_oid); + char params_value[2]; +@@ -192,21 +176,14 @@ grub_x509_read_subject_public_key (asn1_node asn, + /* algorithm: see notes for rsaEncryption_oid */ + result = asn1_read_value (asn, algo_name, algo_oid, &algo_size); + if (result != ASN1_SUCCESS) +- { +- return grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Error reading x509 public key algorithm: %s", +- asn1_strerror (result)); +- } ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading x509 public key algorithm: %s", ++ asn1_strerror (result)); + +- if (grub_strncmp (algo_oid, rsaEncryption_oid, sizeof (rsaEncryption_oid)) +- != 0) +- { +- return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, +- "Unsupported x509 public key algorithm: %s", +- algo_oid); +- } ++ if (grub_strncmp (algo_oid, rsaEncryption_oid, sizeof (rsaEncryption_oid)) != 0) ++ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ "Unsupported x509 public key algorithm: %s", algo_oid); + +- /* ++ /* + * RFC 3279 2.3.1 + * The rsaEncryption OID is intended to be used in the algorithm field + * of a value of type AlgorithmIdentifier. The parameters field MUST +@@ -214,17 +191,12 @@ grub_x509_read_subject_public_key (asn1_node asn, + */ + result = asn1_read_value (asn, params_name, params_value, ¶ms_size); + if (result != ASN1_SUCCESS) +- { +- return grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Error reading x509 public key parameters: %s", +- asn1_strerror (result)); +- } ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading x509 public key parameters: %s", ++ asn1_strerror (result)); + + if (params_value[0] != ASN1_TAG_NULL) +- { +- return grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Invalid x509 public key parameters: expected NULL"); +- } ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Invalid x509 public key parameters: expected NULL"); + + /* + * RFC 3279 2.3.1: The DER encoded RSAPublicKey is the value of the BIT +@@ -232,34 +204,26 @@ grub_x509_read_subject_public_key (asn1_node asn, + */ + result = asn1_read_value_type (asn, pk_name, NULL, &key_size, &key_type); + if (result != ASN1_MEM_ERROR) +- { +- return grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Error reading size of x509 public key: %s", +- asn1_strerror (result)); +- } ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading size of x509 public key: %s", ++ asn1_strerror (result)); + if (key_type != ASN1_ETYPE_BIT_STRING) +- { +- return grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Unexpected ASN.1 type when reading x509 public key: %x", +- key_type); +- } ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected ASN.1 type when reading x509 public key: %x", ++ key_type); + + /* length is in bits */ + key_size = (key_size + 7) / 8; + + key_data = grub_malloc (key_size); + if (!key_data) +- { +- return grub_error (GRUB_ERR_OUT_OF_MEMORY, +- "Out of memory for x509 public key"); +- } ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Out of memory for x509 public key"); + + result = asn1_read_value (asn, pk_name, key_data, &key_size); + if (result != ASN1_SUCCESS) + { + grub_free (key_data); + return grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Error reading public key data"); ++ "Error reading public key data"); + } + key_size = (key_size + 7) / 8; + +@@ -271,8 +235,7 @@ grub_x509_read_subject_public_key (asn1_node asn, + + /* Decode a string as defined in Appendix A */ + static grub_err_t +-decode_string (char *der, int der_size, char **string, +- grub_size_t * string_size) ++decode_string (char *der, int der_size, char **string, grub_size_t *string_size) + { + asn1_node strasn; + int result; +@@ -281,51 +244,51 @@ decode_string (char *der, int der_size, char **string, + int tmp_size = 0; + grub_err_t err = GRUB_ERR_NONE; + +- result = +- asn1_create_element (_gnutls_pkix_asn, "PKIX1.DirectoryString", &strasn); ++ result = asn1_create_element (_gnutls_pkix_asn, "PKIX1.DirectoryString", &strasn); + if (result != ASN1_SUCCESS) +- { +- return grub_error (GRUB_ERR_OUT_OF_MEMORY, +- "Could not create ASN.1 structure for certificate: %s", +- asn1_strerror (result)); +- } ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not create ASN.1 structure for certificate: %s", ++ asn1_strerror (result)); + +- result = asn1_der_decoding2 (&strasn, der, &der_size, +- ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ result = asn1_der_decoding2 (&strasn, der, &der_size, ASN1_DECODE_FLAG_STRICT_DER, asn1_error); + if (result != ASN1_SUCCESS) + { +- err = +- grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Could not parse DER for DirectoryString: %s", +- asn1_error); ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Could not parse DER for DirectoryString: %s", asn1_error); + goto cleanup; + } + +- choice = +- grub_asn1_allocate_and_read (strasn, "", "DirectoryString choice", +- &choice_size); ++ choice = grub_asn1_allocate_and_read (strasn, "", "DirectoryString choice", &choice_size); + if (!choice) + { + err = grub_errno; + goto cleanup; + } + +- if (grub_strncmp ("utf8String", choice, choice_size)) ++ if (grub_strncmp ("utf8String", choice, choice_size) == 0) + { +- err = +- grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, +- "Only UTF-8 DirectoryStrings are supported, got %s", +- choice); +- goto cleanup_choice; ++ result = asn1_read_value (strasn, "utf8String", NULL, &tmp_size); ++ if (result != ASN1_MEM_ERROR) ++ { ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading size of UTF-8 string: %s", ++ asn1_strerror (result)); ++ goto cleanup_choice; ++ } + } +- +- result = asn1_read_value (strasn, "utf8String", NULL, &tmp_size); +- if (result != ASN1_MEM_ERROR) ++ else if (grub_strncmp ("printableString", choice, choice_size) == 0) + { +- err = +- grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Error reading size of UTF-8 string: %s", +- asn1_strerror (result)); ++ result = asn1_read_value (strasn, "printableString", NULL, &tmp_size); ++ if (result != ASN1_MEM_ERROR) ++ { ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading size of UTF-8 string: %s", ++ asn1_strerror (result)); ++ goto cleanup_choice; ++ } ++ } ++ else ++ { ++ err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "Only UTF-8 and printable DirectoryStrings are supported, got %s", ++ choice); + goto cleanup_choice; + } + +@@ -335,20 +298,18 @@ decode_string (char *der, int der_size, char **string, + *string = grub_malloc (tmp_size); + if (!*string) + { +- err = +- grub_error (GRUB_ERR_OUT_OF_MEMORY, +- "Cannot allocate memory for DirectoryString contents"); ++ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Cannot allocate memory for DirectoryString contents"); + goto cleanup_choice; + } + +- result = asn1_read_value (strasn, "utf8String", *string, &tmp_size); ++ result = asn1_read_value (strasn, choice, *string, &tmp_size); + if (result != ASN1_SUCCESS) + { +- err = +- grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Error reading out UTF-8 string in DirectoryString: %s", +- asn1_strerror (result)); ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading out %s in DirectoryString: %s", ++ choice, asn1_strerror (result)); + grub_free (*string); ++ *string = NULL; + goto cleanup_choice; + } + *string_size = tmp_size + 1; +@@ -365,7 +326,7 @@ cleanup: + * TBSCertificate ::= SEQUENCE { + * version [0] EXPLICIT Version DEFAULT v1, + * ... +- * ++ * + * Version ::= INTEGER { v1(0), v2(1), v3(2) } + */ + static grub_err_t +@@ -374,19 +335,18 @@ check_version (asn1_node certificate) + int rc; + const char *name = "tbsCertificate.version"; + grub_uint8_t version; +- int len = 1; ++ int len = sizeof (version); + + rc = asn1_read_value (certificate, name, &version, &len); + + /* require version 3 */ + if (rc != ASN1_SUCCESS || len != 1) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Error reading certificate version"); ++ "Error reading certificate version"); + + if (version != 0x02) +- return grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Invalid x509 certificate version, expected v3 (0x02), got 0x%02x", +- version); ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Invalid x509 certificate version, expected v3 (0x02), got 0x%02x", ++ version); + + return GRUB_ERR_NONE; + } +@@ -397,8 +357,7 @@ check_version (asn1_node certificate) + * For simplicity, we extract only the CN. + */ + static grub_err_t +-read_name (asn1_node asn, const char *name_path, char **name, +- grub_size_t * name_size) ++read_name (asn1_node asn, const char *name_path, char **name, grub_size_t *name_size) + { + int seq_components, set_components; + int result; +@@ -415,16 +374,13 @@ read_name (asn1_node asn, const char *name_path, char **name, + top_path = grub_xasprintf ("%s.rdnSequence", name_path); + if (!top_path) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, +- "Could not allocate memory for %s name parsing path", +- name_path); ++ "Could not allocate memory for %s name parsing path", name_path); + + result = asn1_number_of_elements (asn, top_path, &seq_components); + if (result != ASN1_SUCCESS) + { +- err = +- grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Error counting name components: %s", +- asn1_strerror (result)); ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error counting name components: %s", ++ asn1_strerror (result)); + goto cleanup; + } + +@@ -432,85 +388,75 @@ read_name (asn1_node asn, const char *name_path, char **name, + { + set_path = grub_xasprintf ("%s.?%d", top_path, i); + if (!set_path) +- { +- err = +- grub_error (GRUB_ERR_OUT_OF_MEMORY, +- "Could not allocate memory for %s name set parsing path", +- name_path); +- goto cleanup_set; +- } ++ { ++ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not allocate memory for %s name set parsing path", ++ name_path); ++ goto cleanup_set; ++ } + /* this brings us, hopefully, to a set */ + result = asn1_number_of_elements (asn, set_path, &set_components); + if (result != ASN1_SUCCESS) +- { +- err = +- grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Error counting name sub-components components (element %d): %s", +- i, asn1_strerror (result)); +- goto cleanup_set; +- } ++ { ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error counting name sub-components components (element %d): %s", ++ i, asn1_strerror (result)); ++ goto cleanup_set; ++ } + for (j = 1; j <= set_components; j++) +- { +- type_path = grub_xasprintf ("%s.?%d.?%d.type", top_path, i, j); +- if (!type_path) +- { +- err = +- grub_error (GRUB_ERR_OUT_OF_MEMORY, +- "Could not allocate memory for %s name component type path", +- name_path); +- goto cleanup_set; +- } +- type_len = sizeof (type); +- result = asn1_read_value (asn, type_path, type, &type_len); +- if (result != ASN1_SUCCESS) +- { +- err = +- grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Error reading %s name component type: %s", +- name_path, asn1_strerror (result)); +- goto cleanup_type; +- } ++ { ++ type_path = grub_xasprintf ("%s.?%d.?%d.type", top_path, i, j); ++ if (!type_path) ++ { ++ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not allocate memory for %s name component type path", ++ name_path); ++ goto cleanup_set; ++ } ++ type_len = sizeof (type); ++ result = asn1_read_value (asn, type_path, type, &type_len); ++ if (result != ASN1_SUCCESS) ++ { ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading %s name component type: %s", ++ name_path, asn1_strerror (result)); ++ goto cleanup_type; ++ } + +- if (grub_strncmp (type, commonName_oid, type_len) != 0) +- { +- grub_free (type_path); +- continue; +- } ++ if (grub_strncmp (type, commonName_oid, type_len) != 0) ++ { ++ grub_free (type_path); ++ continue; ++ } + +- val_path = grub_xasprintf ("%s.?%d.?%d.value", top_path, i, j); +- if (!val_path) +- { +- err = +- grub_error (GRUB_ERR_OUT_OF_MEMORY, +- "Could not allocate memory for %s name component value path", +- name_path); +- goto cleanup_set; +- } ++ val_path = grub_xasprintf ("%s.?%d.?%d.value", top_path, i, j); ++ if (!val_path) ++ { ++ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not allocate memory for %s name component value path", ++ name_path); ++ goto cleanup_type; ++ } + +- string_der = +- grub_asn1_allocate_and_read (asn, val_path, name_path, +- &string_size); +- if (!string_der) +- { +- err = grub_errno; +- goto cleanup_val_path; +- } ++ string_der = grub_asn1_allocate_and_read (asn, val_path, name_path, &string_size); ++ if (!string_der) ++ { ++ err = grub_errno; ++ goto cleanup_val_path; ++ } + +- err = decode_string (string_der, string_size, name, name_size); +- if (err) +- goto cleanup_string; ++ err = decode_string (string_der, string_size, name, name_size); ++ if (err) ++ goto cleanup_string; + +- grub_free (string_der); +- grub_free (type_path); +- grub_free (val_path); +- break; +- } ++ grub_free (string_der); ++ grub_free (type_path); ++ grub_free (val_path); ++ break; ++ } + grub_free (set_path); + + if (*name) +- break; ++ break; + } + ++ grub_free (top_path); ++ + return GRUB_ERR_NONE; + + cleanup_string: +@@ -527,51 +473,44 @@ cleanup: + } + + /* +- * details here ++ * Verify the Key Usage extension. ++ * We require the Digital Signature usage. + */ + static grub_err_t +-verify_key_usage (grub_uint8_t * value, int value_size) ++verify_key_usage (grub_uint8_t *value, int value_size) + { + asn1_node usageasn; + int result; + grub_err_t err = GRUB_ERR_NONE; + grub_uint8_t usage = 0xff; +- int usage_size = 1; ++ int usage_size = sizeof (usage_size); + +- result = +- asn1_create_element (_gnutls_pkix_asn, "PKIX1.KeyUsage", &usageasn); ++ result = asn1_create_element (_gnutls_pkix_asn, "PKIX1.KeyUsage", &usageasn); + if (result != ASN1_SUCCESS) +- { +- return grub_error (GRUB_ERR_OUT_OF_MEMORY, +- "Could not create ASN.1 structure for key usage"); +- } ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not create ASN.1 structure for key usage"); + + result = asn1_der_decoding2 (&usageasn, value, &value_size, +- ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ ASN1_DECODE_FLAG_STRICT_DER, asn1_error); + if (result != ASN1_SUCCESS) + { +- err = +- grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Error parsing DER for Key Usage: %s", asn1_error); ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error parsing DER for Key Usage: %s", asn1_error); + goto cleanup; + } + + result = asn1_read_value (usageasn, "", &usage, &usage_size); + if (result != ASN1_SUCCESS) + { +- err = +- grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Error reading Key Usage value: %s", +- asn1_strerror (result)); ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading Key Usage value: %s", ++ asn1_strerror (result)); + goto cleanup; + } + +- /* Only the first bit is permitted to be set */ +- if (usage != 0x80) ++ if (!(usage & digitalSignatureUsage)) + { +- err = +- grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected Key Usage value: %x", +- usage); ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Key Usage (0x%x) missing Digital Signature usage", usage); + goto cleanup; + } + +@@ -586,31 +525,25 @@ cleanup: + * pathLenConstraint INTEGER (0..MAX) OPTIONAL } + */ + static grub_err_t +-verify_basic_constraints (grub_uint8_t * value, int value_size) ++verify_basic_constraints (grub_uint8_t *value, int value_size) + { + asn1_node basicasn; + int result; + grub_err_t err = GRUB_ERR_NONE; +- char cA[6]; /* FALSE or TRUE */ ++ char cA[6]; /* FALSE or TRUE */ + int cA_size = sizeof (cA); + +- result = +- asn1_create_element (_gnutls_pkix_asn, "PKIX1.BasicConstraints", +- &basicasn); ++ result = asn1_create_element (_gnutls_pkix_asn, "PKIX1.BasicConstraints", &basicasn); + if (result != ASN1_SUCCESS) +- { +- return grub_error (GRUB_ERR_OUT_OF_MEMORY, +- "Could not create ASN.1 structure for Basic Constraints"); +- } ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not create ASN.1 structure for Basic Constraints"); + + result = asn1_der_decoding2 (&basicasn, value, &value_size, +- ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ ASN1_DECODE_FLAG_STRICT_DER, asn1_error); + if (result != ASN1_SUCCESS) + { +- err = +- grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Error parsing DER for Basic Constraints: %s", +- asn1_error); ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error parsing DER for Basic Constraints: %s", asn1_error); + goto cleanup; + } + +@@ -623,18 +556,15 @@ verify_basic_constraints (grub_uint8_t * value, int value_size) + } + else if (result != ASN1_SUCCESS) + { +- err = +- grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Error reading Basic Constraints cA value: %s", +- asn1_strerror (result)); ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading Basic Constraints cA value: %s", ++ asn1_strerror (result)); + goto cleanup; + } + + /* The certificate must not be a CA certificate */ + if (grub_strncmp ("FALSE", cA, cA_size) != 0) + { +- err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected CA value: %s", +- cA); ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected CA value: %s", cA); + goto cleanup; + } + +@@ -644,72 +574,64 @@ cleanup: + } + + /* ++ * Verify the Extended Key Usage extension. ++ * We require the Code Signing usage. ++ * + * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId + * + * KeyPurposeId ::= OBJECT IDENTIFIER + */ + static grub_err_t +-verify_extended_key_usage (grub_uint8_t * value, int value_size) ++verify_extended_key_usage (grub_uint8_t *value, int value_size) + { + asn1_node extendedasn; +- int result, count; ++ int result, count, i = 0; + grub_err_t err = GRUB_ERR_NONE; +- char usage[MAX_OID_LEN]; ++ char usage[MAX_OID_LEN], name[3]; + int usage_size = sizeof (usage); + +- result = +- asn1_create_element (_gnutls_pkix_asn, "PKIX1.ExtKeyUsageSyntax", +- &extendedasn); ++ result = asn1_create_element (_gnutls_pkix_asn, "PKIX1.ExtKeyUsageSyntax", &extendedasn); + if (result != ASN1_SUCCESS) +- { +- return grub_error (GRUB_ERR_OUT_OF_MEMORY, +- "Could not create ASN.1 structure for Extended Key Usage"); +- } ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not create ASN.1 structure for Extended Key Usage"); + + result = asn1_der_decoding2 (&extendedasn, value, &value_size, +- ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ ASN1_DECODE_FLAG_STRICT_DER, asn1_error); + if (result != ASN1_SUCCESS) + { +- err = +- grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Error parsing DER for Extended Key Usage: %s", +- asn1_error); ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error parsing DER for Extended Key Usage: %s", asn1_error); + goto cleanup; + } + +- /* +- * If EKUs are present, there must be exactly 1 and it must be a +- * codeSigning usage. +- */ +- result = asn1_number_of_elements(extendedasn, "", &count); ++ /* If EKUs are present, it checks the presents of Code Signing usage */ ++ result = asn1_number_of_elements (extendedasn, "", &count); + if (result != ASN1_SUCCESS) + { +- err = +- grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Error counting number of Extended Key Usages: %s", +- asn1_strerror (result)); ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error counting number of Extended Key Usages: %s", ++ asn1_strerror (result)); + goto cleanup; + } + +- result = asn1_read_value (extendedasn, "?1", usage, &usage_size); +- if (result != ASN1_SUCCESS) +- { +- err = +- grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Error reading Extended Key Usage: %s", +- asn1_strerror (result)); +- goto cleanup; +- } + +- if (grub_strncmp (codeSigningUsage_oid, usage, usage_size) != 0) ++ for (i = 1; i < count + 1; i++) + { +- err = +- grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Unexpected Extended Key Usage OID, got: %s", +- usage); +- goto cleanup; ++ grub_memset (name, 0, sizeof (name)); ++ grub_snprintf (name, sizeof (name), "?%d", i); ++ result = asn1_read_value (extendedasn, name, usage, &usage_size); ++ if (result != ASN1_SUCCESS) ++ { ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading Extended Key Usage: %s", ++ asn1_strerror (result)); ++ goto cleanup; ++ } ++ ++ if (grub_strncmp (codeSigningUsage_oid, usage, usage_size) == 0) ++ goto cleanup; + } + ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Extended Key Usage missing Code Signing usage"); + cleanup: + asn1_delete_structure (&extendedasn); + return err; +@@ -727,10 +649,11 @@ cleanup: + * -- by extnID + * } + * +- * We require that a certificate: +- * - contain the Digital Signature usage only ++ * A certificate must: ++ * - contain the Digital Signature usage + * - not be a CA +- * - MUST not contain any other critical extensions (RFC 5280 s 4.2) ++ * - contain no extended usages, or contain the Code Signing extended usage ++ * - not contain any other critical extensions (RFC 5280 s 4.2) + */ + static grub_err_t + verify_extensions (asn1_node cert) +@@ -742,116 +665,110 @@ verify_extensions (asn1_node cert) + char extnID[MAX_OID_LEN]; + int extnID_size; + grub_err_t err; +- char critical[6]; /* we get either "TRUE" or "FALSE" */ ++ char critical[6]; /* we get either "TRUE" or "FALSE" */ + int critical_size; + grub_uint8_t *value; + int value_size; + +- result = +- asn1_number_of_elements (cert, "tbsCertificate.extensions", +- &num_extensions); ++ result = asn1_number_of_elements (cert, "tbsCertificate.extensions", &num_extensions); + if (result != ASN1_SUCCESS) +- { +- return grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Error counting number of extensions: %s", +- asn1_strerror (result)); +- } ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error counting number of extensions: %s", ++ asn1_strerror (result)); + + if (num_extensions < 2) +- { +- return grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Insufficient number of extensions for certificate, need at least 2, got %d", +- num_extensions); +- } ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Insufficient number of extensions for certificate, need at least 2, got %d", ++ num_extensions); + + for (ext = 1; ext <= num_extensions; ext++) + { + oid_path = grub_xasprintf ("tbsCertificate.extensions.?%d.extnID", ext); ++ if (!oid_path) ++ { ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error extension OID path is empty"); ++ return err; ++ } + + extnID_size = sizeof (extnID); + result = asn1_read_value (cert, oid_path, extnID, &extnID_size); +- if (result != GRUB_ERR_NONE) +- { +- err = +- grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Error reading extension OID: %s", +- asn1_strerror (result)); +- goto cleanup_oid_path; +- } ++ if (result != ASN1_SUCCESS) ++ { ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading extension OID: %s", ++ asn1_strerror (result)); ++ goto cleanup_oid_path; ++ } ++ ++ critical_path = grub_xasprintf ("tbsCertificate.extensions.?%d.critical", ext); ++ if (!critical_path) ++ { ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error critical path is empty"); ++ goto cleanup_oid_path; ++ } + +- critical_path = +- grub_xasprintf ("tbsCertificate.extensions.?%d.critical", ext); + critical_size = sizeof (critical); +- result = +- asn1_read_value (cert, critical_path, critical, &critical_size); ++ result = asn1_read_value (cert, critical_path, critical, &critical_size); + if (result == ASN1_ELEMENT_NOT_FOUND) +- { +- critical[0] = '\0'; +- } ++ critical[0] = '\0'; + else if (result != ASN1_SUCCESS) +- { +- err = +- grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Error reading extension criticality: %s", +- asn1_strerror (result)); +- goto cleanup_critical_path; +- } ++ { ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error reading extension criticality: %s", ++ asn1_strerror (result)); ++ goto cleanup_critical_path; ++ } + +- value_path = +- grub_xasprintf ("tbsCertificate.extensions.?%d.extnValue", ext); +- value = +- grub_asn1_allocate_and_read (cert, value_path, +- "certificate extension value", +- &value_size); ++ value_path = grub_xasprintf ("tbsCertificate.extensions.?%d.extnValue", ext); ++ if (!value_path) ++ { ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Error extnValue path is empty"); ++ goto cleanup_critical_path; ++ } ++ ++ value = grub_asn1_allocate_and_read (cert, value_path, ++ "certificate extension value", &value_size); + if (!value) +- { +- err = grub_errno; +- goto cleanup_value_path; +- } ++ { ++ err = grub_errno; ++ goto cleanup_value_path; ++ } + + /* + * Now we must see if we recognise the OID. + * If we have an unrecognised critical extension we MUST bail. + */ + if (grub_strncmp (keyUsage_oid, extnID, extnID_size) == 0) +- { +- err = verify_key_usage (value, value_size); +- if (err != GRUB_ERR_NONE) +- { +- goto cleanup_value; +- } +- usage_present++; +- } ++ { ++ err = verify_key_usage (value, value_size); ++ if (err != GRUB_ERR_NONE) ++ goto cleanup_value; ++ ++ usage_present++; ++ } + else if (grub_strncmp (basicConstraints_oid, extnID, extnID_size) == 0) +- { +- err = verify_basic_constraints (value, value_size); +- if (err != GRUB_ERR_NONE) +- { +- goto cleanup_value; +- } +- constraints_present++; +- } ++ { ++ err = verify_basic_constraints (value, value_size); ++ if (err != GRUB_ERR_NONE) ++ goto cleanup_value; ++ ++ constraints_present++; ++ } + else if (grub_strncmp (extendedKeyUsage_oid, extnID, extnID_size) == 0) +- { +- err = verify_extended_key_usage (value, value_size); +- if (err != GRUB_ERR_NONE) +- { +- goto cleanup_value; +- } +- extended_usage_present++; +- } ++ { ++ err = verify_extended_key_usage (value, value_size); ++ if (err != GRUB_ERR_NONE) ++ goto cleanup_value; ++ ++ extended_usage_present++; ++ } + else if (grub_strncmp ("TRUE", critical, critical_size) == 0) +- { +- /* +- * per the RFC, we must not process a certificate with +- * a critical extension we do not understand. +- */ +- err = +- grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Unhandled critical x509 extension with OID %s", +- extnID); +- goto cleanup_value; +- } ++ { ++ /* ++ * per the RFC, we must not process a certificate with ++ * a critical extension we do not understand. ++ */ ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Unhandled critical x509 extension with OID %s", extnID); ++ goto cleanup_value; ++ } + + grub_free (value); + grub_free (value_path); +@@ -860,23 +777,17 @@ verify_extensions (asn1_node cert) + } + + if (usage_present != 1) +- { +- return grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Unexpected number of Key Usage extensions - expected 1, got %d", +- usage_present); +- } ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected number of Key Usage extensions " ++ "- expected 1, got %d", usage_present); ++ + if (constraints_present != 1) +- { +- return grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Unexpected number of basic constraints extensions - expected 1, got %d", +- constraints_present); +- } ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected number of basic constraints extensions " ++ "- expected 1, got %d", constraints_present); ++ + if (extended_usage_present > 1) +- { +- return grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Unexpected number of Extended Key Usage extensions - expected 0 or 1, got %d", +- extended_usage_present); +- } ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected number of Extended Key Usage extensions " ++ "- expected 0 or 1, got %d", extended_usage_present); ++ + return GRUB_ERR_NONE; + + cleanup_value: +@@ -887,6 +798,7 @@ cleanup_critical_path: + grub_free (critical_path); + cleanup_oid_path: + grub_free (oid_path); ++ + return err; + } + +@@ -895,8 +807,7 @@ cleanup_oid_path: + * Return the results in @results, which must point to an allocated x509 certificate. + */ + grub_err_t +-certificate_import (void *data, grub_size_t data_size, +- struct x509_certificate *results) ++parse_x509_certificate (const void *data, grub_size_t data_size, struct x509_certificate *results) + { + int result = 0; + asn1_node cert; +@@ -906,45 +817,38 @@ certificate_import (void *data, grub_size_t data_size, + + if (data_size > GRUB_INT_MAX) + return grub_error (GRUB_ERR_OUT_OF_RANGE, +- "Cannot parse a certificate where data size > INT_MAX"); ++ "Cannot parse a certificate where data size > INT_MAX"); + size = (int) data_size; + + result = asn1_create_element (_gnutls_pkix_asn, "PKIX1.Certificate", &cert); + if (result != ASN1_SUCCESS) +- { +- return grub_error (GRUB_ERR_OUT_OF_MEMORY, +- "Could not create ASN.1 structure for certificate: %s", +- asn1_strerror (result)); +- } ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not create ASN.1 structure for certificate: %s", ++ asn1_strerror (result)); + +- result = asn1_der_decoding2 (&cert, data, &size, +- ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ result = asn1_der_decoding2 (&cert, data, &size, ASN1_DECODE_FLAG_STRICT_DER, asn1_error); + if (result != ASN1_SUCCESS) + { +- err = +- grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "Could not parse DER for certificate: %s", asn1_error); ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Could not parse DER for certificate: %s", asn1_error); + goto cleanup; + } + +- /* ++ /* + * TBSCertificate ::= SEQUENCE { + * version [0] EXPLICIT Version DEFAULT v1 + */ + err = check_version (cert); + if (err != GRUB_ERR_NONE) +- { +- goto cleanup; +- } ++ goto cleanup; + + /* + * serialNumber CertificateSerialNumber, + * + * CertificateSerialNumber ::= INTEGER + */ +- results->serial = +- grub_asn1_allocate_and_read (cert, "tbsCertificate.serialNumber", +- "certificate serial number", &tmp_size); ++ results->serial = grub_asn1_allocate_and_read (cert, "tbsCertificate.serialNumber", ++ "certificate serial number", &tmp_size); + if (!results->serial) + { + err = grub_errno; +@@ -956,7 +860,7 @@ certificate_import (void *data, grub_size_t data_size, + */ + results->serial_len = tmp_size; + +- /* ++ /* + * signature AlgorithmIdentifier, + * + * We don't load the signature or issuer at the moment, +@@ -984,12 +888,10 @@ certificate_import (void *data, grub_size_t data_size, + + /* + * subject Name, +- * ++ * + * This is an X501 name, we parse out just the CN. + */ +- err = +- read_name (cert, "tbsCertificate.subject", &results->subject, +- &results->subject_len); ++ err = read_name (cert, "tbsCertificate.subject", &results->subject, &results->subject_len); + if (err != GRUB_ERR_NONE) + goto cleanup_serial; + +@@ -1013,8 +915,7 @@ certificate_import (void *data, grub_size_t data_size, + + err = verify_extensions (cert); + if (err != GRUB_ERR_NONE) +- goto cleanup_name; +- ++ goto cleanup_mpis; + + /* + * We do not read or check the signature on the certificate: +@@ -1025,7 +926,9 @@ certificate_import (void *data, grub_size_t data_size, + asn1_delete_structure (&cert); + return GRUB_ERR_NONE; + +- ++cleanup_mpis: ++ gcry_mpi_release (results->mpis[0]); ++ gcry_mpi_release (results->mpis[1]); + cleanup_name: + grub_free (results->subject); + cleanup_serial: diff --git a/SOURCES/0468-ieee1275-Platform-Keystore-PKS-Support.patch b/SOURCES/0468-ieee1275-Platform-Keystore-PKS-Support.patch new file mode 100644 index 0000000..feb14aa --- /dev/null +++ b/SOURCES/0468-ieee1275-Platform-Keystore-PKS-Support.patch @@ -0,0 +1,200 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sudhakar Kuppusamy +Date: Thu, 27 Mar 2025 01:02:35 +0530 +Subject: [PATCH] ieee1275: Platform Keystore (PKS) Support + +enhancing the infrastructure to enable the Platform Keystore (PKS) feature, +which provides access to the SB VERSION, DB, and DBX secure boot variables +from PKS. + +Signed-off-by: Sudhakar Kuppusamy +Reviewed-by: Stefan Berger +Reviewed-by: Avnish Chouhan +--- + grub-core/Makefile.core.def | 1 + + grub-core/kern/powerpc/ieee1275/ieee1275.c | 140 +++++++++++++++++++++++++++++ + include/grub/powerpc/ieee1275/ieee1275.h | 14 +++ + 3 files changed, 155 insertions(+) + create mode 100644 grub-core/kern/powerpc/ieee1275/ieee1275.c + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 3740330..05b9c8d 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -320,6 +320,7 @@ kernel = { + extra_dist = video/sis315_init.c; + mips_loongson = commands/keylayouts.c; + ++ powerpc_ieee1275 = kern/powerpc/ieee1275/ieee1275.c; + powerpc_ieee1275 = kern/powerpc/cache.S; + powerpc_ieee1275 = kern/powerpc/dl.c; + powerpc_ieee1275 = kern/powerpc/compiler-rt.S; +diff --git a/grub-core/kern/powerpc/ieee1275/ieee1275.c b/grub-core/kern/powerpc/ieee1275/ieee1275.c +new file mode 100644 +index 0000000..f685afc +--- /dev/null ++++ b/grub-core/kern/powerpc/ieee1275/ieee1275.c +@@ -0,0 +1,140 @@ ++/* of.c - Access the Open Firmware client interface. */ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++#include ++#include ++#include ++ ++#define IEEE1275_CELL_INVALID ((grub_ieee1275_cell_t) - 1) ++ ++int ++grub_ieee1275_test (const char *name, grub_ieee1275_cell_t *missing) ++{ ++ struct test_args ++ { ++ struct grub_ieee1275_common_hdr common; ++ grub_ieee1275_cell_t name; ++ grub_ieee1275_cell_t missing; ++ } args; ++ ++ INIT_IEEE1275_COMMON (&args.common, "test", 1, 1); ++ args.name = (grub_ieee1275_cell_t) name; ++ ++ if (IEEE1275_CALL_ENTRY_FN (&args) == -1) ++ return -1; ++ ++ if (args.missing == IEEE1275_CELL_INVALID) ++ return -1; ++ ++ *missing = args.missing; ++ ++ return 0; ++} ++ ++int ++grub_ieee1275_pks_max_object_size (grub_size_t *result) ++{ ++ struct mos_args ++ { ++ struct grub_ieee1275_common_hdr common; ++ grub_ieee1275_cell_t size; ++ } args; ++ ++ INIT_IEEE1275_COMMON (&args.common, "pks-max-object-size", 0, 1); ++ ++ if (IEEE1275_CALL_ENTRY_FN (&args) == -1) ++ return -1; ++ ++ if (args.size == IEEE1275_CELL_INVALID) ++ return -1; ++ ++ *result = args.size; ++ ++ return 0; ++} ++ ++int ++grub_ieee1275_pks_read_object (grub_uint8_t consumer, grub_uint8_t *label, ++ grub_size_t label_len, grub_uint8_t *buffer, ++ grub_size_t buffer_len, grub_size_t *data_len, ++ grub_uint32_t *policies) ++{ ++ struct pks_read_args ++ { ++ struct grub_ieee1275_common_hdr common; ++ grub_ieee1275_cell_t consumer; ++ grub_ieee1275_cell_t label; ++ grub_ieee1275_cell_t label_len; ++ grub_ieee1275_cell_t buffer; ++ grub_ieee1275_cell_t buffer_len; ++ grub_ieee1275_cell_t data_len; ++ grub_ieee1275_cell_t policies; ++ grub_ieee1275_cell_t rc; ++ } args; ++ ++ INIT_IEEE1275_COMMON (&args.common, "pks-read-object", 5, 3); ++ args.consumer = (grub_ieee1275_cell_t) consumer; ++ args.label = (grub_ieee1275_cell_t) label; ++ args.label_len = (grub_ieee1275_cell_t) label_len; ++ args.buffer = (grub_ieee1275_cell_t) buffer; ++ args.buffer_len = (grub_ieee1275_cell_t) buffer_len; ++ ++ if (IEEE1275_CALL_ENTRY_FN (&args) == -1) ++ return -1; ++ ++ if (args.data_len == IEEE1275_CELL_INVALID) ++ return -1; ++ ++ *data_len = args.data_len; ++ *policies = args.policies; ++ ++ return (int) args.rc; ++} ++ ++int ++grub_ieee1275_pks_read_sbvar (grub_uint8_t sbvarflags, grub_uint8_t sbvartype, ++ grub_uint8_t *buffer, grub_size_t buffer_len, ++ grub_size_t *data_len) ++{ ++ struct pks_read_sbvar_args ++ { ++ struct grub_ieee1275_common_hdr common; ++ grub_ieee1275_cell_t sbvarflags; ++ grub_ieee1275_cell_t sbvartype; ++ grub_ieee1275_cell_t buffer; ++ grub_ieee1275_cell_t buffer_len; ++ grub_ieee1275_cell_t data_len; ++ grub_ieee1275_cell_t rc; ++ } args; ++ ++ INIT_IEEE1275_COMMON (&args.common, "pks-read-sbvar", 4, 2); ++ args.sbvarflags = (grub_ieee1275_cell_t) sbvarflags; ++ args.sbvartype = (grub_ieee1275_cell_t) sbvartype; ++ args.buffer = (grub_ieee1275_cell_t) buffer; ++ args.buffer_len = (grub_ieee1275_cell_t) buffer_len; ++ ++ if (IEEE1275_CALL_ENTRY_FN (&args) == -1) ++ return -1; ++ ++ if (args.data_len == IEEE1275_CELL_INVALID) ++ return -1; ++ ++ *data_len = args.data_len; ++ ++ return (int) args.rc; ++} +diff --git a/include/grub/powerpc/ieee1275/ieee1275.h b/include/grub/powerpc/ieee1275/ieee1275.h +index 3c7683f..45c7b16 100644 +--- a/include/grub/powerpc/ieee1275/ieee1275.h ++++ b/include/grub/powerpc/ieee1275/ieee1275.h +@@ -25,4 +25,18 @@ + #define GRUB_IEEE1275_CELL_SIZEOF 4 + typedef grub_uint32_t grub_ieee1275_cell_t; + ++int EXPORT_FUNC (grub_ieee1275_test) (const char *name, ++ grub_ieee1275_cell_t *missing); ++ ++int grub_ieee1275_pks_max_object_size (grub_size_t *result); ++ ++int grub_ieee1275_pks_read_object (grub_uint8_t consumer, grub_uint8_t *label, ++ grub_size_t label_len, grub_uint8_t *buffer, ++ grub_size_t buffer_len, grub_size_t *data_len, ++ grub_uint32_t *policies); ++ ++int grub_ieee1275_pks_read_sbvar (grub_uint8_t sbvarflags, grub_uint8_t sbvartype, ++ grub_uint8_t *buffer, grub_size_t buffer_len, ++ grub_size_t *data_len); ++ + #endif /* ! GRUB_IEEE1275_MACHINE_HEADER */ diff --git a/SOURCES/0469-ieee1275-Read-the-DB-and-DBX-secure-boot-variables.patch b/SOURCES/0469-ieee1275-Read-the-DB-and-DBX-secure-boot-variables.patch new file mode 100644 index 0000000..c2e62d9 --- /dev/null +++ b/SOURCES/0469-ieee1275-Read-the-DB-and-DBX-secure-boot-variables.patch @@ -0,0 +1,686 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sudhakar Kuppusamy +Date: Thu, 27 Mar 2025 01:02:36 +0530 +Subject: [PATCH] ieee1275: Read the DB and DBX secure boot variables + +If secure boot is enabled with PKS, it will read secure boot variables +such as db and dbx from PKS and extract ESL's from it. +The ESL's would be saved in the platform keystore buffer, and +the appendedsig (module) would read it later to extract +the certificate's details from ESL. + +In the following scenarios, static key mode will be activated: + 1. When Secure Boot is enabled with static keys + 2. When SB Version is unavailable but Secure Boot is enabled + 3. When PKS support is unavailable but Secure Boot is enabled + +Note:- + +SB Version - Secure Boot mode +1 - PKS +0 - static key (embeded key) + +Signed-off-by: Sudhakar Kuppusamy +Reviewed-by: Stefan Berger +Reviewed-by: Avnish Chouhan +--- + grub-core/Makefile.am | 1 + + grub-core/Makefile.core.def | 1 + + grub-core/kern/ieee1275/init.c | 15 +- + .../kern/powerpc/ieee1275/platform_keystore.c | 332 +++++++++++++++++++++ + include/grub/powerpc/ieee1275/platform_keystore.h | 225 ++++++++++++++ + include/grub/types.h | 8 + + 6 files changed, 580 insertions(+), 2 deletions(-) + create mode 100644 grub-core/kern/powerpc/ieee1275/platform_keystore.c + create mode 100644 include/grub/powerpc/ieee1275/platform_keystore.h + +diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am +index dd49939..a398a04 100644 +--- a/grub-core/Makefile.am ++++ b/grub-core/Makefile.am +@@ -245,6 +245,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h ++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/powerpc/ieee1275/platform_keystore.h + endif + + if COND_sparc64_ieee1275 +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 05b9c8d..218068b 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -325,6 +325,7 @@ kernel = { + powerpc_ieee1275 = kern/powerpc/dl.c; + powerpc_ieee1275 = kern/powerpc/compiler-rt.S; + powerpc_ieee1275 = kern/lockdown.c; ++ powerpc_ieee1275 = kern/powerpc/ieee1275/platform_keystore.c; + + sparc64_ieee1275 = kern/sparc64/cache.S; + sparc64_ieee1275 = kern/sparc64/dl.c; +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index bb791f8..b853f04 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -47,6 +47,8 @@ + #include + #endif + #include ++#include ++#include + + /* The maximum heap size we're going to claim at boot. Not used by sparc. */ + #ifdef __i386__ +@@ -956,7 +958,7 @@ grub_get_ieee1275_secure_boot (void) + { + grub_ieee1275_phandle_t root; + int rc; +- grub_uint32_t is_sb; ++ grub_uint32_t is_sb = 0; + + grub_ieee1275_finddevice ("/", &root); + +@@ -972,7 +974,16 @@ grub_get_ieee1275_secure_boot (void) + * We only support enforce. + */ + if (rc >= 0 && is_sb >= 2) +- grub_lockdown (); ++ { ++ grub_dprintf ("ieee1275", "Secure Boot Enabled\n"); ++ rc = grub_pks_keystore_init (); ++ if (rc != GRUB_ERR_NONE) ++ grub_error (rc, "Initialization of the Platform Keystore failed!\n"); ++ ++ grub_lockdown (); ++ } ++ else ++ grub_dprintf ("ieee1275", "Secure Boot Disabled\n"); + } + + grub_addr_t grub_modbase; +diff --git a/grub-core/kern/powerpc/ieee1275/platform_keystore.c b/grub-core/kern/powerpc/ieee1275/platform_keystore.c +new file mode 100644 +index 0000000..cf1d055 +--- /dev/null ++++ b/grub-core/kern/powerpc/ieee1275/platform_keystore.c +@@ -0,0 +1,332 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2024 Free Software Foundation, Inc. ++ * Copyright (C) 2024 IBM Corporation ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define PKS_CONSUMER_FW 1 ++#define SB_VERSION_KEY_NAME ((grub_uint8_t *) "SB_VERSION") ++#define SB_VERSION_KEY_LEN 10 ++#define DB 1 ++#define DBX 2 ++#define PKS_OBJECT_NOT_FOUND ((grub_err_t) - 7) ++ ++/* Platform Keystore */ ++static grub_size_t pks_max_object_size; ++grub_uint8_t grub_pks_use_keystore = 0; ++grub_pks_t grub_pks_keystore = { .db = NULL, .dbx = NULL, .db_entries = 0, .dbx_entries = 0 }; ++ ++/* Convert the esl data into the ESL */ ++static grub_esl_t * ++convert_to_esl (const grub_uint8_t *esl_data, const grub_size_t esl_data_size) ++{ ++ grub_esl_t *esl = NULL; ++ ++ if (esl_data_size < sizeof (grub_esl_t) || esl_data == NULL) ++ return esl; ++ ++ esl = (grub_esl_t *) esl_data; ++ ++ return esl; ++} ++ ++/* ++ * Import the GUID, esd, and its size into the pks sd buffer and ++ * pks sd entries from the EFI signature list. ++ */ ++static grub_err_t ++esd_from_esl (const grub_uint8_t *esl_data, grub_size_t esl_size, ++ const grub_size_t signature_size, const grub_uuid_t *guid, ++ grub_pks_sd_t **pks_sd, grub_size_t *pks_sd_entries) ++{ ++ grub_esd_t *esd = NULL; ++ grub_pks_sd_t *signature = *pks_sd; ++ grub_size_t entries = *pks_sd_entries; ++ grub_size_t data_size = 0, offset = 0; ++ ++ /* reads the esd from esl */ ++ while (esl_size > 0) ++ { ++ esd = (grub_esd_t *) (esl_data + offset); ++ data_size = signature_size - sizeof (grub_esd_t); ++ ++ signature = grub_realloc (signature, (entries + 1) * sizeof (grub_pks_sd_t)); ++ if (signature == NULL) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory"); ++ ++ signature[entries].data = grub_malloc (data_size * sizeof (grub_uint8_t)); ++ if (signature[entries].data == NULL) ++ { ++ /* ++ * allocated memory will be freed by ++ * grub_free_platform_keystore ++ */ ++ *pks_sd = signature; ++ *pks_sd_entries = entries + 1; ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory"); ++ } ++ ++ grub_memcpy (signature[entries].data, esd->signaturedata, data_size); ++ signature[entries].data_size = data_size; ++ signature[entries].guid = *guid; ++ entries++; ++ esl_size -= signature_size; ++ offset += signature_size; ++ } ++ ++ *pks_sd = signature; ++ *pks_sd_entries = entries; ++ ++ return GRUB_ERR_NONE; ++} ++ ++/* ++ * Extract the esd after removing the esl header from esl. ++ */ ++static grub_err_t ++esl_to_esd (const grub_uint8_t *esl_data, grub_size_t *next_esl, ++ grub_pks_sd_t **pks_sd, grub_size_t *pks_sd_entries) ++{ ++ grub_uuid_t guid = { 0 }; ++ grub_esl_t *esl = NULL; ++ grub_size_t offset = 0, esl_size = 0, ++ signature_size = 0, signature_header_size = 0; ++ ++ esl = convert_to_esl (esl_data, *next_esl); ++ if (esl == NULL) ++ return grub_error (GRUB_ERR_BUG, "invalid ESL"); ++ ++ esl_size = grub_le_to_cpu32 (esl->signaturelistsize); ++ signature_header_size = grub_le_to_cpu32 (esl->signatureheadersize); ++ signature_size = grub_le_to_cpu32 (esl->signaturesize); ++ guid = esl->signaturetype; ++ ++ if (esl_size < sizeof (grub_esl_t) || esl_size > *next_esl) ++ return grub_error (GRUB_ERR_BUG, "invalid ESL size (%u)\n", esl_size); ++ ++ *next_esl = esl_size; ++ offset = sizeof (grub_esl_t) + signature_header_size; ++ esl_size = esl_size - offset; ++ ++ return esd_from_esl (esl_data + offset, esl_size, signature_size, &guid, ++ pks_sd, pks_sd_entries); ++} ++ ++/* ++ * Import the EFI signature data and the number of esd from the esl ++ * into the pks sd buffer and pks sd entries. ++ */ ++static grub_err_t ++pks_sd_from_esl (const grub_uint8_t *esl_data, grub_size_t esl_size, ++ grub_pks_sd_t **pks_sd, grub_size_t *pks_sd_entries) ++{ ++ grub_err_t rc = GRUB_ERR_NONE; ++ grub_size_t next_esl = esl_size; ++ ++ do ++ { ++ rc = esl_to_esd (esl_data, &next_esl, pks_sd, pks_sd_entries); ++ if (rc != GRUB_ERR_NONE) ++ break; ++ ++ esl_data += next_esl; ++ esl_size -= next_esl; ++ next_esl = esl_size; ++ } ++ while (esl_size > 0); ++ ++ return rc; ++} ++ ++/* ++ * Read the secure boot version from PKS as an object. ++ * caller must free result ++ */ ++static grub_err_t ++read_sbversion_from_pks (grub_uint8_t **out, grub_size_t *outlen, grub_size_t *policy) ++{ ++ *out = grub_malloc (pks_max_object_size); ++ if (*out == NULL) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory"); ++ ++ return grub_ieee1275_pks_read_object (PKS_CONSUMER_FW, SB_VERSION_KEY_NAME, ++ SB_VERSION_KEY_LEN, *out, pks_max_object_size, ++ outlen, policy); ++} ++ ++/* ++ * reads the secure boot variable from PKS. ++ * caller must free result ++ */ ++static grub_err_t ++read_sbvar_from_pks (const grub_uint8_t sbvarflags, const grub_uint8_t sbvartype, ++ grub_uint8_t **out, grub_size_t *outlen) ++{ ++ *out = grub_malloc (pks_max_object_size); ++ if (*out == NULL) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory"); ++ ++ return grub_ieee1275_pks_read_sbvar (sbvarflags, sbvartype, *out, ++ pks_max_object_size, outlen); ++} ++ ++/* Test the availability of PKS support. */ ++static grub_err_t ++is_support_pks (void) ++{ ++ grub_err_t rc = GRUB_ERR_NONE; ++ grub_ieee1275_cell_t missing = 0; ++ ++ rc = grub_ieee1275_test ("pks-max-object-size", &missing); ++ if (rc != GRUB_ERR_NONE || (int) missing == -1) ++ rc = grub_error (GRUB_ERR_BAD_FIRMWARE, "Firmware doesn't have PKS support!\n"); ++ else ++ { ++ rc = grub_ieee1275_pks_max_object_size (&pks_max_object_size); ++ if (rc != GRUB_ERR_NONE) ++ rc = grub_error (GRUB_ERR_BAD_NUMBER, "PKS support is there but it has zero objects!\n"); ++ } ++ ++ return rc; ++} ++ ++/* ++ * Retrieve the secure boot variable from PKS, unpacks it, read the esd ++ * from ESL, and store the information in the pks sd buffer. ++ */ ++static grub_err_t ++read_secure_boot_variables (const grub_uint8_t sbvarflags, const grub_uint8_t sbvartype, ++ grub_pks_sd_t **pks_sd, grub_size_t *pks_sd_entries) ++{ ++ grub_err_t rc = GRUB_ERR_NONE; ++ grub_uint8_t *esl_data = NULL; ++ grub_size_t esl_data_size = 0; ++ ++ rc = read_sbvar_from_pks (sbvarflags, sbvartype, &esl_data, &esl_data_size); ++ /* ++ * at this point we have SB_VERSION, so any error is worth ++ * at least some user-visible info ++ */ ++ if (rc != GRUB_ERR_NONE) ++ rc = grub_error (rc, "secure boot variable %s reading (%d)", ++ (sbvartype == DB ? "db" : "dbx"), rc); ++ else if (esl_data_size != 0) ++ rc = pks_sd_from_esl ((const grub_uint8_t *) esl_data, esl_data_size, ++ pks_sd, pks_sd_entries); ++ grub_free (esl_data); ++ ++ return rc; ++} ++ ++/* reads secure boot version (SB_VERSION) and it supports following ++ * SB_VERSION ++ * 1 - PKS ++ * 0 - static key (embeded key) ++ */ ++static grub_err_t ++get_secure_boot_version (void) ++{ ++ grub_err_t rc = GRUB_ERR_NONE; ++ grub_uint8_t *data = NULL; ++ grub_size_t len = 0, policy = 0; ++ ++ rc = read_sbversion_from_pks (&data, &len, &policy); ++ if (rc != GRUB_ERR_NONE) ++ rc = grub_error (GRUB_ERR_READ_ERROR, "SB version read failed! (%d)\n", rc); ++ else if (len != 1 || (*data >= 2)) ++ rc = grub_error (GRUB_ERR_BAD_NUMBER, "found unexpected SB version! (%d)\n", *data); ++ ++ if (rc != GRUB_ERR_NONE) ++ { ++ grub_printf ("Switch to Static Key!\n"); ++ if (grub_is_lockdown () == GRUB_LOCKDOWN_ENABLED) ++ grub_fatal ("Secure Boot locked down"); ++ } ++ else ++ grub_pks_use_keystore = *data; ++ ++ grub_free (data); ++ ++ return rc; ++} ++ ++/* Free allocated memory */ ++void ++grub_pks_free_keystore (void) ++{ ++ grub_size_t i = 0; ++ ++ for (i = 0; i < grub_pks_keystore.db_entries; i++) ++ grub_free (grub_pks_keystore.db[i].data); ++ ++ for (i = 0; i < grub_pks_keystore.dbx_entries; i++) ++ grub_free (grub_pks_keystore.dbx[i].data); ++ ++ grub_free (grub_pks_keystore.db); ++ grub_free (grub_pks_keystore.dbx); ++ grub_memset (&grub_pks_keystore, 0, sizeof (grub_pks_t)); ++} ++ ++/* Initialization of the Platform Keystore */ ++grub_err_t ++grub_pks_keystore_init (void) ++{ ++ grub_err_t rc = GRUB_ERR_NONE; ++ ++ grub_dprintf ("ieee1275", "trying to load Platform Keystore\n"); ++ ++ rc = is_support_pks (); ++ if (rc != GRUB_ERR_NONE) ++ { ++ grub_printf ("Switch to Static Key!\n"); ++ return rc; ++ } ++ ++ /* SB_VERSION */ ++ rc = get_secure_boot_version (); ++ if (rc != GRUB_ERR_NONE) ++ return rc; ++ ++ if (grub_pks_use_keystore) ++ { ++ grub_memset (&grub_pks_keystore, 0, sizeof (grub_pks_t)); ++ /* DB */ ++ rc = read_secure_boot_variables (0, DB, &grub_pks_keystore.db, &grub_pks_keystore.db_entries); ++ if (rc == GRUB_ERR_NONE) ++ { ++ /* DBX */ ++ rc = read_secure_boot_variables (0, DBX, &grub_pks_keystore.dbx, &grub_pks_keystore.dbx_entries); ++ if (rc == PKS_OBJECT_NOT_FOUND) ++ { ++ grub_dprintf ("ieee1275", "dbx is not found in PKS\n"); ++ rc = GRUB_ERR_NONE; ++ } ++ } ++ ++ } ++ ++ if (rc != GRUB_ERR_NONE) ++ grub_pks_free_keystore (); ++ ++ return rc; ++} +diff --git a/include/grub/powerpc/ieee1275/platform_keystore.h b/include/grub/powerpc/ieee1275/platform_keystore.h +new file mode 100644 +index 0000000..0641adb +--- /dev/null ++++ b/include/grub/powerpc/ieee1275/platform_keystore.h +@@ -0,0 +1,225 @@ ++/* ++ * Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved. This ++ * program and the accompanying materials are licensed and made available ++ * under the terms and conditions of the 2-Clause BSD License which ++ * accompanies this distribution. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright notice, ++ * this list of conditions and the following disclaimer. ++ * ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ * ++ * ++ * https://github.com/tianocore/edk2-staging (edk2-staging repo of tianocore), ++ * the ImageAuthentication.h file under it, and here's the copyright and license. ++ * ++ * MdePkg/Include/Guid/ImageAuthentication.h ++ * ++ * Copyright 2024 IBM Corp. ++ */ ++ ++#ifndef __PLATFORM_KEYSTORE_H__ ++#define __PLATFORM_KEYSTORE_H__ ++ ++#include ++#include ++#include ++ ++#if __GNUC__ >= 9 ++#pragma GCC diagnostic ignored "-Waddress-of-packed-member" ++#endif ++ ++#define GRUB_MAX_HASH_SIZE 64 ++ ++typedef struct grub_esd grub_esd_t; ++typedef struct grub_esl grub_esl_t; ++ ++/* ++ * It is derived from EFI_SIGNATURE_DATA ++ * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h ++ * ++ * The structure of an EFI signature database (ESD).*/ ++struct grub_esd ++{ ++ /* ++ * An identifier which identifies the agent which added ++ * the signature to the list. ++ */ ++ grub_uuid_t signatureowner; ++ /* The format of the signature is defined by the SignatureType.*/ ++ grub_uint8_t signaturedata[]; ++} GRUB_PACKED; ++ ++/* ++ * It is derived from EFI_SIGNATURE_LIST ++ * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h ++ * ++ * The structure of an EFI signature list (ESL).*/ ++struct grub_esl ++{ ++ /* Type of the signature. GUID signature types are defined in below.*/ ++ grub_uuid_t signaturetype; ++ /* Total size of the signature list, including this header.*/ ++ grub_uint32_t signaturelistsize; ++ /* ++ * Size of the signature header which precedes ++ * the array of signatures. ++ */ ++ grub_uint32_t signatureheadersize; ++ /* Size of each signature.*/ ++ grub_uint32_t signaturesize; ++} GRUB_PACKED; ++ ++/* ++ * It is derived from EFI_CERT_X509_GUID ++ * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h ++ */ ++#define GRUB_PKS_CERT_X509_GUID \ ++ (grub_uuid_t) \ ++ { \ ++ { \ ++ 0xa1, 0x59, 0xc0, 0xa5, 0xe4, 0x94, \ ++ 0xa7, 0x4a, 0x87, 0xb5, 0xab, 0x15, \ ++ 0x5c, 0x2b, 0xf0, 0x72 \ ++ } \ ++ } ++ ++/* ++ * It is derived from EFI_CERT_SHA256_GUID ++ * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h ++ */ ++#define GRUB_PKS_CERT_SHA256_GUID \ ++ (grub_uuid_t) \ ++ { \ ++ { \ ++ 0x26, 0x16, 0xc4, 0xc1, 0x4c, 0x50, \ ++ 0x92, 0x40, 0xac, 0xa9, 0x41, 0xf9, \ ++ 0x36, 0x93, 0x43, 0x28 \ ++ } \ ++ } ++ ++/* ++ * It is derived from EFI_CERT_SHA384_GUID ++ * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h ++ */ ++#define GRUB_PKS_CERT_SHA384_GUID \ ++ (grub_uuid_t) \ ++ { \ ++ { \ ++ 0x07, 0x53, 0x3e, 0xff, 0xd0, 0x9f, \ ++ 0xc9, 0x48, 0x85, 0xf1, 0x8a, 0xd5, \ ++ 0x6c, 0x70, 0x1e, 0x1 \ ++ } \ ++ } ++ ++/* ++ * It is derived from EFI_CERT_SHA512_GUID ++ * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h ++ */ ++#define GRUB_PKS_CERT_SHA512_GUID \ ++ (grub_uuid_t) \ ++ { \ ++ { \ ++ 0xae, 0x0f, 0x3e, 0x09, 0xc4, 0xa6, \ ++ 0x50, 0x4f, 0x9f, 0x1b, 0xd4, 0x1e, \ ++ 0x2b, 0x89, 0xc1, 0x9a \ ++ } \ ++ } ++ ++/* ++ * It is derived from EFI_CERT_X509_SHA256_GUID ++ * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h ++ */ ++#define GRUB_PKS_CERT_X509_SHA256_GUID \ ++ (grub_uuid_t) \ ++ { \ ++ { \ ++ 0x92, 0xa4, 0xd2, 0x3b, 0xc0, 0x96, \ ++ 0x79, 0x40, 0xb4, 0x20, 0xfc, 0xf9, \ ++ 0x8e, 0xf1, 0x03, 0xed \ ++ } \ ++ } ++ ++/* ++ * It is derived from EFI_CERT_X509_SHA384_GUID ++ * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h ++ */ ++#define GRUB_PKS_CERT_X509_SHA384_GUID \ ++ (grub_uuid_t) \ ++ { \ ++ { \ ++ 0x6e, 0x87, 0x76, 0x70, 0xc2, 0x80, \ ++ 0xe6, 0x4e, 0xaa, 0xd2, 0x28, 0xb3, \ ++ 0x49, 0xa6, 0x86, 0x5b \ ++ } \ ++ } ++ ++/* ++ * It is derived from EFI_CERT_X509_SHA512_GUID ++ * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h ++ */ ++#define GRUB_PKS_CERT_X509_SHA512_GUID \ ++ (grub_uuid_t) \ ++ { \ ++ { \ ++ 0x63, 0xbf, 0x6d, 0x44, 0x02, 0x25, \ ++ 0xda, 0x4c, 0xbc, 0xfa, 0x24, 0x65, \ ++ 0xd2, 0xb0, 0xfe, 0x9d \ ++ } \ ++ } ++ ++typedef struct grub_pks_sd grub_pks_sd_t; ++typedef struct grub_pks grub_pks_t; ++ ++/* The structure of a PKS signature data.*/ ++struct grub_pks_sd ++{ ++ grub_uuid_t guid; /* signature type */ ++ grub_uint8_t *data; /* signature data */ ++ grub_size_t data_size; /* size of signature data */ ++} GRUB_PACKED; ++ ++/* The structure of a PKS.*/ ++struct grub_pks ++{ ++ grub_pks_sd_t *db; /* signature database */ ++ grub_pks_sd_t *dbx; /* forbidden signature database */ ++ grub_size_t db_entries; /* size of signature database */ ++ grub_size_t dbx_entries; /* size of forbidden signature database */ ++} GRUB_PACKED; ++ ++#ifdef __powerpc__ ++ ++/* Initialization of the Platform Keystore */ ++grub_err_t grub_pks_keystore_init (void); ++/* Free allocated memory */ ++void EXPORT_FUNC(grub_pks_free_keystore) (void); ++extern grub_uint8_t EXPORT_VAR(grub_pks_use_keystore); ++extern grub_pks_t EXPORT_VAR(grub_pks_keystore); ++ ++#else ++ ++#define grub_pks_use_keystore 0 ++grub_pks_t grub_pks_keystore = {NULL, NULL, 0, 0}; ++void grub_pks_free_keystore (void); ++ ++#endif ++ ++#endif +diff --git a/include/grub/types.h b/include/grub/types.h +index 1587ff4..bfa7af9 100644 +--- a/include/grub/types.h ++++ b/include/grub/types.h +@@ -345,4 +345,12 @@ static inline void grub_set_unaligned64 (void *ptr, grub_uint64_t val) + dd->d = val; + } + ++#define GRUB_UUID_SIZE 16 ++typedef struct grub_uuid grub_uuid_t; ++/* The structure of a UUID.*/ ++struct grub_uuid ++{ ++ grub_uint8_t b[GRUB_UUID_SIZE]; ++}; ++ + #endif /* ! GRUB_TYPES_HEADER */ diff --git a/SOURCES/0470-appendedsig-The-creation-of-trusted-and-distrusted-l.patch b/SOURCES/0470-appendedsig-The-creation-of-trusted-and-distrusted-l.patch new file mode 100644 index 0000000..16786a8 --- /dev/null +++ b/SOURCES/0470-appendedsig-The-creation-of-trusted-and-distrusted-l.patch @@ -0,0 +1,764 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sudhakar Kuppusamy +Date: Thu, 27 Mar 2025 01:02:37 +0530 +Subject: [PATCH] appendedsig: The creation of trusted and distrusted lists + +The trusted certificates and binary hashes, distrusted certificates and +binary/certificate hashes will be extracted from the platform keystore buffer +if Secure Boot is enabled with PKS. + +In order to verify the integrity of the kernel, the extracted data +needs to be stored stored in the buffer db and dbx. + +The trusted certificates will be extracted from the grub ELFNOTE if Secure Boot is +enabled with static key. In order to verify the integerity of the kernel, +the extracted data needs to be stored in the buffer db. + +Note:- + +If neither the trusted certificate nor binary hash exists in the distrusted list (dbx), +rejects it while extracting certificate/binary hash from the platform keystore buffer. + +Signed-off-by: Sudhakar Kuppusamy +Reviewed-by: Stefan Berger +Reviewed-by: Avnish Chouhan +--- + grub-core/commands/appendedsig/appendedsig.c | 584 +++++++++++++++++++++++++-- + grub-core/kern/file.c | 34 ++ + include/grub/file.h | 1 + + 3 files changed, 577 insertions(+), 42 deletions(-) + +diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c +index f4eefe5..994852f 100644 +--- a/grub-core/commands/appendedsig/appendedsig.c ++++ b/grub-core/commands/appendedsig/appendedsig.c +@@ -34,7 +34,7 @@ + #include + #include + #include +- ++#include + #include "appendedsig.h" + + GRUB_MOD_LICENSE ("GPLv3+"); +@@ -64,8 +64,23 @@ struct grub_appended_signature + struct pkcs7_signedData pkcs7; /* Parsed PKCS#7 data */ + }; + +-/* Trusted certificates for verifying appended signatures */ +-struct x509_certificate *grub_trusted_key; ++/* This represents a trusted/distrusted list*/ ++struct grub_database ++{ ++ struct x509_certificate *keys; /* Certificates */ ++ grub_size_t key_entries; /* Number of certificates */ ++ grub_uint8_t **signatures; /* Certificate/binary hashes */ ++ grub_size_t *signature_size; /* Size of certificate/binary hashes */ ++ grub_size_t signature_entries; /* Number of certificate/binary hashes */ ++}; ++ ++/* Trusted list */ ++struct grub_database db = {.keys = NULL, .key_entries = 0, .signatures = NULL, ++ .signature_size = NULL, .signature_entries = 0}; ++ ++/* Distrusted list */ ++struct grub_database dbx = {.signatures = NULL, .signature_size = NULL, ++ .signature_entries = 0}; + + /* + * Force gcry_rsa to be a module dependency. +@@ -87,6 +102,13 @@ struct x509_certificate *grub_trusted_key; + * also resolves our concerns about loading from the filesystem. + */ + extern gcry_pk_spec_t _gcry_pubkey_spec_rsa; ++extern gcry_md_spec_t _gcry_digest_spec_sha224; ++extern gcry_md_spec_t _gcry_digest_spec_sha384; ++ ++/* Free trusted list memory */ ++static void free_trusted_list (void); ++/* Free distrusted list memory */ ++static void free_distrusted_list (void); + + static enum + { +@@ -95,6 +117,204 @@ static enum + check_sigs_forced = 2 + } check_sigs = check_sigs_no; + ++/* ++ * GUID can be used to determine the hashing function and ++ * generate the hash using determined hashing function. ++ */ ++static grub_err_t ++get_hash (const grub_uuid_t *guid, const grub_uint8_t *data, const grub_size_t data_size, ++ grub_uint8_t *hash, grub_size_t *hash_size) ++{ ++ gcry_md_spec_t *hash_func = NULL; ++ ++ if (guid == NULL) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, "GUID is null"); ++ ++ if (grub_memcmp (guid, &GRUB_PKS_CERT_SHA256_GUID, GRUB_UUID_SIZE) == 0 || ++ grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA256_GUID, GRUB_UUID_SIZE) == 0) ++ hash_func = &_gcry_digest_spec_sha256; ++ else if (grub_memcmp (guid, &GRUB_PKS_CERT_SHA384_GUID, GRUB_UUID_SIZE) == 0 || ++ grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA384_GUID, GRUB_UUID_SIZE) == 0) ++ hash_func = &_gcry_digest_spec_sha384; ++ else if (grub_memcmp (guid, &GRUB_PKS_CERT_SHA512_GUID, GRUB_UUID_SIZE) == 0 || ++ grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA512_GUID, GRUB_UUID_SIZE) == 0) ++ hash_func = &_gcry_digest_spec_sha512; ++ else ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, "Unsupported GUID for hash"); ++ ++ grub_memset (hash, 0, GRUB_MAX_HASH_SIZE); ++ grub_crypto_hash (hash_func, hash, data, data_size); ++ *hash_size = hash_func->mdlen; ++ ++ return GRUB_ERR_NONE; ++} ++ ++/* Add the certificate/binary hash into the trusted/distrusted list */ ++static grub_err_t ++add_hash (const grub_uint8_t **data, const grub_size_t data_size, ++ grub_uint8_t ***signature_list, grub_size_t **signature_size_list, ++ grub_size_t *signature_list_entries) ++{ ++ grub_uint8_t **signatures = *signature_list; ++ grub_size_t *signature_size = *signature_size_list; ++ grub_size_t signature_entries = *signature_list_entries; ++ ++ if (*data == NULL || data_size == 0) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, "certificate/binary hash data/size is null"); ++ ++ signatures = grub_realloc (signatures, sizeof (grub_uint8_t *) * (signature_entries + 1)); ++ signature_size = grub_realloc (signature_size, ++ sizeof (grub_size_t) * (signature_entries + 1)); ++ ++ if (signatures == NULL || signature_size == NULL) ++ { ++ /* ++ * allocated memory will be freed by ++ * free_trusted_list/free_distrusted_list ++ */ ++ if (signatures != NULL) ++ { ++ *signature_list = signatures; ++ *signature_list_entries = signature_entries + 1; ++ } ++ ++ if (signature_size != NULL) ++ *signature_size_list = signature_size; ++ ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory"); ++ } ++ ++ signatures[signature_entries] = (grub_uint8_t *) *data; ++ signature_size[signature_entries] = data_size; ++ signature_entries++; ++ *data = NULL; ++ ++ *signature_list = signatures; ++ *signature_size_list = signature_size; ++ *signature_list_entries = signature_entries; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static int ++is_x509 (const grub_uuid_t *guid) ++{ ++ if (grub_memcmp (guid, &GRUB_PKS_CERT_X509_GUID, GRUB_UUID_SIZE) == 0) ++ return GRUB_ERR_NONE; ++ ++ return GRUB_ERR_UNKNOWN_COMMAND; ++} ++ ++static int ++is_cert_match (const struct x509_certificate *distrusted_cert, ++ const struct x509_certificate *db_cert) ++{ ++ ++ if (grub_memcmp (distrusted_cert->subject, db_cert->subject, db_cert->subject_len) == 0 ++ && grub_memcmp (distrusted_cert->serial, db_cert->serial, db_cert->serial_len) == 0 ++ && grub_memcmp (distrusted_cert->mpis[0], db_cert->mpis[0], sizeof (db_cert->mpis[0])) == 0 ++ && grub_memcmp (distrusted_cert->mpis[1], db_cert->mpis[1], sizeof (db_cert->mpis[1])) == 0) ++ return GRUB_ERR_NONE; ++ ++ return GRUB_ERR_UNKNOWN_COMMAND; ++} ++ ++/* ++ * Verify the certificate against the certificate from platform keystore buffer's ++ * distrusted list. ++ */ ++static grub_err_t ++is_distrusted_cert (const struct x509_certificate *db_cert) ++{ ++ grub_err_t rc = GRUB_ERR_NONE; ++ grub_size_t i = 0; ++ struct x509_certificate *distrusted_cert = NULL; ++ ++ for (i = 0; i < grub_pks_keystore.dbx_entries; i++) ++ { ++ if (grub_pks_keystore.dbx[i].data == NULL) ++ continue; ++ ++ if (is_x509 (&grub_pks_keystore.dbx[i].guid) == GRUB_ERR_NONE) ++ { ++ distrusted_cert = grub_zalloc (sizeof (struct x509_certificate)); ++ if (distrusted_cert == NULL) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory"); ++ ++ rc = parse_x509_certificate (grub_pks_keystore.dbx[i].data, ++ grub_pks_keystore.dbx[i].data_size, distrusted_cert); ++ if (rc != GRUB_ERR_NONE) ++ { ++ grub_free (distrusted_cert); ++ continue; ++ } ++ ++ if (is_cert_match (distrusted_cert, db_cert) == GRUB_ERR_NONE) ++ { ++ grub_printf ("Warning: a trusted certificate CN='%s' is ignored " ++ "because it is on the distrusted list (dbx).\n", db_cert->subject); ++ grub_free (grub_pks_keystore.dbx[i].data); ++ grub_memset (&grub_pks_keystore.dbx[i], 0, sizeof (grub_pks_sd_t)); ++ certificate_release (distrusted_cert); ++ grub_free (distrusted_cert); ++ return GRUB_ERR_ACCESS_DENIED; ++ } ++ ++ certificate_release (distrusted_cert); ++ grub_free (distrusted_cert); ++ } ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++/* Add the certificate into the trusted/distrusted list */ ++static grub_err_t ++add_certificate (const grub_uint8_t *data, const grub_size_t data_size, ++ struct grub_database *database, const grub_size_t is_db) ++{ ++ grub_err_t rc = GRUB_ERR_NONE; ++ grub_size_t key_entries = database->key_entries; ++ struct x509_certificate *cert = NULL; ++ ++ if (data == NULL || data_size == 0) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, "certificate data/size is null"); ++ ++ cert = grub_zalloc (sizeof (struct x509_certificate)); ++ if (cert == NULL) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory"); ++ ++ rc = parse_x509_certificate (data, data_size, cert); ++ if (rc != GRUB_ERR_NONE) ++ { ++ grub_dprintf ("appendedsig", "skipping %s certificate (%d)\n", ++ (is_db ? "trusted":"distrusted"), rc); ++ grub_free (cert); ++ return rc; ++ } ++ ++ if (is_db) ++ { ++ rc = is_distrusted_cert (cert); ++ if (rc != GRUB_ERR_NONE) ++ { ++ certificate_release (cert); ++ grub_free (cert); ++ return rc; ++ } ++ } ++ ++ grub_dprintf ("appendedsig", "add a %s certificate CN='%s'\n", ++ (is_db ? "trusted":"distrusted"), cert->subject); ++ ++ key_entries++; ++ cert->next = database->keys; ++ database->keys = cert; ++ database->key_entries = key_entries; ++ ++ return rc; ++} ++ + static const char * + grub_env_read_sec (struct grub_env_var *var __attribute__ ((unused)), + const char *val __attribute__ ((unused))) +@@ -248,7 +468,7 @@ grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize) + struct pkcs7_signerInfo *si; + int i; + +- if (!grub_trusted_key) ++ if (!db.key_entries) + return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("No trusted keys to verify against")); + + err = extract_appended_signature (buf, bufsize, &sig); +@@ -279,7 +499,7 @@ grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize) + datasize, i, hash[0], hash[1], hash[2], hash[3]); + + err = GRUB_ERR_BAD_SIGNATURE; +- for (pk = grub_trusted_key; pk; pk = pk->next) ++ for (pk = db.keys; pk; pk = pk->next) + { + rc = grub_crypto_rsa_pad (&hashmpi, hash, si->hash, pk->mpis[0]); + if (rc) +@@ -376,16 +596,16 @@ grub_cmd_distrust (grub_command_t cmd __attribute__ ((unused)), int argc, char * + + if (cert_num == 1) + { +- cert = grub_trusted_key; +- grub_trusted_key = cert->next; ++ cert = db.keys; ++ db.keys = cert->next; + + certificate_release (cert); + grub_free (cert); + return GRUB_ERR_NONE; + } + i = 2; +- prev = grub_trusted_key; +- cert = grub_trusted_key->next; ++ prev = db.keys; ++ cert = db.keys->next; + while (cert) + { + if (i == cert_num) +@@ -432,8 +652,8 @@ grub_cmd_trust (grub_command_t cmd __attribute__ ((unused)), int argc, char **ar + } + grub_dprintf ("appendedsig", "Loaded certificate with CN: %s\n", cert->subject); + +- cert->next = grub_trusted_key; +- grub_trusted_key = cert; ++ cert->next = db.keys; ++ db.keys = cert; + + return GRUB_ERR_NONE; + } +@@ -446,7 +666,7 @@ grub_cmd_list (grub_command_t cmd __attribute__ ((unused)), int argc __attribute + int cert_num = 1; + grub_size_t i; + +- for (cert = grub_trusted_key; cert; cert = cert->next) ++ for (cert = db.keys; cert; cert = cert->next) + { + grub_printf (N_("Certificate %d:\n"), cert_num); + +@@ -539,6 +759,274 @@ static struct grub_fs pseudo_fs = { .name = "pseudo", .fs_read = pseudo_read }; + + static grub_command_t cmd_verify, cmd_list, cmd_distrust, cmd_trust; + ++/* ++ * Verify the trusted certificate against the certificate hashes from platform keystore buffer's ++ * distrusted list. ++ */ ++static grub_err_t ++is_distrusted_cert_hash (const grub_uint8_t *data, const grub_size_t data_size) ++{ ++ grub_err_t rc = GRUB_ERR_NONE; ++ grub_size_t i = 0, cert_hash_size = 0; ++ grub_uint8_t cert_hash[GRUB_MAX_HASH_SIZE] = { 0 }; ++ ++ if (data == NULL || data_size == 0) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, "trusted certificate data/size is null"); ++ ++ for (i = 0; i < grub_pks_keystore.dbx_entries; i++) ++ { ++ if (grub_pks_keystore.dbx[i].data == NULL || ++ grub_pks_keystore.dbx[i].data_size == 0) ++ continue; ++ ++ rc = get_hash (&grub_pks_keystore.dbx[i].guid, data, data_size, ++ cert_hash, &cert_hash_size); ++ if (rc != GRUB_ERR_NONE) ++ continue; ++ ++ if (cert_hash_size == grub_pks_keystore.dbx[i].data_size && ++ grub_memcmp (grub_pks_keystore.dbx[i].data, cert_hash, cert_hash_size) == 0) ++ { ++ grub_printf ("Warning: a trusted certificate (%02x%02x%02x%02x) is ignored " ++ "because this certificate hash is on the distrusted list (dbx).\n", ++ cert_hash[0], cert_hash[1], cert_hash[2], cert_hash[3]); ++ grub_free (grub_pks_keystore.dbx[i].data); ++ grub_memset (&grub_pks_keystore.dbx[i], 0, sizeof (grub_pks_keystore.dbx[i])); ++ return GRUB_ERR_BAD_SIGNATURE; ++ } ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++/* ++ * Verify the trusted binary hash against the platform keystore buffer's ++ * distrusted list. ++ */ ++static grub_err_t ++is_distrusted_binary_hash (const grub_uint8_t *binary_hash, ++ const grub_size_t binary_hash_size) ++{ ++ grub_size_t i = 0; ++ ++ for (i = 0; i < grub_pks_keystore.dbx_entries; i++) ++ { ++ if (grub_pks_keystore.dbx[i].data == NULL || ++ grub_pks_keystore.dbx[i].data_size == 0) ++ continue; ++ ++ if (binary_hash_size == grub_pks_keystore.dbx[i].data_size && ++ grub_memcmp (grub_pks_keystore.dbx[i].data, binary_hash, binary_hash_size) == 0) ++ { ++ grub_printf ("Warning: a trusted binary hash (%02x%02x%02x%02x) is ignored" ++ " because it is on the distrusted list (dbx).\n", ++ binary_hash[0], binary_hash[1], binary_hash[2], binary_hash[3]); ++ grub_free (grub_pks_keystore.dbx[i].data); ++ grub_memset (&grub_pks_keystore.dbx[i], 0, sizeof(grub_pks_keystore.dbx[i])); ++ return GRUB_ERR_BAD_SIGNATURE; ++ } ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++/* ++ * Extract the binary hashes from the platform keystore buffer, ++ * and add it to the trusted list if it does not exist in the distrusted list. ++ */ ++static grub_err_t ++add_trusted_binary_hash (const grub_uint8_t **data, const grub_size_t data_size) ++{ ++ grub_err_t rc = GRUB_ERR_NONE; ++ ++ if (*data == NULL || data_size == 0) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, "trusted binary hash data/size is null"); ++ ++ rc = is_distrusted_binary_hash (*data, data_size); ++ if (rc != GRUB_ERR_NONE) ++ return rc; ++ ++ rc = add_hash (data, data_size, &db.signatures, &db.signature_size, ++ &db.signature_entries); ++ return rc; ++} ++ ++static int ++is_hash (const grub_uuid_t *guid) ++{ ++ /* GUID type of the binary hash */ ++ if (grub_memcmp (guid, &GRUB_PKS_CERT_SHA256_GUID, GRUB_UUID_SIZE) == 0 || ++ grub_memcmp (guid, &GRUB_PKS_CERT_SHA384_GUID, GRUB_UUID_SIZE) == 0 || ++ grub_memcmp (guid, &GRUB_PKS_CERT_SHA512_GUID, GRUB_UUID_SIZE) == 0) ++ return GRUB_ERR_NONE; ++ ++ /* GUID type of the certificate hash */ ++ if (grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA256_GUID, GRUB_UUID_SIZE) == 0 || ++ grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA384_GUID, GRUB_UUID_SIZE) == 0 || ++ grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA512_GUID, GRUB_UUID_SIZE) == 0) ++ return GRUB_ERR_NONE; ++ ++ return GRUB_ERR_UNKNOWN_COMMAND; ++} ++ ++/* ++ * Extract the x509 certificates/binary hashes from the platform keystore buffer, ++ * parse it, and add it to the trusted list. ++ */ ++static grub_err_t ++create_trusted_list (void) ++{ ++ grub_err_t rc = GRUB_ERR_NONE; ++ grub_size_t i = 0; ++ ++ for (i = 0; i < grub_pks_keystore.db_entries; i++) ++ { ++ if (is_hash (&grub_pks_keystore.db[i].guid) == GRUB_ERR_NONE) ++ { ++ rc = add_trusted_binary_hash ((const grub_uint8_t **) ++ &grub_pks_keystore.db[i].data, ++ grub_pks_keystore.db[i].data_size); ++ if (rc == GRUB_ERR_OUT_OF_MEMORY) ++ return rc; ++ } ++ else if (is_x509 (&grub_pks_keystore.db[i].guid) == GRUB_ERR_NONE) ++ { ++ rc = is_distrusted_cert_hash (grub_pks_keystore.db[i].data, ++ grub_pks_keystore.db[i].data_size); ++ if (rc != GRUB_ERR_NONE) ++ continue; ++ ++ rc = add_certificate (grub_pks_keystore.db[i].data, ++ grub_pks_keystore.db[i].data_size, &db, 1); ++ if (rc == GRUB_ERR_OUT_OF_MEMORY) ++ return rc; ++ else if (rc != GRUB_ERR_NONE) ++ continue; ++ } ++ else ++ grub_dprintf ("appendedsig", "unsupported signature data type and " ++ "skipping trusted data (%" PRIuGRUB_SIZE ")\n", i + 1); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++/* ++ * Extract the certificates, certificate/binary hashes out of the platform keystore buffer, ++ * and add it to the distrusted list. ++ */ ++static grub_err_t ++create_distrusted_list (void) ++{ ++ grub_err_t rc = GRUB_ERR_NONE; ++ grub_size_t i = 0; ++ ++ for (i = 0; i < grub_pks_keystore.dbx_entries; i++) ++ { ++ if (grub_pks_keystore.dbx[i].data != NULL || ++ grub_pks_keystore.dbx[i].data_size > 0) ++ { ++ if (is_x509 (&grub_pks_keystore.dbx[i].guid) == GRUB_ERR_NONE) ++ { ++ rc = add_certificate (grub_pks_keystore.dbx[i].data, ++ grub_pks_keystore.dbx[i].data_size, &dbx, 0); ++ if (rc == GRUB_ERR_OUT_OF_MEMORY) ++ return rc; ++ } ++ else if (is_hash (&grub_pks_keystore.dbx[i].guid) == GRUB_ERR_NONE) ++ { ++ rc = add_hash ((const grub_uint8_t **) &grub_pks_keystore.dbx[i].data, ++ grub_pks_keystore.dbx[i].data_size, ++ &dbx.signatures, &dbx.signature_size, ++ &dbx.signature_entries); ++ if (rc != GRUB_ERR_NONE) ++ return rc; ++ } ++ else ++ grub_dprintf ("appendedsig", "unsupported signature data type and " ++ "skipping distrusted data (%" PRIuGRUB_SIZE ")\n", i + 1); ++ } ++ } ++ ++ return rc; ++} ++ ++/* ++ * Extract the x509 certificates from the ELF note header, ++ * parse it, and add it to the trusted list. ++ */ ++static grub_err_t ++build_static_trusted_list (const struct grub_module_header *header) ++{ ++ grub_err_t err = GRUB_ERR_NONE; ++ struct grub_file pseudo_file; ++ grub_uint8_t *cert_data = NULL; ++ grub_ssize_t cert_data_size = 0; ++ ++ grub_memset (&pseudo_file, 0, sizeof (pseudo_file)); ++ pseudo_file.fs = &pseudo_fs; ++ pseudo_file.size = header->size - sizeof (struct grub_module_header); ++ pseudo_file.data = (char *) header + sizeof (struct grub_module_header); ++ ++ grub_dprintf ("appendedsig", "found an x509 key, size=%" PRIuGRUB_UINT64_T "\n", ++ pseudo_file.size); ++ ++ err = grub_read_file (&pseudo_file, &cert_data, &cert_data_size); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ ++ err = add_certificate (cert_data, cert_data_size, &db, 1); ++ grub_free (cert_data); ++ ++ return err; ++} ++ ++/* releasing memory */ ++static void ++free_trusted_list (void) ++{ ++ struct x509_certificate *cert; ++ grub_size_t i = 0; ++ ++ while (db.keys != NULL) ++ { ++ cert = db.keys; ++ db.keys = db.keys->next; ++ certificate_release (cert); ++ grub_free (cert); ++ } ++ ++ for (i = 0; i < db.signature_entries; i++) ++ grub_free (db.signatures[i]); ++ ++ grub_free (db.signatures); ++ grub_free (db.signature_size); ++ grub_memset (&db, 0, sizeof (db)); ++} ++ ++/* releasing memory */ ++static void ++free_distrusted_list (void) ++{ ++ struct x509_certificate *cert; ++ grub_size_t i = 0; ++ ++ while (dbx.keys != NULL) ++ { ++ cert = dbx.keys; ++ dbx.keys = dbx.keys->next; ++ certificate_release (cert); ++ grub_free (cert); ++ } ++ ++ for (i = 0; i < dbx.signature_entries; i++) ++ grub_free (dbx.signatures[i]); ++ ++ grub_free (dbx.signatures); ++ grub_free (dbx.signature_size); ++ grub_memset (&dbx, 0, sizeof (dbx)); ++} ++ + GRUB_MOD_INIT (appendedsig) + { + int rc; +@@ -548,7 +1036,6 @@ GRUB_MOD_INIT (appendedsig) + if (grub_is_lockdown () == GRUB_LOCKDOWN_ENABLED) + check_sigs = check_sigs_forced; + +- grub_trusted_key = NULL; + grub_register_variable_hook ("check_appended_signatures", grub_env_read_sec, grub_env_write_sec); + grub_env_export ("check_appended_signatures"); + +@@ -556,37 +1043,50 @@ GRUB_MOD_INIT (appendedsig) + if (rc) + grub_fatal ("Error initing ASN.1 data structures: %d: %s\n", rc, asn1_strerror (rc)); + +- FOR_MODULES (header) +- { +- struct grub_file pseudo_file; +- struct x509_certificate *pk = NULL; +- grub_err_t err; ++ if (!grub_pks_use_keystore && check_sigs == check_sigs_forced) ++ { ++ FOR_MODULES (header) ++ { ++ /* Not an ELF module, skip. */ ++ if (header->type != OBJ_TYPE_X509_PUBKEY) ++ continue; + +- /* Not an X.509 certificate, skip. */ +- if (header->type != OBJ_TYPE_X509_PUBKEY) +- continue; ++ rc = build_static_trusted_list (header); ++ if (rc != GRUB_ERR_NONE) ++ { ++ free_trusted_list (); ++ grub_error (rc, "static trusted list creation failed"); ++ } ++ else ++ grub_dprintf ("appendedsig", "the trusted list now has %" PRIuGRUB_SIZE " static keys\n", ++ db.key_entries); ++ } ++ } ++ else if (grub_pks_use_keystore && check_sigs == check_sigs_forced) ++ { ++ rc = create_trusted_list (); ++ if (rc != GRUB_ERR_NONE) ++ { ++ free_trusted_list (); ++ grub_error (rc, "trusted list creation failed"); ++ } ++ else ++ { ++ rc = create_distrusted_list (); ++ if (rc != GRUB_ERR_NONE) ++ { ++ free_trusted_list (); ++ free_distrusted_list (); ++ grub_error (rc, "distrusted list creation failed"); ++ } ++ else ++ grub_dprintf ("appendedsig", "the trusted list now has %" PRIuGRUB_SIZE " keys.\n" ++ "the distrusted list now has %" PRIuGRUB_SIZE " keys.\n", ++ db.signature_entries + db.key_entries, dbx.signature_entries); ++ } + +- grub_memset (&pseudo_file, 0, sizeof (pseudo_file)); +- pseudo_file.fs = &pseudo_fs; +- pseudo_file.size = header->size - sizeof (struct grub_module_header); +- pseudo_file.data = (char *) header + sizeof (struct grub_module_header); +- +- grub_dprintf ("appendedsig", "Found an x509 key, size=%" PRIuGRUB_UINT64_T "\n", +- pseudo_file.size); +- +- pk = grub_zalloc (sizeof (struct x509_certificate)); +- if (!pk) +- grub_fatal ("Out of memory loading initial certificates"); +- +- err = read_cert_from_file (&pseudo_file, pk); +- if (err != GRUB_ERR_NONE) +- grub_fatal ("Error loading initial key: %s", grub_errmsg); +- +- grub_dprintf ("appendedsig", "loaded certificate CN='%s'\n", pk->subject); +- +- pk->next = grub_trusted_key; +- grub_trusted_key = pk; +- } ++ grub_pks_free_keystore (); ++ } + + cmd_trust = grub_register_command ("trust_certificate", grub_cmd_trust, N_("X509_CERTIFICATE"), + N_("Add X509_CERTIFICATE to trusted certificates.")); +diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c +index 58fae17..fa73c04 100644 +--- a/grub-core/kern/file.c ++++ b/grub-core/kern/file.c +@@ -256,3 +256,37 @@ grub_file_seek (grub_file_t file, grub_off_t offset) + + return old; + } ++ ++grub_err_t ++grub_read_file (const grub_file_t file, grub_uint8_t **data, grub_ssize_t *data_size) ++{ ++ grub_uint8_t *buffer = NULL; ++ grub_ssize_t read_size = 0; ++ grub_off_t total_read_size = 0; ++ grub_off_t file_size = grub_file_size (file); ++ ++ if (file_size == GRUB_FILE_SIZE_UNKNOWN) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("could not determine the size of the file.")); ++ ++ buffer = grub_zalloc (file_size); ++ if (buffer == NULL) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ ++ while (total_read_size < file_size) ++ { ++ read_size = grub_file_read (file, &buffer[total_read_size], file_size - total_read_size); ++ if (read_size < 0) ++ { ++ grub_free (buffer); ++ return grub_error (GRUB_ERR_READ_ERROR, N_("unable to read the file")); ++ } ++ ++ total_read_size += read_size; ++ } ++ ++ *data = buffer; ++ *data_size = total_read_size; ++ ++ return GRUB_ERR_NONE; ++} +diff --git a/include/grub/file.h b/include/grub/file.h +index d678de0..27e1a88 100644 +--- a/include/grub/file.h ++++ b/include/grub/file.h +@@ -217,6 +217,7 @@ grub_ssize_t EXPORT_FUNC(grub_file_read) (grub_file_t file, void *buf, + grub_size_t len); + grub_off_t EXPORT_FUNC(grub_file_seek) (grub_file_t file, grub_off_t offset); + grub_err_t EXPORT_FUNC(grub_file_close) (grub_file_t file); ++grub_err_t EXPORT_FUNC(grub_read_file) (const grub_file_t file, grub_uint8_t **data, grub_ssize_t *data_size); + + /* Return value of grub_file_size() in case file size is unknown. */ + #define GRUB_FILE_SIZE_UNKNOWN 0xffffffffffffffffULL diff --git a/SOURCES/0471-appendedsig-While-verifying-the-kernel-use-trusted-a.patch b/SOURCES/0471-appendedsig-While-verifying-the-kernel-use-trusted-a.patch new file mode 100644 index 0000000..2011cb7 --- /dev/null +++ b/SOURCES/0471-appendedsig-While-verifying-the-kernel-use-trusted-a.patch @@ -0,0 +1,250 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sudhakar Kuppusamy +Date: Thu, 27 Mar 2025 01:02:38 +0530 +Subject: [PATCH] appendedsig: While verifying the kernel, use trusted and + distrusted lists + +To verify the kernel's signature: verify the kernel binary against lists of binary hashes +that are either distrusted or trusted. If it is not list in either trusted or distrusted hashes list +then the trusted keys from the trusted key list are used to verify the signature. + +Signed-off-by: Sudhakar Kuppusamy +Reviewed-by: Stefan Berger +Reviewed-by: Avnish Chouhan +--- + grub-core/commands/appendedsig/appendedsig.c | 193 +++++++++++++++++++-------- + 1 file changed, 139 insertions(+), 54 deletions(-) + +diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c +index 994852f..07d6b39 100644 +--- a/grub-core/commands/appendedsig/appendedsig.c ++++ b/grub-core/commands/appendedsig/appendedsig.c +@@ -454,6 +454,83 @@ extract_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize, + return parse_pkcs7_signedData (appsigdata, pkcs7_size, &sig->pkcs7); + } + ++static grub_err_t ++get_binary_hash (const grub_size_t binary_hash_size, const grub_uint8_t *data, ++ const grub_size_t data_size, grub_uint8_t *hash, grub_size_t *hash_size) ++{ ++ grub_uuid_t guid = { 0 }; ++ ++ /* support SHA256, SHA384 and SHA512 for binary hash */ ++ if (binary_hash_size == 32) ++ grub_memcpy (&guid, &GRUB_PKS_CERT_SHA256_GUID, GRUB_UUID_SIZE); ++ else if (binary_hash_size == 48) ++ grub_memcpy (&guid, &GRUB_PKS_CERT_SHA384_GUID, GRUB_UUID_SIZE); ++ else if (binary_hash_size == 64) ++ grub_memcpy (&guid, &GRUB_PKS_CERT_SHA512_GUID, GRUB_UUID_SIZE); ++ else ++ { ++ grub_dprintf ("appendedsig", "unsupported hash type (%" PRIuGRUB_SIZE ") and skipping binary hash\n", ++ binary_hash_size); ++ return GRUB_ERR_UNKNOWN_COMMAND; ++ } ++ ++ return get_hash (&guid, data, data_size, hash, hash_size); ++} ++ ++/* ++ * Verify binary hash against the list of binary hashes that are distrusted ++ * and trusted. ++ * The following errors can occur: ++ * - GRUB_ERR_BAD_SIGNATURE: indicates that the hash is distrusted. ++ * - GRUB_ERR_NONE: the hash is trusted, since it was found in the trusted hashes list ++ * - GRUB_ERR_EOF: the hash could not be found in the hashes list ++ */ ++static grub_err_t ++verify_binary_hash (const grub_uint8_t *data, const grub_size_t data_size) ++{ ++ grub_err_t rc = GRUB_ERR_NONE; ++ grub_size_t i = 0, hash_size = 0; ++ grub_uint8_t hash[GRUB_MAX_HASH_SIZE] = { 0 }; ++ ++ for (i = 0; i < dbx.signature_entries; i++) ++ { ++ rc = get_binary_hash (dbx.signature_size[i], data, data_size, hash, &hash_size); ++ if (rc != GRUB_ERR_NONE) ++ continue; ++ ++ if (hash_size == dbx.signature_size[i] && ++ grub_memcmp (dbx.signatures[i], hash, hash_size) == 0) ++ { ++ grub_dprintf ("appendedsig", "the binary hash (%02x%02x%02x%02x) was listed as distrusted\n", ++ hash[0], hash[1], hash[2], hash[3]); ++ return GRUB_ERR_BAD_SIGNATURE; ++ } ++ } ++ ++ for (i = 0; i < db.signature_entries; i++) ++ { ++ rc = get_binary_hash (db.signature_size[i], data, data_size, hash, &hash_size); ++ if (rc != GRUB_ERR_NONE) ++ continue; ++ ++ if (hash_size == db.signature_size[i] && ++ grub_memcmp (db.signatures[i], hash, hash_size) == 0) ++ { ++ grub_dprintf ("appendedsig", "verified with a trusted binary hash (%02x%02x%02x%02x)\n", ++ hash[0], hash[1], hash[2], hash[3]); ++ return GRUB_ERR_NONE; ++ } ++ } ++ ++ return GRUB_ERR_EOF; ++} ++ ++ ++/* ++ * Verify the kernel's integrity, the trusted key will be used from ++ * the trusted key list. If it fails, verify it against the list of binary hashes ++ * that are distrusted and trusted. ++ */ + static grub_err_t + grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize) + { +@@ -463,12 +540,12 @@ grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize) + unsigned char *hash; + gcry_mpi_t hashmpi; + gcry_err_code_t rc; +- struct x509_certificate *pk; ++ struct x509_certificate *cert; + struct grub_appended_signature sig; + struct pkcs7_signerInfo *si; + int i; + +- if (!db.key_entries) ++ if (!db.key_entries && !db.signature_entries) + return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("No trusted keys to verify against")); + + err = extract_appended_signature (buf, bufsize, &sig); +@@ -476,69 +553,77 @@ grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize) + return err; + + datasize = bufsize - sig.signature_len; +- +- for (i = 0; i < sig.pkcs7.signerInfo_count; i++) ++ err = verify_binary_hash (buf, datasize); ++ if (err != GRUB_ERR_EOF && err != GRUB_ERR_NONE) + { +- /* +- * This could be optimised in a couple of ways: +- * - we could only compute hashes once per hash type +- * - we could track signer information and only verify where IDs match +- * For now we do the naive O(trusted keys * pkcs7 signers) approach. +- */ +- si = &sig.pkcs7.signerInfos[i]; +- context = grub_zalloc (si->hash->contextsize); +- if (!context) +- return grub_errno; +- +- si->hash->init (context); +- si->hash->write (context, buf, datasize); +- si->hash->final (context); +- hash = si->hash->read (context); +- +- grub_dprintf ("appendedsig", "data size %" PRIxGRUB_SIZE ", signer %d hash %02x%02x%02x%02x...\n", +- datasize, i, hash[0], hash[1], hash[2], hash[3]); +- +- err = GRUB_ERR_BAD_SIGNATURE; +- for (pk = db.keys; pk; pk = pk->next) ++ err = grub_error (err, N_("failed to verify binary-hash/signature with any trusted binary-hash/key\n")); ++ pkcs7_signedData_release (&sig.pkcs7); ++ return err; ++ } ++ else if (err == GRUB_ERR_EOF) ++ { ++ /* Binary hash was not found in trusted and distrusted list: check signature now */ ++ for (i = 0; i < sig.pkcs7.signerInfo_count; i++) + { +- rc = grub_crypto_rsa_pad (&hashmpi, hash, si->hash, pk->mpis[0]); +- if (rc) +- { +- err = grub_error (GRUB_ERR_BAD_SIGNATURE, +- N_("Error padding hash for RSA verification: %d"), rc); +- grub_free (context); +- goto cleanup; +- } ++ /* ++ * This could be optimised in a couple of ways: ++ * - we could only compute hashes once per hash type ++ * - we could track signer information and only verify where IDs match ++ * For now we do the naive O(db.keys * pkcs7 signers) approach. ++ */ ++ si = &sig.pkcs7.signerInfos[i]; ++ context = grub_zalloc (si->hash->contextsize); ++ if (context == NULL) ++ return grub_errno; + +- rc = _gcry_pubkey_spec_rsa.verify (0, hashmpi, &si->sig_mpi, pk->mpis, NULL, NULL); +- gcry_mpi_release (hashmpi); ++ si->hash->init (context); ++ si->hash->write (context, buf, datasize); ++ si->hash->final (context); ++ hash = si->hash->read (context); + +- if (rc == 0) +- { +- grub_dprintf ("appendedsig", "verify signer %d with key '%s' succeeded\n", +- i, pk->subject); +- err = GRUB_ERR_NONE; +- break; +- } ++ grub_dprintf ("appendedsig", ++ "data size %" PRIxGRUB_SIZE ", signer %d hash %02x%02x%02x%02x...\n", ++ datasize, i, hash[0], hash[1], hash[2], hash[3]); + +- grub_dprintf ("appendedsig", "verify signer %d with key '%s' failed with %d\n", +- i, pk->subject, rc); +- } ++ err = GRUB_ERR_BAD_SIGNATURE; ++ for (cert = db.keys; cert; cert = cert->next) ++ { ++ rc = grub_crypto_rsa_pad (&hashmpi, hash, si->hash, cert->mpis[0]); ++ if (rc != 0) ++ { ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, ++ N_("Error padding hash for RSA verification: %d"), rc); ++ grub_free (context); ++ pkcs7_signedData_release (&sig.pkcs7); ++ return err; ++ } + +- grub_free (context); ++ rc = _gcry_pubkey_spec_rsa.verify (0, hashmpi, &si->sig_mpi, cert->mpis, NULL, NULL); ++ gcry_mpi_release (hashmpi); ++ if (rc == 0) ++ { ++ grub_dprintf ("appendedsig", "verify signer %d with key '%s' succeeded\n", ++ i, cert->subject); ++ err = GRUB_ERR_NONE; ++ break; ++ } + +- if (err == GRUB_ERR_NONE) +- break; ++ grub_dprintf ("appendedsig", "verify signer %d with key '%s' failed with %d\n", ++ i, cert->subject, rc); ++ } ++ grub_free (context); ++ if (err == GRUB_ERR_NONE) ++ break; ++ } + } + +- /* If we didn't verify, provide a neat message */ +- if (err != GRUB_ERR_NONE) +- err = grub_error (GRUB_ERR_BAD_SIGNATURE, +- N_("Failed to verify signature against a trusted key")); +- +-cleanup: + pkcs7_signedData_release (&sig.pkcs7); + ++ if (err != GRUB_ERR_NONE) ++ err = grub_error (err, N_("failed to verify signature with any trusted key\n")); ++ else ++ grub_dprintf ("appendedsig", "successfully verified the signature with a trusted key\n"); ++ + return err; + } + diff --git a/SOURCES/0472-powerpc_ieee1275-set-use_static_keys-flag.patch b/SOURCES/0472-powerpc_ieee1275-set-use_static_keys-flag.patch new file mode 100644 index 0000000..f0837fc --- /dev/null +++ b/SOURCES/0472-powerpc_ieee1275-set-use_static_keys-flag.patch @@ -0,0 +1,107 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sudhakar Kuppusamy +Date: Thu, 27 Mar 2025 01:02:39 +0530 +Subject: [PATCH] powerpc_ieee1275: set use_static_keys flag + +Introduce the use_static_keys flag to indicate that static keys are to be used +rather than keys from the PKS storage's DB variable. This variable is set when +Secure Boot is enabled with PKS but the DB variable is not present in the PKS storage. +The appendedsig module would use this variable to extract the default DB keys from +the ELF note and store the keys found there in the trustedlist. + +Signed-off-by: Sudhakar Kuppusamy +Reviewed-by: Stefan Berger +Reviewed-by: Avnish Chouhan +--- + grub-core/kern/powerpc/ieee1275/platform_keystore.c | 16 +++++++++++++++- + grub-core/term/tparm.c | 1 - + include/grub/powerpc/ieee1275/platform_keystore.h | 11 ++++++----- + include/grub/types.h | 2 ++ + 4 files changed, 23 insertions(+), 7 deletions(-) + +diff --git a/grub-core/kern/powerpc/ieee1275/platform_keystore.c b/grub-core/kern/powerpc/ieee1275/platform_keystore.c +index cf1d055..a83fcf7 100644 +--- a/grub-core/kern/powerpc/ieee1275/platform_keystore.c ++++ b/grub-core/kern/powerpc/ieee1275/platform_keystore.c +@@ -34,7 +34,11 @@ + /* Platform Keystore */ + static grub_size_t pks_max_object_size; + grub_uint8_t grub_pks_use_keystore = 0; +-grub_pks_t grub_pks_keystore = { .db = NULL, .dbx = NULL, .db_entries = 0, .dbx_entries = 0 }; ++grub_pks_t grub_pks_keystore = { .db = NULL, ++ .dbx = NULL, ++ .db_entries = 0, ++ .dbx_entries = 0, ++ .use_static_keys = false }; + + /* Convert the esl data into the ESL */ + static grub_esl_t * +@@ -312,6 +316,16 @@ grub_pks_keystore_init (void) + grub_memset (&grub_pks_keystore, 0, sizeof (grub_pks_t)); + /* DB */ + rc = read_secure_boot_variables (0, DB, &grub_pks_keystore.db, &grub_pks_keystore.db_entries); ++ if (rc == PKS_OBJECT_NOT_FOUND) ++ { ++ rc = GRUB_ERR_NONE; ++ /* ++ * DB variable won't be available by default in PKS. ++ * So, it will load the Default Keys from ELF Note ++ */ ++ grub_pks_keystore.use_static_keys = true; ++ } ++ + if (rc == GRUB_ERR_NONE) + { + /* DBX */ +diff --git a/grub-core/term/tparm.c b/grub-core/term/tparm.c +index fb5b15a..f2db325 100644 +--- a/grub-core/term/tparm.c ++++ b/grub-core/term/tparm.c +@@ -46,7 +46,6 @@ + /* + * Common/troublesome character definitions + */ +-typedef char grub_bool_t; + #ifndef FALSE + # define FALSE (0) + #endif +diff --git a/include/grub/powerpc/ieee1275/platform_keystore.h b/include/grub/powerpc/ieee1275/platform_keystore.h +index 0641adb..870fb8c 100644 +--- a/include/grub/powerpc/ieee1275/platform_keystore.h ++++ b/include/grub/powerpc/ieee1275/platform_keystore.h +@@ -199,10 +199,11 @@ struct grub_pks_sd + /* The structure of a PKS.*/ + struct grub_pks + { +- grub_pks_sd_t *db; /* signature database */ +- grub_pks_sd_t *dbx; /* forbidden signature database */ +- grub_size_t db_entries; /* size of signature database */ +- grub_size_t dbx_entries; /* size of forbidden signature database */ ++ grub_pks_sd_t *db; /* signature database */ ++ grub_pks_sd_t *dbx; /* forbidden signature database */ ++ grub_size_t db_entries; /* size of signature database */ ++ grub_size_t dbx_entries; /* size of forbidden signature database */ ++ grub_bool_t use_static_keys;/* flag to indicate use of static keys */ + } GRUB_PACKED; + + #ifdef __powerpc__ +@@ -217,7 +218,7 @@ extern grub_pks_t EXPORT_VAR(grub_pks_keystore); + #else + + #define grub_pks_use_keystore 0 +-grub_pks_t grub_pks_keystore = {NULL, NULL, 0, 0}; ++grub_pks_t grub_pks_keystore = {NULL, NULL, 0, 0, false}; + void grub_pks_free_keystore (void); + + #endif +diff --git a/include/grub/types.h b/include/grub/types.h +index bfa7af9..32ca225 100644 +--- a/include/grub/types.h ++++ b/include/grub/types.h +@@ -353,4 +353,6 @@ struct grub_uuid + grub_uint8_t b[GRUB_UUID_SIZE]; + }; + ++typedef char grub_bool_t; ++ + #endif /* ! GRUB_TYPES_HEADER */ diff --git a/SOURCES/0473-appendedsig-Reads-the-default-DB-keys-from-ELF-Note.patch b/SOURCES/0473-appendedsig-Reads-the-default-DB-keys-from-ELF-Note.patch new file mode 100644 index 0000000..64f2b89 --- /dev/null +++ b/SOURCES/0473-appendedsig-Reads-the-default-DB-keys-from-ELF-Note.patch @@ -0,0 +1,108 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sudhakar Kuppusamy +Date: Thu, 27 Mar 2025 01:02:40 +0530 +Subject: [PATCH] appendedsig: Reads the default DB keys from ELF Note + +If Secure Boot is enabled with PKS and the use_static_keys flag is set, +then read the DB default keys from the ELF note and store them in the trusted list buffer. + +Signed-off-by: Sudhakar Kuppusamy +Reviewed-by: Stefan Berger +Reviewed-by: Avnish Chouhan +--- + grub-core/commands/appendedsig/appendedsig.c | 56 ++++++++++++++++++++-------- + 1 file changed, 40 insertions(+), 16 deletions(-) + +diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c +index 07d6b39..f51942b 100644 +--- a/grub-core/commands/appendedsig/appendedsig.c ++++ b/grub-core/commands/appendedsig/appendedsig.c +@@ -1041,7 +1041,7 @@ create_distrusted_list (void) + * parse it, and add it to the trusted list. + */ + static grub_err_t +-build_static_trusted_list (const struct grub_module_header *header) ++build_static_trusted_list (const struct grub_module_header *header, const grub_bool_t is_pks) + { + grub_err_t err = GRUB_ERR_NONE; + struct grub_file pseudo_file; +@@ -1060,6 +1060,13 @@ build_static_trusted_list (const struct grub_module_header *header) + if (err != GRUB_ERR_NONE) + return err; + ++ if (is_pks) ++ { ++ err = is_distrusted_cert_hash (cert_data, cert_data_size); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ } ++ + err = add_certificate (cert_data, cert_data_size, &db, 1); + grub_free (cert_data); + +@@ -1112,6 +1119,22 @@ free_distrusted_list (void) + grub_memset (&dbx, 0, sizeof (dbx)); + } + ++static grub_err_t ++load_static_keys (const struct grub_module_header *header, const grub_bool_t is_pks) ++{ ++ int rc = GRUB_ERR_NONE; ++ FOR_MODULES (header) ++ { ++ /* Not an ELF module, skip. */ ++ if (header->type != OBJ_TYPE_X509_PUBKEY) ++ continue; ++ rc = build_static_trusted_list (header, is_pks); ++ if (rc != GRUB_ERR_NONE) ++ return rc; ++ } ++ return rc; ++} ++ + GRUB_MOD_INIT (appendedsig) + { + int rc; +@@ -1130,26 +1153,27 @@ GRUB_MOD_INIT (appendedsig) + + if (!grub_pks_use_keystore && check_sigs == check_sigs_forced) + { +- FOR_MODULES (header) ++ rc = load_static_keys (header, false); ++ if (rc != GRUB_ERR_NONE) + { +- /* Not an ELF module, skip. */ +- if (header->type != OBJ_TYPE_X509_PUBKEY) +- continue; +- +- rc = build_static_trusted_list (header); +- if (rc != GRUB_ERR_NONE) +- { +- free_trusted_list (); +- grub_error (rc, "static trusted list creation failed"); +- } +- else +- grub_dprintf ("appendedsig", "the trusted list now has %" PRIuGRUB_SIZE " static keys\n", +- db.key_entries); ++ free_trusted_list (); ++ grub_error (rc, "static trusted list creation failed"); + } ++ else ++ grub_dprintf ("appendedsig", "the trusted list now has %" PRIuGRUB_SIZE " static keys\n", ++ db.key_entries); + } + else if (grub_pks_use_keystore && check_sigs == check_sigs_forced) + { +- rc = create_trusted_list (); ++ if (grub_pks_keystore.use_static_keys) ++ { ++ grub_printf ("Warning: db variable is not available at PKS and using a static keys " ++ "as a default key in trusted list\n"); ++ rc = load_static_keys (header, grub_pks_keystore.use_static_keys); ++ } ++ else ++ rc = create_trusted_list (); ++ + if (rc != GRUB_ERR_NONE) + { + free_trusted_list (); diff --git a/SOURCES/0474-appendedsig-The-grub-command-s-trusted-and-distruste.patch b/SOURCES/0474-appendedsig-The-grub-command-s-trusted-and-distruste.patch new file mode 100644 index 0000000..6dc51f6 --- /dev/null +++ b/SOURCES/0474-appendedsig-The-grub-command-s-trusted-and-distruste.patch @@ -0,0 +1,660 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sudhakar Kuppusamy +Date: Thu, 27 Mar 2025 01:02:41 +0530 +Subject: [PATCH] appendedsig: The grub command's trusted and distrusted + support + +To support the following trusted and distrusted commands + + 1. trusted_list: + It will show the list of trusted certificates and binary hashes + 2. distrusted_list: + It will show the list of distrusted certificates and binary/certificate hashes + 3. trusted_certificate: + It will add the trusted certificate to the trusted list + 4. trusted_signature: + It will add the certificate/binary hash to the trusted list + 5. distrusted_certificate: + It will remove the trusted certificate from trsuted list + 6. distrusted_signature: + It will add the certificate/binary hash to the distrsuted list + +Note:- + The addition/deletion of trusted certificates and binary hashes +are not allowed in grub command prompt while secure boot is enabled. + +Signed-off-by: Sudhakar Kuppusamy +Reviewed-by: Avnish Chouhan +--- + grub-core/commands/appendedsig/appendedsig.c | 528 ++++++++++++++++++--------- + 1 file changed, 356 insertions(+), 172 deletions(-) + +diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c +index f51942b..b8548f8 100644 +--- a/grub-core/commands/appendedsig/appendedsig.c ++++ b/grub-core/commands/appendedsig/appendedsig.c +@@ -117,6 +117,36 @@ static enum + check_sigs_forced = 2 + } check_sigs = check_sigs_no; + ++enum ++{ ++ OPTION_BINARY_HASH = 0, ++ OPTION_CERT_HASH = 1 ++}; ++ ++static const struct grub_arg_option options[] = ++{ ++ {"binary-hash", 'b', 0, N_("hash file of the binary."), 0, ARG_TYPE_NONE}, ++ {"cert-hash", 'c', 1, N_("hash file of the certificate."), 0, ARG_TYPE_NONE}, ++ {0, 0, 0, 0, 0, 0} ++}; ++ ++static void ++print_hex (const grub_uint8_t *data, const grub_size_t length) ++{ ++ grub_size_t i, count = 0; ++ for (i = 0; i < length-1; i++) ++ { ++ grub_printf ("%02x:", data[i]); ++ count++; ++ if (count == 16) ++ { ++ grub_printf ("\n\t "); ++ count = 0; ++ } ++ } ++ grub_printf ("%02x\n", data[i]); ++} ++ + /* + * GUID can be used to determine the hashing function and + * generate the hash using determined hashing function. +@@ -344,72 +374,6 @@ grub_env_write_sec (struct grub_env_var *var __attribute__ ((unused)), const cha + return grub_strdup (grub_env_read_sec (NULL, NULL)); + } + +-static grub_err_t +-file_read_all (grub_file_t file, grub_uint8_t **buf, grub_size_t *len) +-{ +- grub_off_t full_file_size; +- grub_size_t file_size, total_read_size = 0; +- grub_ssize_t read_size; +- +- full_file_size = grub_file_size (file); +- if (full_file_size == GRUB_FILE_SIZE_UNKNOWN) +- return grub_error (GRUB_ERR_BAD_ARGUMENT, +- N_("Cannot read a file of unknown size into a buffer")); +- +- if (full_file_size > GRUB_SIZE_MAX) +- return grub_error (GRUB_ERR_OUT_OF_RANGE, +- N_("File is too large to read: %" PRIuGRUB_UINT64_T " bytes"), +- full_file_size); +- +- file_size = (grub_size_t) full_file_size; +- +- *buf = grub_malloc (file_size); +- if (!*buf) +- return grub_error (GRUB_ERR_OUT_OF_MEMORY, +- N_("Could not allocate file data buffer size %" PRIuGRUB_SIZE), +- file_size); +- +- while (total_read_size < file_size) +- { +- read_size = grub_file_read (file, *buf + total_read_size, file_size - total_read_size); +- +- if (read_size < 0) +- { +- grub_free (*buf); +- return grub_errno; +- } +- else if (read_size == 0) +- { +- grub_free (*buf); +- return grub_error (GRUB_ERR_IO, +- N_("Could not read full file size " +- "(%" PRIuGRUB_SIZE "), only %" PRIuGRUB_SIZE " bytes read"), +- file_size, total_read_size); +- } +- +- total_read_size += read_size; +- } +- *len = file_size; +- return GRUB_ERR_NONE; +-} +- +-static grub_err_t +-read_cert_from_file (grub_file_t f, struct x509_certificate *certificate) +-{ +- grub_err_t err; +- grub_uint8_t *buf; +- grub_size_t file_size; +- +- err = file_read_all (f, &buf, &file_size); +- if (err != GRUB_ERR_NONE) +- return err; +- +- err = parse_x509_certificate (buf, file_size, certificate); +- grub_free (buf); +- +- return err; +-} +- + static grub_err_t + extract_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize, + struct grub_appended_signature *sig) +@@ -630,143 +594,345 @@ grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize) + static grub_err_t + grub_cmd_verify_signature (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) + { +- grub_file_t f; + grub_err_t err = GRUB_ERR_NONE; +- grub_uint8_t *data; +- grub_size_t file_size; ++ grub_file_t signed_file = NULL; ++ grub_uint8_t *signed_data = NULL; ++ grub_ssize_t signed_data_size = 0; + +- if (argc < 1) +- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); ++ if (argc != 1) ++ { ++ grub_printf (N_("a signed file is expected\n" ++ "Example:\n\tverify_appended \n")); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } + + grub_dprintf ("appendedsig", "verifying %s\n", args[0]); + +- f = grub_file_open (args[0], GRUB_FILE_TYPE_VERIFY_SIGNATURE); +- if (!f) ++ signed_file = grub_file_open (args[0], GRUB_FILE_TYPE_VERIFY_SIGNATURE); ++ if (signed_file == NULL) ++ return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("unable to open a signed file")); ++ ++ err = grub_read_file (signed_file, &signed_data, &signed_data_size); ++ if (err != GRUB_ERR_NONE) ++ { ++ grub_file_close (signed_file); ++ return err; ++ } ++ ++ grub_file_close (signed_file); ++ err = grub_verify_appended_signature (signed_data, signed_data_size); ++ grub_free (signed_data); ++ ++ return err; ++} ++ ++static grub_err_t ++grub_cmd_trusted_list (grub_command_t cmd __attribute__((unused)), ++ int argc __attribute__((unused)), char **args __attribute__((unused))) ++{ ++ struct x509_certificate *cert = NULL; ++ grub_size_t i = 0, cert_num = 1; ++ ++ for (cert = db.keys; cert; cert = cert->next) ++ { ++ grub_printf (N_("trusted certificate %" PRIuGRUB_SIZE ":\n"), cert_num); ++ grub_printf (N_("\tserial: ")); ++ ++ for (i = 0; i < cert->serial_len - 1; i++) ++ grub_printf ("%02x:", cert->serial[i]); ++ ++ grub_printf ("%02x\n", cert->serial[cert->serial_len - 1]); ++ grub_printf ("\tCN: %s\n\n", cert->subject); ++ cert_num++; ++ } ++ ++ for (i = 0; i < db.signature_entries; i++) ++ { ++ grub_printf (N_("trusted binary hash %" PRIuGRUB_SIZE ":\n"), i+1); ++ grub_printf (N_("\thash: ")); ++ print_hex (db.signatures[i], db.signature_size[i]); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_distrusted_list (grub_command_t cmd __attribute__((unused)), ++ int argc __attribute__((unused)), ++ char **args __attribute__((unused))) ++{ ++ struct x509_certificate *cert = NULL; ++ grub_size_t i = 0, cert_num = 1; ++ ++ for (cert = dbx.keys; cert; cert = cert->next) ++ { ++ grub_printf (N_("distrusted certificate %" PRIuGRUB_SIZE ":\n"), cert_num); ++ grub_printf (N_("\tserial: ")); ++ ++ for (i = 0; i < cert->serial_len - 1; i++) ++ grub_printf ("%02x:", cert->serial[i]); ++ ++ grub_printf ("%02x\n", cert->serial[cert->serial_len - 1]); ++ grub_printf ("\tCN: %s\n\n", cert->subject); ++ cert_num++; ++ } ++ ++ for (i = 0; i < dbx.signature_entries; i++) ++ { ++ grub_printf (N_("distrusted certificate/binary hash %" PRIuGRUB_SIZE ":\n"), i+1); ++ grub_printf (N_("\thash: ")); ++ print_hex (dbx.signatures[i], dbx.signature_size[i]); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_trusted_cert (grub_command_t cmd __attribute__((unused)), ++ int argc, char **args) ++{ ++ grub_err_t err = GRUB_ERR_NONE; ++ grub_file_t cert_file = NULL; ++ grub_uint8_t *cert_data = NULL; ++ grub_ssize_t cert_data_size = 0; ++ ++ if (argc != 1) + { +- err = grub_errno; +- goto cleanup; ++ grub_printf (N_("a trusted X.509 certificate file is expected\n" ++ "Example:\n\ttrusted_certificate \n")); ++ return GRUB_ERR_BAD_ARGUMENT; + } + +- err = file_read_all (f, &data, &file_size); ++ if (check_sigs == check_sigs_forced) ++ { ++ grub_printf ("Warning: since secure boot is enabled, " ++ "adding of trusted X.509 certificate is not permitted!\n"); ++ return grub_errno; ++ } ++ ++ if (grub_strlen (args[0]) == 0) ++ return grub_error (GRUB_ERR_BAD_FILENAME, ++ N_("missing trusted X.509 certificate file")); ++ ++ cert_file = grub_file_open (args[0], GRUB_FILE_TYPE_CERTIFICATE_TRUST | ++ GRUB_FILE_TYPE_NO_DECOMPRESS); ++ if (cert_file == NULL) ++ return grub_error (GRUB_ERR_FILE_NOT_FOUND, ++ N_("unable to open the trusted X.509 certificate file")); ++ ++ err = grub_read_file (cert_file, &cert_data, &cert_data_size); + if (err != GRUB_ERR_NONE) +- goto cleanup; ++ { ++ grub_file_close (cert_file); ++ return err; ++ } + +- err = grub_verify_appended_signature (data, file_size); ++ grub_file_close (cert_file); ++ err = add_certificate (cert_data, cert_data_size, &db, 1); ++ if (err != GRUB_ERR_NONE) ++ { ++ free_trusted_list (); ++ free_distrusted_list (); ++ grub_error (err, "adding of trusted certificate failed"); ++ } + +- grub_free (data); ++ grub_free (cert_data); + +-cleanup: +- if (f) +- grub_file_close (f); + return err; + } + + static grub_err_t +-grub_cmd_distrust (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) ++grub_cmd_trusted_hash (grub_command_t cmd __attribute__((unused)), int argc, char**args) + { +- unsigned long cert_num, i; +- struct x509_certificate *cert, *prev; ++ grub_err_t rc = GRUB_ERR_NONE; ++ grub_file_t hash_file = NULL; ++ grub_uint8_t *hash_data = NULL; ++ grub_ssize_t hash_data_size = 0; + + if (argc != 1) +- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("One argument expected")); ++ { ++ grub_printf (N_("a trusted binary hash file is expected\n" ++ "Example:\n\ttrusted_signature \n")); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ if (check_sigs == check_sigs_forced) ++ { ++ grub_printf ("Warning: since secure boot is enabled, " ++ "adding of trusted binary hash is not permitted!\n"); ++ return grub_errno; ++ } ++ ++ if (grub_strlen (args[0]) == 0) ++ return grub_error (GRUB_ERR_BAD_FILENAME, N_("missing trusted binary hash file")); ++ ++ hash_file = grub_file_open (args[0], GRUB_FILE_TYPE_TO_HASH | GRUB_FILE_TYPE_NO_DECOMPRESS); ++ if (hash_file == NULL) ++ return grub_error (GRUB_ERR_FILE_NOT_FOUND, ++ N_("unable to open the trusted binary hash file")); ++ ++ rc = grub_read_file (hash_file, &hash_data, &hash_data_size); ++ if (rc != GRUB_ERR_NONE) ++ { ++ grub_file_close (hash_file); ++ return rc; ++ } ++ ++ grub_file_close (hash_file); ++ ++ grub_dprintf ("appendedsig", "adding a trusted binary hash %s\n with size of %" PRIuGRUB_SIZE "\n", ++ hash_data, hash_data_size); ++ ++ /* only accept SHA256, SHA384 and SHA512 binary hash */ ++ if (hash_data_size != 32 && hash_data_size != 48 && hash_data_size != 64) ++ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("unacceptable trusted binary hash type")); ++ ++ rc = add_hash ((const grub_uint8_t **) &hash_data, hash_data_size, &db.signatures, ++ &db.signature_size, &db.signature_entries); ++ if (rc != GRUB_ERR_NONE) ++ { ++ free_trusted_list (); ++ free_distrusted_list (); ++ grub_error (rc, "adding of trusted binary hash failed"); ++ } ++ ++ grub_free (hash_data); ++ ++ return rc; ++} ++ ++static grub_err_t ++grub_cmd_distrusted_cert (grub_command_t cmd __attribute__((unused)), int argc, char **args) ++{ ++ grub_size_t cert_num = 0, i = 1; ++ struct x509_certificate *current_cert = db.keys; ++ struct x509_certificate *previous_cert = db.keys; ++ ++ if (argc != 1) ++ { ++ grub_printf (N_("trusted certificate number is expected\n" ++ "Example:\n\tdistrusted_certificate \n")); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ if (check_sigs == check_sigs_forced) ++ { ++ grub_printf ("Warning: since secure boot is enabled, " ++ "removing of trusted certificate is not permitted!\n"); ++ return grub_errno; ++ } + +- grub_errno = GRUB_ERR_NONE; + cert_num = grub_strtoul (args[0], NULL, 10); +- if (grub_errno != GRUB_ERR_NONE) +- return grub_errno; +- + if (cert_num < 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, +- N_("Certificate number too small - numbers start at 1")); ++ N_("trusted certificate number should to begin with 1")); + +- if (cert_num == 1) +- { +- cert = db.keys; +- db.keys = cert->next; ++ if (cert_num > db.key_entries) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("trusted certificate number should not exceed %" PRIuGRUB_SIZE ""), ++ db.key_entries); ++ else if (cert_num < db.key_entries) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("there is no certificate on the trusted list. so, not permitted")); + +- certificate_release (cert); +- grub_free (cert); +- return GRUB_ERR_NONE; +- } +- i = 2; +- prev = db.keys; +- cert = db.keys->next; +- while (cert) ++ for (i = 1; i < db.key_entries; i++) + { +- if (i == cert_num) ++ if (cert_num == 1) ++ { ++ previous_cert = current_cert->next; ++ break; ++ } ++ else if (cert_num == i) + { +- prev->next = cert->next; +- certificate_release (cert); +- grub_free (cert); +- return GRUB_ERR_NONE; ++ previous_cert->next = current_cert->next; ++ break; + } +- i++; +- prev = cert; +- cert = cert->next; ++ ++ previous_cert = current_cert; ++ current_cert = current_cert->next; + } + +- return grub_error (GRUB_ERR_BAD_ARGUMENT, +- N_("No certificate number %lu found - only %lu certificates in the store"), +- cert_num, i - 1); ++ certificate_release (current_cert); ++ grub_free (current_cert); ++ ++ return GRUB_ERR_NONE; + } + + static grub_err_t +-grub_cmd_trust (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) ++grub_cmd_distrusted_hash (grub_extcmd_context_t ctxt, int argc, char **args) + { +- grub_file_t certf; +- struct x509_certificate *cert = NULL; +- grub_err_t err; ++ grub_err_t rc = GRUB_ERR_NONE; ++ grub_file_t hash_file = NULL; ++ grub_uint8_t *hash_data = NULL; ++ grub_ssize_t hash_data_size = 0; + +- if (argc != 1) +- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); +- +- certf = grub_file_open (args[0], GRUB_FILE_TYPE_CERTIFICATE_TRUST | GRUB_FILE_TYPE_NO_DECOMPRESS); +- if (!certf) +- return grub_errno; +- +- cert = grub_zalloc (sizeof (struct x509_certificate)); +- if (!cert) +- return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("Could not allocate memory for certificate")); ++ if (argc != 2) ++ { ++ grub_printf (N_("a distrusted certificate/binary hash file is expected\n" ++ "Example:\n\tdistrusted_signature [option] \n" ++ "option:\n[-b|--binary-hash] FILE [BINARY HASH FILE]\n" ++ "[-c|--cert-hash] FILE [CERTFICATE HASH FILE]\n")); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } + +- err = read_cert_from_file (certf, cert); +- grub_file_close (certf); +- if (err != GRUB_ERR_NONE) ++ if (check_sigs == check_sigs_forced) + { +- grub_free (cert); +- return err; ++ grub_printf ("Warning: since secure boot is enabled, " ++ "adding of distrusted certificate/binary hash is not permitted!\n"); ++ return grub_errno; + } +- grub_dprintf ("appendedsig", "Loaded certificate with CN: %s\n", cert->subject); + +- cert->next = db.keys; +- db.keys = cert; ++ if (!ctxt->state[OPTION_BINARY_HASH].set && !ctxt->state[OPTION_CERT_HASH].set) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("missing options and use --help to konw")); + +- return GRUB_ERR_NONE; +-} ++ if (grub_strlen (args[1]) == 0) ++ return grub_error (GRUB_ERR_BAD_FILENAME, ++ N_("missing distrusted certificate/binary hash file")); + +-static grub_err_t +-grub_cmd_list (grub_command_t cmd __attribute__ ((unused)), int argc __attribute__ ((unused)), +- char **args __attribute__ ((unused))) +-{ +- struct x509_certificate *cert; +- int cert_num = 1; +- grub_size_t i; ++ hash_file = grub_file_open (args[1], GRUB_FILE_TYPE_TO_HASH | GRUB_FILE_TYPE_NO_DECOMPRESS); ++ if (hash_file == NULL) ++ return grub_error (GRUB_ERR_FILE_NOT_FOUND, ++ N_("unable to open the distrusted certificate/binary hash file")); + +- for (cert = db.keys; cert; cert = cert->next) ++ rc = grub_read_file (hash_file, &hash_data, &hash_data_size); ++ if (rc != GRUB_ERR_NONE) + { +- grub_printf (N_("Certificate %d:\n"), cert_num); ++ grub_file_close (hash_file); ++ return rc; ++ } + +- grub_printf (N_("\tSerial: ")); +- for (i = 0; i < cert->serial_len - 1; i++) +- { +- grub_printf ("%02x:", cert->serial[i]); +- } +- grub_printf ("%02x\n", cert->serial[cert->serial_len - 1]); ++ grub_file_close (hash_file); + +- grub_printf ("\tCN: %s\n\n", cert->subject); +- cert_num++; ++ grub_dprintf ("appendedsig", "adding a distrusted certificate/binary hash %s\n" ++ " with size of %" PRIuGRUB_SIZE "\n", hash_data, hash_data_size); ++ ++ if (ctxt->state[OPTION_BINARY_HASH].set) ++ { ++ /* only accept SHA256, SHA384 and SHA512 binary hash */ ++ if (hash_data_size != 32 && hash_data_size != 48 && hash_data_size != 64) ++ return grub_error (GRUB_ERR_BAD_SIGNATURE, ++ N_("unacceptable distrusted binary hash type")); ++ } ++ else if (ctxt->state[OPTION_CERT_HASH].set) ++ { ++ /* only accept SHA256, SHA384 and SHA512 certificate hash */ ++ if (hash_data_size != 32 && hash_data_size != 48 && hash_data_size != 64) ++ return grub_error (GRUB_ERR_BAD_SIGNATURE, ++ N_("unacceptable distrusted certificate hash type")); + } + +- return GRUB_ERR_NONE; ++ rc = add_hash ((const grub_uint8_t **) &hash_data, hash_data_size, &dbx.signatures, ++ &dbx.signature_size, &dbx.signature_entries); ++ if (rc != GRUB_ERR_NONE) ++ { ++ free_trusted_list (); ++ free_distrusted_list (); ++ grub_error (rc, "adding of distrusted binary/certificate hash failed"); ++ } ++ ++ grub_free (hash_data); ++ ++ return rc; + } + + static grub_err_t +@@ -842,8 +1008,6 @@ pseudo_read (struct grub_file *file, char *buf, grub_size_t len) + /* Filesystem descriptor. */ + static struct grub_fs pseudo_fs = { .name = "pseudo", .fs_read = pseudo_read }; + +-static grub_command_t cmd_verify, cmd_list, cmd_distrust, cmd_trust; +- + /* + * Verify the trusted certificate against the certificate hashes from platform keystore buffer's + * distrusted list. +@@ -1135,6 +1299,10 @@ load_static_keys (const struct grub_module_header *header, const grub_bool_t is_ + return rc; + } + ++static grub_extcmd_t cmd_distrusted_hash; ++static grub_command_t cmd_verify, cmd_trusted_list, cmd_trusted_cert, cmd_trusted_hash, ++ cmd_distrusted_list, cmd_distrusted_cert; ++ + GRUB_MOD_INIT (appendedsig) + { + int rc; +@@ -1196,17 +1364,31 @@ GRUB_MOD_INIT (appendedsig) + + grub_pks_free_keystore (); + } +- +- cmd_trust = grub_register_command ("trust_certificate", grub_cmd_trust, N_("X509_CERTIFICATE"), +- N_("Add X509_CERTIFICATE to trusted certificates.")); +- cmd_list = grub_register_command ("list_certificates", grub_cmd_list, 0, +- N_("Show the list of trusted x509 certificates.")); ++ cmd_trusted_cert = grub_register_command ("trusted_certificate", grub_cmd_trusted_cert, ++ N_("X509_CERTIFICATE"), ++ N_("Add X509_CERTIFICATE to trusted list.")); ++ cmd_trusted_hash = grub_register_command ("trusted_signature", grub_cmd_trusted_hash, ++ N_("BINARY HASH FILE"), ++ N_("Add trusted BINARY HASH to trusted list.")); ++ cmd_distrusted_cert = grub_register_command ("distrusted_certificate", grub_cmd_distrusted_cert, ++ N_("CERT_NUMBER"), ++ N_("Remove CERT_NUMBER (as listed by list_trusted)" ++ " from trusted list.")); ++ cmd_distrusted_hash = grub_register_extcmd ("distrusted_signature", grub_cmd_distrusted_hash, 0, ++ N_("[-b|--binary-hash] FILE [BINARY HASH FILE]\n" ++ "[-c|--cert-hash] FILE [CERTFICATE HASH FILE]"), ++ N_("Add distrusted CERTFICATE/BINARY HASH " ++ "to distrusted list."), ++ options); ++ cmd_trusted_list = grub_register_command ("trusted_list", grub_cmd_trusted_list, 0, ++ N_("Show the list of trusted x509 certificates and" ++ " trusted binary hashes.")); ++ cmd_distrusted_list = grub_register_command ("distrusted_list", grub_cmd_distrusted_list, 0, ++ N_("Show the list of distrusted certificates and" ++ " certificate/binary hashes")); + cmd_verify = grub_register_command ("verify_appended", grub_cmd_verify_signature, N_("FILE"), +- N_("Verify FILE against the trusted x509 certificates.")); +- cmd_distrust = grub_register_command ("distrust_certificate", grub_cmd_distrust, +- N_("CERT_NUMBER"), +- N_("Remove CERT_NUMBER (as listed by list_certificates)" +- " from trusted certificates.")); ++ N_("Verify FILE against the trusted x509 certificates/" ++ "trusted binary hashes.")); + + grub_verifier_register (&grub_appendedsig_verifier); + grub_dl_set_persistent (mod); +@@ -1218,10 +1400,12 @@ GRUB_MOD_FINI (appendedsig) + * grub_dl_set_persistent should prevent this from actually running, but + * it does still run under emu. + */ +- + grub_verifier_unregister (&grub_appendedsig_verifier); + grub_unregister_command (cmd_verify); +- grub_unregister_command (cmd_list); +- grub_unregister_command (cmd_trust); +- grub_unregister_command (cmd_distrust); ++ grub_unregister_command (cmd_trusted_list); ++ grub_unregister_command (cmd_distrusted_list); ++ grub_unregister_command (cmd_trusted_cert); ++ grub_unregister_command (cmd_distrusted_cert); ++ grub_unregister_command (cmd_trusted_hash); ++ grub_unregister_extcmd (cmd_distrusted_hash); + } diff --git a/SOURCES/0475-appendedsig-documentation.patch b/SOURCES/0475-appendedsig-documentation.patch new file mode 100644 index 0000000..1d78f42 --- /dev/null +++ b/SOURCES/0475-appendedsig-documentation.patch @@ -0,0 +1,210 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sudhakar Kuppusamy +Date: Thu, 27 Mar 2025 01:02:42 +0530 +Subject: [PATCH] appendedsig: documentation + +This explains how static and dynamic key appended signatures can be used to form part of +a secure boot chain, and documents the commands and variables introduced. + +Signed-off-by: Sudhakar Kuppusamy +Reviewed-by: Avnish Chouhan +--- + docs/grub.texi | 109 +++++++++++++++++++++++++++++++++++++++------------------ + 1 file changed, 74 insertions(+), 35 deletions(-) + +diff --git a/docs/grub.texi b/docs/grub.texi +index 72cf517..a4ae8cd 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -4016,7 +4016,9 @@ you forget a command, you can run the command @command{help} + * date:: Display or set current date and time + * devicetree:: Load a device tree blob + * distrust:: Remove a pubkey from trusted keys +-* distrust_certificate:: Remove a certificate from the list of trusted certificates ++* distrusted_certificate:: Remove a certificate from the trusted list ++* distrusted_list:: List distrusted certificates and binary/certificate hashes ++* distrusted_signature:: Add a binary hash to the distrusted list + * drivemap:: Map a drive to another + * echo:: Display a line of text + * eval:: Evaluate agruments as GRUB commands +@@ -4033,7 +4035,6 @@ you forget a command, you can run the command @command{help} + * keystatus:: Check key modifier status + * linux:: Load a Linux kernel + * linux16:: Load a Linux kernel (16-bit mode) +-* list_certificates:: List trusted certificates + * list_env:: List variables in environment block + * list_trusted:: List trusted public keys + * load_env:: Load variables from environment block +@@ -4072,7 +4073,9 @@ you forget a command, you can run the command @command{help} + * test:: Check file types and compare values + * true:: Do nothing, successfully + * trust:: Add public key to list of trusted keys +-* trust_certificate:: Add an x509 certificate to the list of trusted certificates ++* trusted_certificate:: Add an x509 certificate to the trusted list ++* trusted_list:: List trusted certificates and binary hashes ++* trusted_signature:: Add a binary hash to the trusted list. + * unset:: Unset an environment variable + @comment * vbeinfo:: List available video modes + * verify_appended:: Verify appended digital signature +@@ -4416,16 +4419,15 @@ These keys are used to validate signatures when environment variable + GPG-style digital signatures}, for more information. + @end deffn + ++@node distrusted_certificate ++@subsection distrusted_certificate + +-@node distrust_certificate +-@subsection distrust_certificate +- +-@deffn Command distrust_certificate cert_number ++@deffn Command distrusted_certificate cert_number + Remove the x509 certificate numbered @var{cert_number} from GRUB's keyring of + trusted x509 certificates for verifying appended signatures. + + @var{cert_number} is the certificate number as listed by +-@command{list_certificates} (@pxref{list_certificates}). ++@command{trusted_list} (@pxref{trusted_list}). + + These certificates are used to validate appended signatures when environment + variable @code{check_appended_signatures} is set to @code{enforce} or +@@ -4434,6 +4436,27 @@ variable @code{check_appended_signatures} is set to @code{enforce} or + @xref{Using appended signatures} for more information. + @end deffn + ++@node distrusted_list ++@subsection distrusted_list ++ ++@deffn Command distrusted_list ++List all the distrusted x509 certificates and binary/certificate hashes. ++The output is a numbered list of certificates and binary/certificate hashes, ++showing the certificate's serial number and Common Name. ++@end deffn ++ ++@node distrusted_signature ++@subsection distrusted_signature ++ ++@deffn Command distrusted_signature ++Read a binary hash from the file @var{binary hash file} ++and add it to GRUB's internal distrusted list. These hash are used to ++restrict validation of linux image integrity using trusted list if appended ++signatures validation failed when the environment variable ++@code{check_appended_signatures} is set to @code{enforce}. ++ ++See @xref{Using appended signatures} for more information. ++@end deffn + + @node drivemap + @subsection drivemap +@@ -4691,22 +4714,6 @@ for the sake of convenience. + This command is only available on x86 systems. + @end deffn + +- +-@node list_certificates +-@subsection list_certificates +- +-@deffn Command list_certificates +-List all x509 certificates trusted by GRUB for validating appended signatures. +-The output is a numbered list of certificates, showing the certificate's serial +-number and Common Name. +- +-The certificate number can be used as an argument to +-@command{distrust_certificate} (@pxref{distrust_certificate}). +- +-See @xref{Using appended signatures} for more information. +-@end deffn +- +- + @node list_env + @subsection list_env + +@@ -5540,10 +5547,10 @@ information. + @end deffn + + +-@node trust_certificate +-@subsection trust_certificate ++@node trusted_certificate ++@subsection trusted_certificate + +-@deffn Command trust_certificate x509_certificate ++@deffn Command trusted_certificate x509_certificate + Read an DER-formatted x509 certificate from the file @var{x509_certificate} + and add it to GRUB's internal list of trusted x509 certificates. These + certificates are used to validate appended signatures when the environment +@@ -5551,7 +5558,7 @@ variable @code{check_appended_signatures} is set to @code{enforce} or + @code{forced}. + + Note that if @code{check_appended_signatures} is set to @code{enforce} or +-@code{forced} when @command{trust_certificate} is executed, then ++@code{forced} when @command{trusted_certificate} is executed, then + @var{x509_certificate} must itself bear an appended signature. (It is not + sufficient that @var{x509_certificate} be signed by a trusted certificate + according to the x509 rules: grub does not include support for validating +@@ -5560,6 +5567,32 @@ signatures within x509 certificates themselves.) + See @xref{Using appended signatures} for more information. + @end deffn + ++@node trusted_list ++@subsection trusted_list ++ ++@deffn Command trusted_list ++List all x509 certificates and binary hases trusted by GRUB for validating ++appended signatures. The output is a numbered list of certificates and binary ++hashes, showing the certificate's serial number and Common Name. ++ ++The certificate number can be used as an argument to ++@command{distrusted_certificate} (@pxref{distrusted_certificate}). ++ ++See @xref{Using appended signatures} for more information. ++@end deffn ++ ++@node trusted_signature ++@subsection trusted_signature ++ ++@deffn Command trust_signature ++Read a binary hash from the file @var{binary hash file} ++and add it to GRUB's internal trusted list. These binary hash are used to ++validate linux image integrity if appended signatures validation failed ++when the environment variable @code{check_appended_signatures} is set ++to @code{enforce}. ++ ++See @xref{Using appended signatures} for more information. ++@end deffn + + @node unset + @subsection unset +@@ -5584,9 +5617,8 @@ only on PC BIOS platforms. + + @deffn Command verify_appended file + Verifies an appended signature on @var{file} against the trusted certificates +-known to GRUB (See @pxref{list_certificates}, @pxref{trust_certificate}, and +-@pxref{distrust_certificate}). +- ++known to GRUB (See @pxref{trusted_list}, @pxref{trusted_certificate}, and ++@pxref{distrusted_certificate}). + Exit code @code{$?} is set to 0 if the signature validates + successfully. If validation fails, it is set to a non-zero value. + See @xref{Using appended signatures}, for more information. +@@ -6183,10 +6215,17 @@ with an appended signature ends with the magic string: + + where @code{\n} represents the line-feed character, @code{0x0a}. + +-Certificates can be managed at boot time using the @pxref{trust_certificate}, +-@pxref{distrust_certificate} and @pxref{list_certificates} commands. +-Certificates can also be built in to the core image using the @code{--x509} +-parameter to @command{grub-install} or @command{grub-mkimage}. ++For static key, Certificates will be built in to the core image using ++the @code{--x509} parameter to @command{grub-install} or @command{grub-mkimage}. ++it can allow to list the trusted certificates and binary hashes at boot time using ++@pxref{trusted_list} and list distrusted certificates and binary/certificate hashes ++at boot time using @pxref{distrusted_list} commands. ++ ++For dynamic key, loads the signature database (DB) and forbidden ++signature database (DBX) from platform keystore (PKS) and it can allow to list ++the trusted certificates and binary hashes at boot time using @pxref{trusted_list} ++and list distrusted certificates and binary/certificate hashes at boot time using ++@pxref{distrusted_list} commands. + + A file can be explictly verified using the @pxref{verify_appended} command. + diff --git a/SOURCES/0476-efi-Add-efitextmode-command-for-getting-setting-the-.patch b/SOURCES/0476-efi-Add-efitextmode-command-for-getting-setting-the-.patch new file mode 100644 index 0000000..0d1d43a --- /dev/null +++ b/SOURCES/0476-efi-Add-efitextmode-command-for-getting-setting-the-.patch @@ -0,0 +1,301 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Fri, 22 Jul 2022 02:16:33 -0500 +Subject: [PATCH] efi: Add efitextmode command for getting/setting the text + mode resolution + +This command is meant to behave similarly to the "mode" command of the EFI +Shell application. In addition to allowing mode selection by giving the +number of columns and rows as arguments, the command allows specifying the +mode number to select the mode. Also supported are the arguments "min" and +"max", which set the mode to the minimum and maximum mode respectively as +calculated by the columns * rows of that mode. + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + docs/grub.texi | 42 ++++++++++ + grub-core/Makefile.core.def | 6 ++ + grub-core/commands/efi/efitextmode.c | 155 +++++++++++++++++++++++++++++++++++ + include/grub/efi/api.h | 6 ++ + include/grub/err.h | 1 + + 5 files changed, 210 insertions(+) + create mode 100644 grub-core/commands/efi/efitextmode.c + +diff --git a/docs/grub.texi b/docs/grub.texi +index a4ae8cd..2677059 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -4021,6 +4021,7 @@ you forget a command, you can run the command @command{help} + * distrusted_signature:: Add a binary hash to the distrusted list + * drivemap:: Map a drive to another + * echo:: Display a line of text ++* efitextmode:: Set/Get text output mode resolution + * eval:: Evaluate agruments as GRUB commands + * export:: Export an environment variable + * false:: Do nothing, unsuccessfully +@@ -4527,6 +4528,47 @@ character will print that character. + @end deffn + + ++@node efitextmode ++@subsection efitextmode ++ ++@deffn Command efitextmode [min | max | | ] ++When used with no arguments displays all available text output modes. The ++set mode determines the columns and rows of the text display when in ++text mode. An asterisk, @samp{*}, will be at the end of the line of the ++currently set mode. ++ ++If given a single parameter, it must be @samp{min}, @samp{max}, or a mode ++number given by the listing when run with no arguments. These arguments set ++the mode to the minimum, maximum, and particular mode respectively. ++ ++Otherwise, the command must be given two numerical arguments specifying the ++columns and rows of the desired mode. Specifying a columns and rows ++combination that corresponds to no supported mode, will return error, but ++otherwise have no effect. ++ ++By default GRUB will start in whatever mode the EFI firmware defaults to. ++There are firmwares known to set up the default mode such that output ++behaves strangely, for example the cursor in the GRUB shell never reaches ++the bottom of the screen or, when typing characters at the prompt, ++characters from previous command output are overwritten. Setting the mode ++may fix this. ++ ++The EFI specification says that mode 0 must be available and have ++columns and rows of 80 and 25 respectively. Mode 1 may be defined and if ++so must have columns and rows of 80 and 50 respectively. Any other modes ++may have columns and rows arbitrarily defined by the firmware. This means ++that a mode with columns and rows of 100 and 31 on one firmware may be ++a different mode number on a different firmware or not exist at all. ++Likewise, mode number 2 on one firmware may have a different number of ++columns and rows than mode 2 on a different firmware. So one should not ++rely on a particular mode number or a mode of a certain number of columns ++and rows existing on all firmwares, except for mode 0. ++ ++Note: This command is only available on EFI platforms and is similar to ++EFI shell "mode" command. ++@end deffn ++ ++ + @node eval + @subsection eval + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 218068b..4588fa7 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -844,6 +844,12 @@ module = { + enable = efi; + }; + ++module = { ++ name = efitextmode; ++ efi = commands/efi/efitextmode.c; ++ enable = efi; ++}; ++ + module = { + name = blocklist; + common = commands/blocklist.c; +diff --git a/grub-core/commands/efi/efitextmode.c b/grub-core/commands/efi/efitextmode.c +new file mode 100644 +index 0000000..3679f6b +--- /dev/null ++++ b/grub-core/commands/efi/efitextmode.c +@@ -0,0 +1,155 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ * ++ * Set/Get UEFI text output mode resolution. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++static grub_err_t ++grub_efi_set_mode (grub_efi_simple_text_output_interface_t *o, ++ grub_efi_int32_t mode) ++{ ++ grub_efi_status_t status; ++ ++ if (mode != o->mode->mode) ++ { ++ status = efi_call_2 (o->set_mode, o, mode); ++ if (status == GRUB_EFI_SUCCESS) ++ ; ++ else if (status == GRUB_EFI_DEVICE_ERROR) ++ return grub_error (GRUB_ERR_BAD_DEVICE, ++ N_("device error: could not set requested mode")); ++ else if (status == GRUB_EFI_UNSUPPORTED) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("invalid mode: number not valid")); ++ else ++ return grub_error (GRUB_ERR_BAD_FIRMWARE, ++ N_("unexpected EFI error number: `%u'"), ++ (unsigned) status); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_efitextmode (grub_command_t cmd __attribute__ ((unused)), ++ int argc, char **args) ++{ ++ grub_efi_simple_text_output_interface_t *o = grub_efi_system_table->con_out; ++ unsigned long mode; ++ const char *p = NULL; ++ grub_err_t err; ++ grub_efi_uintn_t columns, rows; ++ grub_efi_int32_t i; ++ ++ if (o == NULL) ++ return grub_error (GRUB_ERR_BAD_DEVICE, N_("no UEFI output console interface")); ++ ++ if (o->mode == NULL) ++ return grub_error (GRUB_ERR_BUG, N_("no mode struct for UEFI output console")); ++ ++ if (argc > 2) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("at most two arguments expected")); ++ ++ if (argc == 0) ++ { ++ grub_printf_ (N_("Available modes for console output device.\n")); ++ ++ for (i = 0; i < o->mode->max_mode; i++) ++ if (GRUB_EFI_SUCCESS == efi_call_4 (o->query_mode, o, i, ++ &columns, &rows)) ++ grub_printf_ (N_(" [%" PRIuGRUB_EFI_UINT32_T "] Col %5" ++ PRIuGRUB_EFI_UINTN_T " Row %5" PRIuGRUB_EFI_UINTN_T ++ " %c\n"), ++ i, columns, rows, (i == o->mode->mode) ? '*' : ' '); ++ } ++ else if (argc == 1) ++ { ++ if (grub_strcmp (args[0], "min") == 0) ++ mode = 0; ++ else if (grub_strcmp (args[0], "max") == 0) ++ mode = o->mode->max_mode - 1; ++ else ++ { ++ mode = grub_strtoul (args[0], &p, 0); ++ ++ if (*args[0] == '\0' || *p != '\0') ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("non-numeric or invalid mode `%s'"), args[0]); ++ } ++ ++ if (mode < (unsigned long) o->mode->max_mode) ++ { ++ err = grub_efi_set_mode (o, (grub_efi_int32_t) mode); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ } ++ else ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("invalid mode: `%lu' is greater than maximum mode `%lu'"), ++ mode, (unsigned long) o->mode->max_mode); ++ } ++ else if (argc == 2) ++ { ++ grub_efi_uintn_t u_columns, u_rows; ++ ++ u_columns = (grub_efi_uintn_t) grub_strtoul (args[0], &p, 0); ++ ++ if (*args[0] == '\0' || *p != '\0') ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("non-numeric or invalid columns number `%s'"), args[0]); ++ ++ u_rows = (grub_efi_uintn_t) grub_strtoul (args[1], &p, 0); ++ ++ if (*args[1] == '\0' || *p != '\0') ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("non-numeric or invalid rows number `%s'"), args[1]); ++ ++ for (i = 0; i < o->mode->max_mode; i++) ++ if (GRUB_EFI_SUCCESS == efi_call_4 (o->query_mode, o, i, ++ &columns, &rows)) ++ if (u_columns == columns && u_rows == rows) ++ return grub_efi_set_mode (o, (grub_efi_int32_t) i); ++ ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("no mode found with requested columns and rows")); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_command_t cmd; ++GRUB_MOD_INIT (efitextmode) ++{ ++ cmd = grub_register_command ("efitextmode", grub_cmd_efitextmode, ++ N_("[min | max | | ]"), ++ N_("Get or set EFI text mode.")); ++} ++ ++GRUB_MOD_FINI (efitextmode) ++{ ++ grub_unregister_command (cmd); ++} +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index 464842b..f224037 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -545,9 +545,13 @@ typedef char grub_efi_boolean_t; + #if GRUB_CPU_SIZEOF_VOID_P == 8 + typedef grub_int64_t grub_efi_intn_t; + typedef grub_uint64_t grub_efi_uintn_t; ++#define PRIxGRUB_EFI_UINTN_T PRIxGRUB_UINT64_T ++#define PRIuGRUB_EFI_UINTN_T PRIuGRUB_UINT64_T + #else + typedef grub_int32_t grub_efi_intn_t; + typedef grub_uint32_t grub_efi_uintn_t; ++#define PRIxGRUB_EFI_UINTN_T PRIxGRUB_UINT32_T ++#define PRIuGRUB_EFI_UINTN_T PRIuGRUB_UINT32_T + #endif + typedef grub_int8_t grub_efi_int8_t; + typedef grub_uint8_t grub_efi_uint8_t; +@@ -555,6 +559,8 @@ typedef grub_int16_t grub_efi_int16_t; + typedef grub_uint16_t grub_efi_uint16_t; + typedef grub_int32_t grub_efi_int32_t; + typedef grub_uint32_t grub_efi_uint32_t; ++#define PRIxGRUB_EFI_UINT32_T PRIxGRUB_UINT32_T ++#define PRIuGRUB_EFI_UINT32_T PRIuGRUB_UINT32_T + typedef grub_int64_t grub_efi_int64_t; + typedef grub_uint64_t grub_efi_uint64_t; + typedef grub_uint8_t grub_efi_char8_t; +diff --git a/include/grub/err.h b/include/grub/err.h +index 905a6df..7530f58 100644 +--- a/include/grub/err.h ++++ b/include/grub/err.h +@@ -73,6 +73,7 @@ typedef enum + GRUB_ERR_NET_NO_DOMAIN, + GRUB_ERR_EOF, + GRUB_ERR_BAD_SIGNATURE, ++ GRUB_ERR_BAD_FIRMWARE, + GRUB_ERR_STILL_REFERENCED, + GRUB_ERR_RECURSION_DEPTH + } diff --git a/SOURCES/0477-10_linux.in-escape-kernel-option-characters-properly.patch b/SOURCES/0477-10_linux.in-escape-kernel-option-characters-properly.patch new file mode 100644 index 0000000..1937cb9 --- /dev/null +++ b/SOURCES/0477-10_linux.in-escape-kernel-option-characters-properly.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Leo Sandoval +Date: Wed, 7 May 2025 13:23:37 -0600 +Subject: [PATCH] 10_linux.in: escape kernel option characters properly + +This handles cases where kernel options, specifically the values, +contain special characters, in this case ';', '&' and '$'. + +For example, the user defines the following GRUB_CMDLINE_LINUX on the +default grub file /etc/default/grub, note the dolar sign on the 'memmap' +option + + GRUB_CMDLINE_LINUX="console=ttyS0 memmap=32g\\\$0x2000000000" + +then regenerating the grub cfg and BLS options line with the +grub2-mkconfig command, resulting into + + options root=UUID=6baedf23-2510-499a-815d-48b58cf6e619 ro + rootflags=subvol=root console=ttyS0 memmap=32g\$0x2000000000 + +without this patch, we would end up with + + options root=UUID=6baedf23-2510-499a-815d-48b58cf6e619 ro + rootflags=subvol=root console=ttyS0 memmap=32g$0x2000000000 + +Note the missing '\' which is required to escape the '$', otherwise +it would be consider a variable by blscfg parser which is not the case. + +Signed-off-by: Leo Sandoval +--- + util/grub.d/10_linux.in | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index fafdfbc4d3..4276d5e240 100755 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -180,6 +180,7 @@ update_bls_cmdline() + options="$(echo "${options}" | sed -e 's/\//\\\//g')" + options="$(echo "${options}" | sed -e 's/\;/\\\;/g')" + options="$(echo "${options}" | sed -e 's/\\&/\\\\&/g')" ++ options="$(echo "${options}" | sed -e 's/\$/\\\$/g')" + sed -i -e "s/^options.*/options ${options}/" "${blsdir}/${bls}.conf" + done + } diff --git a/SOURCES/0478-blscfg-check-if-variable-is-escaped-before-consideri.patch b/SOURCES/0478-blscfg-check-if-variable-is-escaped-before-consideri.patch new file mode 100644 index 0000000..fba6906 --- /dev/null +++ b/SOURCES/0478-blscfg-check-if-variable-is-escaped-before-consideri.patch @@ -0,0 +1,26 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Leo Sandoval +Date: Wed, 7 May 2025 13:49:47 -0600 +Subject: [PATCH] blscfg: check if variable is escaped before considering one + +Otherwise escaped variables are considered real variables. + +Signed-off-by: Leo Sandoval +--- + grub-core/commands/blscfg.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c +index 6e398fc175..5d931b0c9b 100644 +--- a/grub-core/commands/blscfg.c ++++ b/grub-core/commands/blscfg.c +@@ -695,7 +695,8 @@ static char *expand_val(const char *value) + return NULL; + + while (*value) { +- if (*value == '$') { ++ /* It's a variable only when *value is '$' and it is not escaped with '\'*/ ++ if (*value == '$' && *end != '\\') { + if (start != end) { + buffer = field_append(is_var, buffer, start, end); + if (!buffer) diff --git a/SOURCES/0479-osdep-linux-getroot-Detect-DDF-container-similar-to-.patch b/SOURCES/0479-osdep-linux-getroot-Detect-DDF-container-similar-to-.patch new file mode 100644 index 0000000..07d7d29 --- /dev/null +++ b/SOURCES/0479-osdep-linux-getroot-Detect-DDF-container-similar-to-.patch @@ -0,0 +1,86 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Renaud=20M=C3=A9trich?= +Date: Thu, 24 Apr 2025 11:43:28 +0200 +Subject: [PATCH] osdep/linux/getroot: Detect DDF container similar to IMSM +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Similarly to Intel IMSM, there are BIOS and UEFI implementations that +support DDF containers natively. + +DDF and IMSM are very similar in handling, especially these should not +be considered as RAID abstraction. This fixes the requirement of having +a device map when probing DDF containers. + +Fixes: https://issues.redhat.com/browse/RHEL-44336 + +Signed-off-by: Renaud Métrich +Reviewed-by: Daniel Kiper +--- + grub-core/osdep/linux/getroot.c | 19 +++++++++++++------ + 1 file changed, 13 insertions(+), 6 deletions(-) + +diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c +index 893527a..7430391 100644 +--- a/grub-core/osdep/linux/getroot.c ++++ b/grub-core/osdep/linux/getroot.c +@@ -131,7 +131,7 @@ struct btrfs_ioctl_search_args { + struct btrfs_ioctl_fs_info_args) + + static int +-grub_util_is_imsm (const char *os_dev); ++grub_util_is_imsm_or_ddf (const char *os_dev); + + + #define ESCAPED_PATH_MAX (4 * PATH_MAX) +@@ -762,10 +762,10 @@ out: + } + + static int +-grub_util_is_imsm (const char *os_dev) ++grub_util_is_imsm_or_ddf (const char *os_dev) + { + int retry; +- int is_imsm = 0; ++ int is_imsm_or_ddf = 0; + int container_seen = 0; + const char *dev = os_dev; + +@@ -826,10 +826,17 @@ grub_util_is_imsm (const char *os_dev) + if (strncmp (buf, "MD_METADATA=imsm", + sizeof ("MD_METADATA=imsm") - 1) == 0) + { +- is_imsm = 1; ++ is_imsm_or_ddf = 1; + grub_util_info ("%s is imsm", dev); + break; + } ++ if (strncmp (buf, "MD_METADATA=ddf", ++ sizeof ("MD_METADATA=ddf") - 1) == 0) ++ { ++ is_imsm_or_ddf = 1; ++ grub_util_info ("%s is ddf", dev); ++ break; ++ } + } + + free (buf); +@@ -840,7 +847,7 @@ grub_util_is_imsm (const char *os_dev) + + if (dev != os_dev) + free ((void *) dev); +- return is_imsm; ++ return is_imsm_or_ddf; + } + + char * +@@ -1205,7 +1212,7 @@ grub_util_get_dev_abstraction_os (const char *os_dev) + + /* Check for RAID. */ + if (!strncmp (os_dev, "/dev/md", 7) && ! grub_util_device_is_mapped (os_dev) +- && !grub_util_is_imsm (os_dev)) ++ && !grub_util_is_imsm_or_ddf (os_dev)) + return GRUB_DEV_ABSTRACTION_RAID; + return GRUB_DEV_ABSTRACTION_NONE; + } diff --git a/SOURCES/0480-Set-correctly-the-memory-attributes-for-the-kernel-P.patch b/SOURCES/0480-Set-correctly-the-memory-attributes-for-the-kernel-P.patch new file mode 100644 index 0000000..aa4270c --- /dev/null +++ b/SOURCES/0480-Set-correctly-the-memory-attributes-for-the-kernel-P.patch @@ -0,0 +1,342 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Leo Sandoval +Date: Mon, 28 Jul 2025 12:37:06 -0600 +Subject: [PATCH] Set correctly the memory attributes for the kernel PE + sections + +Currently the whole kernel memory region is set to RO, so at some +point when execution is passed to the kernel, the latter faults on a +memory write access, e.g. zeroing .bss section. The proposed change +sets the memory attribute appropriately for each kernel PE section. + +Signed-off-by: Leo Sandoval +--- + grub-core/loader/arm64/linux.c | 2 +- + grub-core/loader/efi/linux.c | 165 ++++++++++++++++++++++++++++---------- + grub-core/loader/i386/efi/linux.c | 5 +- + include/grub/efi/linux.h | 7 ++ + include/grub/efi/pe32.h | 28 +++++++ + 5 files changed, 161 insertions(+), 46 deletions(-) + +diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c +index a3a193c255..c03e602974 100644 +--- a/grub-core/loader/arm64/linux.c ++++ b/grub-core/loader/arm64/linux.c +@@ -182,7 +182,7 @@ grub_arch_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args, + + grub_dprintf ("linux", "linux command line: '%s'\n", args); + +- retval = grub_efi_linux_boot (addr, size, handover_offset, ++ retval = grub_efi_linux_boot (addr, size, 0, handover_offset, + (void *)addr, nx_supported); + + /* Never reached... */ +diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c +index e413bdcc23..4d7cd3c624 100644 +--- a/grub-core/loader/efi/linux.c ++++ b/grub-core/loader/efi/linux.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wcast-align" +@@ -133,20 +134,130 @@ grub_efi_check_nx_required (int *nx_required) + typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *); + + grub_err_t +-grub_efi_linux_boot (grub_addr_t kernel_addr, grub_size_t kernel_size, ++grub_efi_mem_set_att (grub_addr_t kernel_address, grub_size_t kernel_size, ++ grub_size_t kernel_start, int nx_supported) ++{ ++ grub_addr_t kernel_start_address = kernel_address + kernel_start; ++ ++ grub_uint64_t default_set_attrs = GRUB_MEM_ATTR_R | GRUB_MEM_ATTR_W | GRUB_MEM_ATTR_X; ++ grub_uint64_t default_clear_attrs = 0; ++ grub_uint64_t stack_set_attrs = default_set_attrs; ++ grub_uint64_t stack_clear_attrs = default_clear_attrs; ++ grub_uint64_t kernel_set_attrs = default_set_attrs; ++ grub_uint64_t kernel_clear_attrs = default_clear_attrs; ++ grub_uint64_t attrs; ++ ++ struct grub_msdos_image_header *header; ++ struct grub_pe_image_header *pe_image_header; ++ struct grub_pe32_coff_header *coff_header; ++ struct grub_pe32_section_table *section, *sections; ++ grub_uint16_t i; ++ grub_size_t sz; ++ ++ header = (struct grub_msdos_image_header *)kernel_address; ++ ++ if (grub_add ((grub_addr_t) header, header->pe_image_header_offset, &sz)) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("Error on PE image header address calculation")); ++ ++ pe_image_header = (struct grub_pe_image_header *) (sz); ++ ++ if (pe_image_header > (kernel_address + kernel_size)) ++ return grub_error (GRUB_ERR_BAD_OS, N_("PE image header address is invalid")); ++ ++ if (grub_memcmp (pe_image_header->signature, GRUB_PE32_SIGNATURE, ++ GRUB_PE32_SIGNATURE_SIZE) != 0) ++ return grub_error (GRUB_ERR_BAD_OS, N_("kernel PE magic is invalid")); ++ ++ coff_header = &(pe_image_header->coff_header); ++ grub_dprintf ("nx", "coff_header 0x%"PRIxGRUB_ADDR" machine %08x\n", (grub_addr_t)coff_header, coff_header->machine); ++ ++ if (grub_add ((grub_addr_t) coff_header, sizeof (*coff_header), &sz) || ++ grub_add (sz, coff_header->optional_header_size, &sz)) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("Error on PE sections calculation")); ++ ++ sections = (struct grub_pe32_section_table *) (sz); ++ ++ if (sections > (kernel_address + kernel_size)) ++ return grub_error (GRUB_ERR_BAD_OS, N_("Section address is invalid")); ++ ++ /* Parse the PE, remove W for code section, remove X for data sections, RO for the rest */ ++ for (i = 0, section = sections; i < coff_header->num_sections; i++, section++) ++ { ++ kernel_set_attrs = default_set_attrs; ++ kernel_clear_attrs = default_clear_attrs; ++ ++ if (nx_supported) ++ { ++ if (section->characteristics & GRUB_PE32_SCN_MEM_EXECUTE) ++ { ++ /* RX section */ ++ kernel_set_attrs &= ~GRUB_MEM_ATTR_W; ++ kernel_clear_attrs |= GRUB_MEM_ATTR_W; ++ } ++ else if (section->characteristics & GRUB_PE32_SCN_MEM_WRITE) ++ { ++ /* RW section */ ++ kernel_set_attrs &= ~GRUB_MEM_ATTR_X; ++ kernel_clear_attrs |= GRUB_MEM_ATTR_X; ++ } ++ else ++ { ++ /* RO section */ ++ kernel_set_attrs &= ~GRUB_MEM_ATTR_W & ~GRUB_MEM_ATTR_X; ++ kernel_clear_attrs |= GRUB_MEM_ATTR_X | GRUB_MEM_ATTR_W ; ++ } ++ } ++ ++ /* Make sure we are inside range */ ++ if (grub_add ((grub_addr_t) kernel_address, section->raw_data_offset, &sz)) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("Error on PE Executable section calculation")); ++ ++ grub_update_mem_attrs (sz, section->raw_data_size, kernel_set_attrs, kernel_clear_attrs); ++ ++ grub_get_mem_attrs (sz, 4096, &attrs); ++ grub_dprintf ("nx", "permissions for section %s 0x%"PRIxGRUB_ADDR" are %s%s%s\n", ++ section->name, ++ (grub_addr_t)sz, ++ (attrs & GRUB_MEM_ATTR_R) ? "r" : "-", ++ (attrs & GRUB_MEM_ATTR_W) ? "w" : "-", ++ (attrs & GRUB_MEM_ATTR_X) ? "x" : "-"); ++ } ++ ++ if (grub_stack_addr != (grub_addr_t)-1ll) ++ { ++ if (nx_supported) ++ { ++ stack_set_attrs &= ~GRUB_MEM_ATTR_X; ++ stack_clear_attrs |= GRUB_MEM_ATTR_X; ++ } ++ ++ grub_dprintf ("nx", "Setting attributes for stack at 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to rw%c\n", ++ grub_stack_addr, grub_stack_addr + grub_stack_size - 1, ++ (stack_set_attrs & GRUB_MEM_ATTR_X) ? 'x' : '-'); ++ ++ grub_update_mem_attrs (grub_stack_addr, grub_stack_size, ++ stack_set_attrs, stack_clear_attrs); ++ ++ grub_get_mem_attrs (grub_stack_addr, 4096, &attrs); ++ grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n", ++ grub_stack_addr, ++ (attrs & GRUB_MEM_ATTR_R) ? "r" : "-", ++ (attrs & GRUB_MEM_ATTR_W) ? "w" : "-", ++ (attrs & GRUB_MEM_ATTR_X) ? "x" : "-"); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++grub_err_t ++grub_efi_linux_boot (grub_addr_t kernel_addr, grub_size_t kernel_size, grub_size_t kernel_start, + grub_off_t handover_offset, void *kernel_params, + int nx_supported) + { ++ grub_addr_t kernel_start_address = kernel_addr + kernel_start; + grub_efi_loaded_image_t *loaded_image = NULL; + handover_func hf; + int offset = 0; +- grub_uint64_t stack_set_attrs = GRUB_MEM_ATTR_R | +- GRUB_MEM_ATTR_W | +- GRUB_MEM_ATTR_X; +- grub_uint64_t stack_clear_attrs = 0; +- grub_uint64_t kernel_set_attrs = stack_set_attrs; +- grub_uint64_t kernel_clear_attrs = stack_clear_attrs; +- grub_uint64_t attrs; + int nx_required = 0; + + #ifdef __x86_64__ +@@ -171,41 +282,7 @@ grub_efi_linux_boot (grub_addr_t kernel_addr, grub_size_t kernel_size, + if (nx_required && !nx_supported) + return grub_error (GRUB_ERR_BAD_OS, N_("kernel does not support NX loading required by policy")); + +- if (nx_supported) +- { +- kernel_set_attrs &= ~GRUB_MEM_ATTR_W; +- kernel_clear_attrs |= GRUB_MEM_ATTR_W; +- stack_set_attrs &= ~GRUB_MEM_ATTR_X; +- stack_clear_attrs |= GRUB_MEM_ATTR_X; +- } +- +- grub_dprintf ("nx", "Setting attributes for 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to r%cx\n", +- kernel_addr, kernel_addr + kernel_size - 1, +- (kernel_set_attrs & GRUB_MEM_ATTR_W) ? 'w' : '-'); +- grub_update_mem_attrs (kernel_addr, kernel_size, +- kernel_set_attrs, kernel_clear_attrs); +- +- grub_get_mem_attrs (kernel_addr, 4096, &attrs); +- grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n", +- (grub_addr_t)kernel_addr, +- (attrs & GRUB_MEM_ATTR_R) ? "r" : "-", +- (attrs & GRUB_MEM_ATTR_W) ? "w" : "-", +- (attrs & GRUB_MEM_ATTR_X) ? "x" : "-"); +- if (grub_stack_addr != (grub_addr_t)-1ll) +- { +- grub_dprintf ("nx", "Setting attributes for stack at 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to rw%c\n", +- grub_stack_addr, grub_stack_addr + grub_stack_size - 1, +- (stack_set_attrs & GRUB_MEM_ATTR_X) ? 'x' : '-'); +- grub_update_mem_attrs (grub_stack_addr, grub_stack_size, +- stack_set_attrs, stack_clear_attrs); +- +- grub_get_mem_attrs (grub_stack_addr, 4096, &attrs); +- grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n", +- grub_stack_addr, +- (attrs & GRUB_MEM_ATTR_R) ? "r" : "-", +- (attrs & GRUB_MEM_ATTR_W) ? "w" : "-", +- (attrs & GRUB_MEM_ATTR_X) ? "x" : "-"); +- } ++ grub_efi_mem_set_att (kernel_addr, kernel_size, kernel_start, nx_supported); + + #if defined(__i386__) || defined(__x86_64__) + asm volatile ("cli"); +@@ -214,7 +291,7 @@ grub_efi_linux_boot (grub_addr_t kernel_addr, grub_size_t kernel_size, + /* Invalidate the instruction cache */ + grub_arch_sync_caches((void *)kernel_addr, kernel_size); + +- hf = (handover_func)((char *)kernel_addr + handover_offset + offset); ++ hf = (handover_func)((char *)kernel_start_address + handover_offset + offset); + hf (grub_efi_image_handle, grub_efi_system_table, kernel_params); + + return GRUB_ERR_BUG; +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 9854b0defa..c44821608e 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -41,6 +41,7 @@ static grub_command_t cmd_linuxefi, cmd_initrdefi; + struct grub_linuxefi_context { + void *kernel_mem; + grub_uint64_t kernel_size; ++ grub_uint64_t kernel_start; + grub_uint32_t handover_offset; + struct linux_kernel_params *params; + char *cmdline; +@@ -169,6 +170,7 @@ grub_linuxefi_boot (void *data) + + return grub_efi_linux_boot ((grub_addr_t)context->kernel_mem, + context->kernel_size, ++ context->kernel_start, + context->handover_offset, + context->params, + context->nx_supported); +@@ -527,7 +529,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + LOW_U32(kernel_mem)); + lh->code32_start = LOW_U32(kernel_mem); + +- grub_memcpy (kernel_mem, (char *)kernel + start, filelen - start); ++ grub_memcpy (kernel_mem, (char *)kernel, filelen); + + lh->type_of_loader = 0x6; + grub_dprintf ("linux", "setting lh->type_of_loader = 0x%02x\n", +@@ -544,6 +546,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + context->kernel_mem = kernel_mem; + context->kernel_size = kernel_size; ++ context->kernel_start = start; + context->handover_offset = handover_offset; + context->params = params; + context->cmdline = cmdline; +diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h +index b82f71006a..0aec66dafb 100644 +--- a/include/grub/efi/linux.h ++++ b/include/grub/efi/linux.h +@@ -27,6 +27,7 @@ + grub_err_t + EXPORT_FUNC(grub_efi_linux_boot) (grub_addr_t kernel_address, + grub_size_t kernel_size, ++ grub_size_t kernel_start, + grub_off_t handover_offset, + void *kernel_param, int nx_enabled); + +@@ -38,4 +39,10 @@ EXPORT_FUNC(grub_efi_check_nx_image_support) (grub_addr_t kernel_addr, + grub_err_t + EXPORT_FUNC(grub_efi_check_nx_required) (int *nx_required); + ++grub_err_t ++EXPORT_FUNC(grub_efi_mem_set_att) (grub_addr_t kernel_address, ++ grub_size_t kernel_size, ++ grub_size_t kernel_start, ++ int nx_supported); ++ + #endif /* ! GRUB_EFI_LINUX_HEADER */ +diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h +index a5e623eb04..131a2c0c3d 100644 +--- a/include/grub/efi/pe32.h ++++ b/include/grub/efi/pe32.h +@@ -71,6 +71,17 @@ struct grub_dos_header + grub_uint32_t lfanew; + }; + ++struct grub_msdos_image_header ++{ ++ /* This is always 'MZ'. (GRUB_PE32_MAGIC) */ ++ grub_uint16_t msdos_magic; ++ ++ grub_uint16_t reserved[29]; ++ ++ /* The file offset of the PE image header. */ ++ grub_uint32_t pe_image_header_offset; ++}; ++ + /* According to the spec, the minimal alignment is 512 bytes... + But some examples (such as EFI drivers in the Intel + Sample Implementation) use 32 bytes (0x20) instead, and it seems +@@ -308,6 +319,23 @@ struct grub_pe32_section_table + #define GRUB_PE32_SIGNATURE_SIZE 4 + #define GRUB_PE32_SIGNATURE "PE\0\0" + ++struct grub_pe_image_header ++{ ++ /* This is always PE\0\0. */ ++ char signature[GRUB_PE32_SIGNATURE_SIZE]; ++ ++ /* The COFF file header. */ ++ struct grub_pe32_coff_header coff_header; ++ ++#if GRUB_TARGET_SIZEOF_VOID_P == 8 ++ /* The Optional header. */ ++ struct grub_pe64_optional_header optional_header; ++#else ++ /* The Optional header. */ ++ struct grub_pe32_optional_header optional_header; ++#endif ++}; ++ + struct grub_pe32_header + { + /* This should be filled in with GRUB_PE32_MSDOS_STUB. */ diff --git a/SOURCES/20-grub.install b/SOURCES/20-grub.install index a3f1b18..492c9ac 100755 --- a/SOURCES/20-grub.install +++ b/SOURCES/20-grub.install @@ -175,8 +175,9 @@ case "$COMMAND" in if [[ "x${GRUB_ENABLE_BLSCFG}" = "xtrue" ]] || [[ ! -f /sbin/new-kernel-pkg ]]; then BLS_TARGET="${BLS_DIR}/${MACHINE_ID}-${KERNEL_VERSION}.conf" + BLS_FAKE_TARGET="${BLS_DIR}/ffffffffffffffffffffffffffffffff-${KERNEL_VERSION}.conf" BLS_DEBUG="$(echo ${BLS_TARGET} | sed -e "s/${KERNEL_VERSION}/${KERNEL_VERSION}~debug/")" - rm -f "${BLS_TARGET}" "${BLS_DEBUG}" + rm -f "${BLS_TARGET}" "${BLS_DEBUG}" "${BLS_FAKE_TARGET}" for i in vmlinuz System.map config zImage.stub dtb; do rm -rf "/boot/${i}-${KERNEL_VERSION}" diff --git a/SOURCES/gen_grub_cfgstub b/SOURCES/gen_grub_cfgstub new file mode 100644 index 0000000..c73ee53 --- /dev/null +++ b/SOURCES/gen_grub_cfgstub @@ -0,0 +1,29 @@ +#!/bin/sh +set -eu + +if [ $# -ne 2 ] + then + echo "Missing argument" + echo "Usage: script.sh GRUB_HOME EFI_HOME" + exit 1 +fi + +GRUB_HOME=$1 +EFI_HOME=$2 + +# create a stub grub2 config in EFI +BOOT_UUID=$(grub2-probe --target=fs_uuid "${GRUB_HOME}") +GRUB_DIR=$(grub2-mkrelpath "${GRUB_HOME}") + +echo "Generating grub stub config for drive " "${BOOT_UUID}" +echo "GRUB_DIR=" "${GRUB_DIR}" +echo "EFI_HOME=" "${EFI_HOME}" + +cat << EOF > "${EFI_HOME}"/grub.cfg.stb +search --no-floppy --root-dev-only --fs-uuid --set=dev ${BOOT_UUID} +set prefix=(\$dev)${GRUB_DIR} +export \$prefix +configfile \$prefix/grub.cfg +EOF + +mv ${EFI_HOME}/grub.cfg.stb ${EFI_HOME}/grub.cfg diff --git a/SOURCES/grub.macros b/SOURCES/grub.macros index 966c079..c2d0833 100755 --- a/SOURCES/grub.macros +++ b/SOURCES/grub.macros @@ -522,6 +522,8 @@ install -m 700 %{3} $RPM_BUILD_ROOT%{efi_esp_dir}/%{3} \ %ifarch %{arm} \ install -D -m 700 %{2} $RPM_BUILD_ROOT%{efi_esp_boot}/BOOTARM.EFI \ %endif \ +install -D -m 700 %{SOURCE13} \\\ + ${RPM_BUILD_ROOT}/usr/bin/gen_grub_cfgstub \ install -D -m 700 unicode.pf2 \\\ ${RPM_BUILD_ROOT}/boot/%{name}/fonts/unicode.pf2 \ ${RPM_BUILD_ROOT}/%{_bindir}/%{name}-editenv \\\ @@ -633,6 +635,7 @@ ln -s ../boot/%{name}/grub.cfg \\\ %attr(0700,root,root) %verify(not mtime) %{efi_esp_boot}/BOOTARM.EFI \ %endif \ %attr(0700,root,root)/boot/%{name}/fonts \ +%attr(0700,root,root)/usr/bin/gen_grub_cfgstub \ %dir %attr(0700,root,root)/boot/loader/entries \ %ghost %config(noreplace) %attr(0600,root,root)/boot/%{name}/grub.cfg \ %ghost %config(noreplace) %verify(not mtime) %attr(0700,root,root)%{efi_esp_dir}/grub.cfg \ diff --git a/SOURCES/grub.patches b/SOURCES/grub.patches index a48a7a5..87b04a7 100644 --- a/SOURCES/grub.patches +++ b/SOURCES/grub.patches @@ -454,3 +454,26 @@ Patch0454: 0454-fs-ext2-Rework-out-of-bounds-read-for-inline-and-ext.patch Patch0455: 0455-tpm-Disable-the-tpm-verifier-if-the-TPM-device-is-no.patch Patch0456: 0456-powerpc-increase-MIN-RMA-size-for-CAS-negotiation.patch Patch0457: 0457-ieee1275-ofnet-Fix-grub_malloc-removed-after-added-s.patch +Patch0458: 0458-fs-Remove-trailing-whitespaces.patch +Patch0459: 0459-fs-xfs-Fix-memory-leaks-in-XFS-module.patch +Patch0460: 0460-fs-xfs-Incorrect-short-form-directory-data-boundary-.patch +Patch0461: 0461-fs-xfs-Fix-XFS-directory-extent-parsing.patch +Patch0462: 0462-fs-xfs-Add-large-extent-counters-incompat-feature-su.patch +Patch0463: 0463-fs-xfs-Handle-non-continuous-data-blocks-in-director.patch +Patch0464: 0464-fs-xfs-fix-large-extent-counters-incompat-feature-su.patch +Patch0465: 0465-grub-mkimage-Create-new-ELF-note-for-SBAT.patch +Patch0466: 0466-grub-mkimage-Add-SBAT-metadata-into-ELF-note-for-Pow.patch +Patch0467: 0467-appended-sig-sync-d-with-upstream-code.patch +Patch0468: 0468-ieee1275-Platform-Keystore-PKS-Support.patch +Patch0469: 0469-ieee1275-Read-the-DB-and-DBX-secure-boot-variables.patch +Patch0470: 0470-appendedsig-The-creation-of-trusted-and-distrusted-l.patch +Patch0471: 0471-appendedsig-While-verifying-the-kernel-use-trusted-a.patch +Patch0472: 0472-powerpc_ieee1275-set-use_static_keys-flag.patch +Patch0473: 0473-appendedsig-Reads-the-default-DB-keys-from-ELF-Note.patch +Patch0474: 0474-appendedsig-The-grub-command-s-trusted-and-distruste.patch +Patch0475: 0475-appendedsig-documentation.patch +Patch0476: 0476-efi-Add-efitextmode-command-for-getting-setting-the-.patch +Patch0477: 0477-10_linux.in-escape-kernel-option-characters-properly.patch +Patch0478: 0478-blscfg-check-if-variable-is-escaped-before-consideri.patch +Patch0479: 0479-osdep-linux-getroot-Detect-DDF-container-similar-to-.patch +Patch0480: 0480-Set-correctly-the-memory-attributes-for-the-kernel-P.patch \ No newline at end of file diff --git a/SOURCES/sbat.csv.in b/SOURCES/sbat.csv.in index b338b5f..a0c77de 100755 --- a/SOURCES/sbat.csv.in +++ b/SOURCES/sbat.csv.in @@ -1,3 +1,4 @@ sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md -grub,3,Free Software Foundation,grub,@@VERSION@@,https//www.gnu.org/software/grub/ +grub,5,Free Software Foundation,grub,@@VERSION@@,https//www.gnu.org/software/grub/ grub.rh,2,Red Hat,grub2,@@VERSION_RELEASE@@,mailto:secalert@redhat.com +grub.centos,2,Red Hat,grub2,@@VERSION_RELEASE@@,mailto:secalert@redhat.com diff --git a/SPECS/grub2.spec b/SPECS/grub2.spec index e178f6d..f549e12 100644 --- a/SPECS/grub2.spec +++ b/SPECS/grub2.spec @@ -16,7 +16,7 @@ Name: grub2 Epoch: 1 Version: 2.06 -Release: 100%{?dist} +Release: 113%{?dist} Summary: Bootloader with support for Linux, Multiboot and more License: GPLv3+ URL: http://www.gnu.org/software/grub/ @@ -34,6 +34,7 @@ Source9: strtoull_test.c Source10: 20-grub.install Source11: grub.patches Source12: sbat.csv.in +Source13: gen_grub_cfgstub %include %{SOURCE1} @@ -361,23 +362,13 @@ if test -f ${EFI_HOME}/grub.cfg; then fi # create a stub grub2 config in EFI -BOOT_UUID=$(%{name}-probe --target=fs_uuid ${GRUB_HOME}) -GRUB_DIR=$(%{name}-mkrelpath ${GRUB_HOME}) - -cat << EOF > ${EFI_HOME}/grub.cfg.stb -search --no-floppy --root-dev-only --fs-uuid --set=dev ${BOOT_UUID} -set prefix=(\$dev)${GRUB_DIR} -export \$prefix -configfile \$prefix/grub.cfg -EOF +gen_grub_cfgstub $GRUB_HOME $EFI_HOME || : if test -f ${EFI_HOME}/grubenv; then cp -a ${EFI_HOME}/grubenv ${EFI_HOME}/grubenv.rpmsave mv --force ${EFI_HOME}/grubenv ${GRUB_HOME}/grubenv fi -mv ${EFI_HOME}/grub.cfg.stb ${EFI_HOME}/grub.cfg - %files common -f grub.lang %dir %{_libdir}/grub/ %dir %{_datarootdir}/grub/ @@ -547,6 +538,47 @@ mv ${EFI_HOME}/grub.cfg.stb ${EFI_HOME}/grub.cfg %endif %changelog +* Thu Aug 7 2025 Nicolas Frayer 2.06-113 +- sbat: add new sbat entry for centos +- Resolves: #RHEL-108060 + +* Tue Jul 29 2025 Leo Sandoval 2.06-112 +- Set correctly the memory attributes for the kernel PE sections +- Resolves: #RHEL-106075 + +* Tue Jul 29 2025 Nicolas Frayer 2.06-111 +- spec/posttrans: move grub config stub creation out of spec +- Resolves: #RHEL-69944 + +* Fri Jun 6 2025 Nicolas Frayer - 2.06-110 +- osdep/linux/getroot: Detect DDF container similar to IMSM +- Resolves: #RHEL-44336 + +* Mon Jun 2 2025 Leo Sandoval 2.06-109 +- Handle special kernel parameter characters properly +- Resolves: #RHEL-64297 + +* Wed May 21 2025 Nicolas Frayer - 2.06-108 +- ieee1275: Appended signature support +- Resolves: #RHEL-24742 + +* Wed May 14 2025 Nicolas Frayer - 2.06-107 +- Remove BLS fake config in case of kernel removal +- Resolves: #RHEL-83915 + +* Wed May 14 2025 Nicolas Frayer - 2.06-106 +- sbat: bump grub sbat for new shim release +- Resolves: #RHEL-91278 + +* Tue Apr 15 2025 Nicolas Frayer - 2.06-105 +- ppc/mkimage: SBAT support on powerpc +- Resolves: #RHEL-87421 + +* Thu Apr 3 2025 Nicolas Frayer 2.06-104 +- fs/xfs: Sync with latest xfs upstream +- Resolves: #RHEL-85960 +- (NVR bump to catch up with zstream) + * Tue Mar 25 2025 Nicolas Frayer 2.06-100 - ieee1275/ofnet: Fix grub_malloc() removed after added safe - Resolves: #RHEL-83117