From 6eaa34fe078bf49f94b2ea279e2885ff28533bca Mon Sep 17 00:00:00 2001 From: Nicolas Frayer Date: Thu, 13 Feb 2025 16:38:23 -0600 Subject: [PATCH] Add several CVE fixes - Resolves: CVE-2024-45779 CVE-2024-45778 CVE-2025-1118 - Resolves: CVE-2025-0677 CVE-2024-45782 CVE-2025-0690 - Resolves: CVE-2024-45783 CVE-2025-0624 CVE-2024-45776 - Resolves: CVE-2025-0622 CVE-2024-45774 CVE-2024-45775 - Resolves: CVE-2024-45781 CVE-2024-45780 - Resolves: #RHEL-79700 - Resolves: #RHEL-79341 - Resolves: #RHEL-79875 - Resolves: #RHEL-79849 - Resolves: #RHEL-79707 - Resolves: #RHEL-79857 - Resolves: #RHEL-79709 - Resolves: #RHEL-79846 - Resolves: #RHEL-75737 - Resolves: #RHEL-79713 - Resolves: #RHEL-73785 - Resolves: #RHEL-73787 - Resolves: #RHEL-79704 - Resolves: #RHEL-79702 Signed-off-by: Nicolas Frayer --- 0355-misc-Implement-grub_strlcpy.patch | 65 ++ 0356-fs-ufs-Fix-a-heap-OOB-write.patch | 31 + ...Fix-stack-OOB-write-with-grub_strcpy.patch | 31 + ...itialize-name-in-grub_cpio_find_file.patch | 40 ++ ...ger-overflow-leads-to-heap-OOB-write.patch | 89 +++ ...f2fs-Set-a-grub_errno-if-mount-fails.patch | 31 + ...plus-Set-a-grub_errno-if-mount-fails.patch | 35 + ...9660-Set-a-grub_errno-if-mount-fails.patch | 33 + 0363-fs-iso9660-Fix-invalid-free.patch | 50 ++ 0364-fs-jfs-Fix-OOB-read-in-jfs_getent.patch | 63 ++ ...ead-caused-by-invalid-dir-slot-index.patch | 64 ++ ...40-bits-offset-and-address-for-a-dat.patch | 128 ++++ ...ent-signed-unsigned-types-usage-in-r.patch | 85 +++ ...ut-of-bounds-read-for-inline-extents.patch | 46 ++ 0369-fs-ntfs-Fix-out-of-bounds-read.patch | 47 ++ ...-the-end-of-the-MFT-attribute-buffer.patch | 141 ++++ ...helper-function-to-access-attributes.patch | 183 ++++++ ...tfs-Implement-attribute-verification.patch | 245 +++++++ 0373-fs-xfs-Fix-out-of-bounds-read.patch | 43 ++ ...g-failing-to-mount-sets-a-grub_errno.patch | 42 ++ 0375-kern-file-Ensure-file-data-is-set.patch | 32 + ...lement-filesystem-reference-counting.patch | 440 +++++++++++++ ...ld-option-to-block-command-line-inte.patch | 367 +++++++++++ ...k-Refactor-to-discard-have_it-global.patch | 184 ++++++ ...n-failure-in-cryptomount-when-no-cry.patch | 29 + ...ve-error-messaging-in-cryptomount-in.patch | 55 ++ ...-Improve-cryptomount-u-error-message.patch | 28 + ...nfrastructure-to-pass-data-from-cryp.patch | 249 ++++++++ ...tor-password-input-out-of-crypto-dev.patch | 339 ++++++++++ ...message-to-align-with-luks-and-geli-.patch | 27 + ...global-variables-into-grub_cryptomou.patch | 245 +++++++ ...ve-handling-of-partition-name-in-cry.patch | 36 ++ ...disk-Fix-Coverity-use-after-free-bug.patch | 72 +++ ...Add-options-to-cryptomount-to-suppor.patch | 155 +++++ ...Use-enum-constants-as-indexes-into-c.patch | 140 ++++ ...upport-for-using-detached-header-fil.patch | 259 ++++++++ ...Support-encrypted-volumes-using-deta.patch | 51 ++ ...Allows-UUIDs-to-be-compared-in-a-das.patch | 200 ++++++ ...k-Fix-unintentional-integer-overflow.patch | 36 ++ ...When-cheatmounting-use-the-sector-in.patch | 73 +++ ...Fix-missing-change-when-updating-to-.patch | 34 + ...-cryptodisk-Optimize-luks_script_get.patch | 34 + ...Add-support-for-LUKS2-in-proc-luks_s.patch | 69 ++ ...Require-authentication-after-TPM-unl.patch | 337 ++++++++++ ...-Reference-tracking-for-the-loopback.patch | 108 ++++ 0400-kern-disk-Limit-recursion-depth.patch | 120 ++++ ...tion-Limit-recursion-in-part_iterate.patch | 44 ++ ...pt-execute-Limit-the-recursion-depth.patch | 55 ++ ...et_default_ip-and-net_default_mac-va.patch | 29 + ...bles-hooks-when-interface-is-unregis.patch | 84 +++ ...write-in-grub_net_search_config_file.patch | 79 +++ ...x-stack-buffer-overflow-in-tftp_open.patch | 115 ++++ ...eg-Do-not-permit-duplicate-SOF0-mark.patch | 33 + ...r-an-integer-overflow-in-grub_dl_ref.patch | 138 ++++ ...r-the-SHF_INFO_LINK-flag-in-grub_dl_.patch | 34 + ...-Missing-check-for-failed-allocation.patch | 34 + 0411-commands-ls-Fix-NULL-dereference.patch | 32 + ...egister-the-check_signatures-hooks-o.patch | 31 + ...ove-variables-hooks-on-module-unload.patch | 37 ++ ...ove-variables-hooks-on-module-unload.patch | 34 + ...overflow-leads-to-heap-OOB-write-or-.patch | 35 + ...ger-overflow-leads-to-heap-OOB-write.patch | 53 ++ ...d-silent-mode-to-read-command-to-sup.patch | 106 +++ ...ds-read-Fix-overflow-in-grub_getline.patch | 47 ++ ...x-an-integer-overflow-when-supplying.patch | 69 ++ ...ack-overflow-due-to-unlimited-recurs.patch | 83 +++ ...-Block-the-dump-command-in-lockdown-.patch | 33 + ...isable-memory-reading-in-lockdown-mo.patch | 50 ++ ...-Disable-memory-reading-in-lockdown-.patch | 37 ++ 0424-fs-bfs-Disable-under-lockdown.patch | 52 ++ ...able-many-filesystems-under-lockdown.patch | 391 ++++++++++++ ...nmount-Support-plain-encryption-mode.patch | 603 ++++++++++++++++++ ...afe-math-macros-to-prevent-overflows.patch | 543 ++++++++++++++++ ...rflows-when-allocating-memory-for-ar.patch | 38 ++ ...turned-pointer-for-allocated-memory-.patch | 152 +++++ ...disk-Call-grub_ieee1275_close-when-g.patch | 31 + ...afe-math-macros-to-prevent-overflows.patch | 353 ++++++++++ ...lows-when-allocating-memory-for-arra.patch | 82 +++ ...lows-when-assigning-returned-values-.patch | 105 +++ ...afe-math-macros-to-prevent-overflows.patch | 138 ++++ ...verflows-when-allocating-memory-for-.patch | 40 ++ ...returned-pointer-for-allocated-memor.patch | 88 +++ ...ng-NULL-check-after-grub_strdup-call.patch | 24 + ...afe-math-macros-to-prevent-overflows.patch | 240 +++++++ ...flows-when-allocating-memory-for-arr.patch | 45 ++ ...urned-pointer-for-allocated-memory-i.patch | 31 + ...fs-Check-if-allocated-memory-is-NULL.patch | 32 + ...ix-potential-underflow-and-NULL-dere.patch | 32 + ...unix-getroot-Fix-potential-underflow.patch | 35 + ...e-consistent-overflow-error-messages.patch | 55 ++ ...ine-GRUB_EHCI_TOGGLE-as-grub_uint32_.patch | 30 + ...safe-math-to-avoid-an-integer-overfl.patch | 41 ++ ...dd-sanity-check-after-grub_strtoul-c.patch | 46 ++ ...sanity-check-after-grub_strtoul-call.patch | 57 ++ ...nux-Cast-left-shift-to-grub_uint32_t.patch | 30 + ...bsd-Use-safe-math-to-avoid-underflow.patch | 56 ++ ...-types-Make-bool-generally-available.patch | 78 +++ ...es.h-Add-PRI-GRUB_OFFSET-and-PRI-GRU.patch | 35 + ...s-found-while-fuzzing-the-XFS-filesy.patch | 106 +++ grub.patches | 99 +++ grub2.spec | 24 +- 101 files changed, 10214 insertions(+), 1 deletion(-) create mode 100644 0355-misc-Implement-grub_strlcpy.patch create mode 100644 0356-fs-ufs-Fix-a-heap-OOB-write.patch create mode 100644 0357-fs-hfs-Fix-stack-OOB-write-with-grub_strcpy.patch create mode 100644 0358-fs-tar-Initialize-name-in-grub_cpio_find_file.patch create mode 100644 0359-fs-tar-Integer-overflow-leads-to-heap-OOB-write.patch create mode 100644 0360-fs-f2fs-Set-a-grub_errno-if-mount-fails.patch create mode 100644 0361-fs-hfsplus-Set-a-grub_errno-if-mount-fails.patch create mode 100644 0362-fs-iso9660-Set-a-grub_errno-if-mount-fails.patch create mode 100644 0363-fs-iso9660-Fix-invalid-free.patch create mode 100644 0364-fs-jfs-Fix-OOB-read-in-jfs_getent.patch create mode 100644 0365-fs-jfs-Fix-OOB-read-caused-by-invalid-dir-slot-index.patch create mode 100644 0366-fs-jfs-Use-full-40-bits-offset-and-address-for-a-dat.patch create mode 100644 0367-fs-jfs-Inconsistent-signed-unsigned-types-usage-in-r.patch create mode 100644 0368-fs-ext2-Fix-out-of-bounds-read-for-inline-extents.patch create mode 100644 0369-fs-ntfs-Fix-out-of-bounds-read.patch create mode 100644 0370-fs-ntfs-Track-the-end-of-the-MFT-attribute-buffer.patch create mode 100644 0371-fs-ntfs-Use-a-helper-function-to-access-attributes.patch create mode 100644 0372-fs-ntfs-Implement-attribute-verification.patch create mode 100644 0373-fs-xfs-Fix-out-of-bounds-read.patch create mode 100644 0374-fs-xfs-Ensuring-failing-to-mount-sets-a-grub_errno.patch create mode 100644 0375-kern-file-Ensure-file-data-is-set.patch create mode 100644 0376-kern-file-Implement-filesystem-reference-counting.patch create mode 100644 0377-cli_lock-Add-build-option-to-block-command-line-inte.patch create mode 100644 0378-cryptodisk-Refactor-to-discard-have_it-global.patch create mode 100644 0379-cryptodisk-Return-failure-in-cryptomount-when-no-cry.patch create mode 100644 0380-cryptodisk-Improve-error-messaging-in-cryptomount-in.patch create mode 100644 0381-cryptodisk-Improve-cryptomount-u-error-message.patch create mode 100644 0382-cryptodisk-Add-infrastructure-to-pass-data-from-cryp.patch create mode 100644 0383-cryptodisk-Refactor-password-input-out-of-crypto-dev.patch create mode 100644 0384-luks2-Add-debug-message-to-align-with-luks-and-geli-.patch create mode 100644 0385-cryptodisk-Move-global-variables-into-grub_cryptomou.patch create mode 100644 0386-cryptodisk-Improve-handling-of-partition-name-in-cry.patch create mode 100644 0387-cryptodisk-Fix-Coverity-use-after-free-bug.patch create mode 100644 0388-disk-cryptodisk-Add-options-to-cryptomount-to-suppor.patch create mode 100644 0389-disk-cryptodisk-Use-enum-constants-as-indexes-into-c.patch create mode 100644 0390-cryptodisk-Add-support-for-using-detached-header-fil.patch create mode 100644 0391-disk-cryptodisk-Support-encrypted-volumes-using-deta.patch create mode 100644 0392-disk-cryptodisk-Allows-UUIDs-to-be-compared-in-a-das.patch create mode 100644 0393-disk-cryptodisk-Fix-unintentional-integer-overflow.patch create mode 100644 0394-disk-cryptodisk-When-cheatmounting-use-the-sector-in.patch create mode 100644 0395-disk-cryptodisk-Fix-missing-change-when-updating-to-.patch create mode 100644 0396-disk-cryptodisk-Optimize-luks_script_get.patch create mode 100644 0397-disk-cryptodisk-Add-support-for-LUKS2-in-proc-luks_s.patch create mode 100644 0398-disk-cryptodisk-Require-authentication-after-TPM-unl.patch create mode 100644 0399-disk-loopback-Reference-tracking-for-the-loopback.patch create mode 100644 0400-kern-disk-Limit-recursion-depth.patch create mode 100644 0401-kern-partition-Limit-recursion-in-part_iterate.patch create mode 100644 0402-script-execute-Limit-the-recursion-depth.patch create mode 100644 0403-net-Unregister-net_default_ip-and-net_default_mac-va.patch create mode 100644 0404-net-Remove-variables-hooks-when-interface-is-unregis.patch create mode 100644 0405-net-Fix-OOB-write-in-grub_net_search_config_file.patch create mode 100644 0406-net-tftp-Fix-stack-buffer-overflow-in-tftp_open.patch create mode 100644 0407-video-readers-jpeg-Do-not-permit-duplicate-SOF0-mark.patch create mode 100644 0408-kern-dl-Fix-for-an-integer-overflow-in-grub_dl_ref.patch create mode 100644 0409-kern-dl-Check-for-the-SHF_INFO_LINK-flag-in-grub_dl_.patch create mode 100644 0410-commands-extcmd-Missing-check-for-failed-allocation.patch create mode 100644 0411-commands-ls-Fix-NULL-dereference.patch create mode 100644 0412-commands-pgp-Unregister-the-check_signatures-hooks-o.patch create mode 100644 0413-normal-Remove-variables-hooks-on-module-unload.patch create mode 100644 0414-gettext-Remove-variables-hooks-on-module-unload.patch create mode 100644 0415-gettext-Integer-overflow-leads-to-heap-OOB-write-or-.patch create mode 100644 0416-gettext-Integer-overflow-leads-to-heap-OOB-write.patch create mode 100644 0417-commands-read-Add-silent-mode-to-read-command-to-sup.patch create mode 100644 0418-commands-read-Fix-overflow-in-grub_getline.patch create mode 100644 0419-commands-read-Fix-an-integer-overflow-when-supplying.patch create mode 100644 0420-commands-test-Stack-overflow-due-to-unlimited-recurs.patch create mode 100644 0421-commands-minicmd-Block-the-dump-command-in-lockdown-.patch create mode 100644 0422-commands-memrw-Disable-memory-reading-in-lockdown-mo.patch create mode 100644 0423-commands-hexdump-Disable-memory-reading-in-lockdown-.patch create mode 100644 0424-fs-bfs-Disable-under-lockdown.patch create mode 100644 0425-fs-Disable-many-filesystems-under-lockdown.patch create mode 100644 0426-disk-plainmount-Support-plain-encryption-mode.patch create mode 100644 0427-disk-Use-safe-math-macros-to-prevent-overflows.patch create mode 100644 0428-disk-Prevent-overflows-when-allocating-memory-for-ar.patch create mode 100644 0429-disk-Check-if-returned-pointer-for-allocated-memory-.patch create mode 100644 0430-disk-ieee1275-ofdisk-Call-grub_ieee1275_close-when-g.patch create mode 100644 0431-fs-Use-safe-math-macros-to-prevent-overflows.patch create mode 100644 0432-fs-Prevent-overflows-when-allocating-memory-for-arra.patch create mode 100644 0433-fs-Prevent-overflows-when-assigning-returned-values-.patch create mode 100644 0434-fs-zfs-Use-safe-math-macros-to-prevent-overflows.patch create mode 100644 0435-fs-zfs-Prevent-overflows-when-allocating-memory-for-.patch create mode 100644 0436-fs-zfs-Check-if-returned-pointer-for-allocated-memor.patch create mode 100644 0437-fs-zfs-Add-missing-NULL-check-after-grub_strdup-call.patch create mode 100644 0438-net-Use-safe-math-macros-to-prevent-overflows.patch create mode 100644 0439-net-Prevent-overflows-when-allocating-memory-for-arr.patch create mode 100644 0440-net-Check-if-returned-pointer-for-allocated-memory-i.patch create mode 100644 0441-fs-sfs-Check-if-allocated-memory-is-NULL.patch create mode 100644 0442-script-execute-Fix-potential-underflow-and-NULL-dere.patch create mode 100644 0443-osdep-unix-getroot-Fix-potential-underflow.patch create mode 100644 0444-misc-Ensure-consistent-overflow-error-messages.patch create mode 100644 0445-bus-usb-ehci-Define-GRUB_EHCI_TOGGLE-as-grub_uint32_.patch create mode 100644 0446-normal-menu-Use-safe-math-to-avoid-an-integer-overfl.patch create mode 100644 0447-kern-partition-Add-sanity-check-after-grub_strtoul-c.patch create mode 100644 0448-kern-misc-Add-sanity-check-after-grub_strtoul-call.patch create mode 100644 0449-loader-i386-linux-Cast-left-shift-to-grub_uint32_t.patch create mode 100644 0450-loader-i386-bsd-Use-safe-math-to-avoid-underflow.patch create mode 100644 0451-types-Make-bool-generally-available.patch create mode 100644 0452-include-grub-types.h-Add-PRI-GRUB_OFFSET-and-PRI-GRU.patch create mode 100644 0453-fs-xfs-Fix-issues-found-while-fuzzing-the-XFS-filesy.patch diff --git a/0355-misc-Implement-grub_strlcpy.patch b/0355-misc-Implement-grub_strlcpy.patch new file mode 100644 index 0000000..722cab9 --- /dev/null +++ b/0355-misc-Implement-grub_strlcpy.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: B Horn +Date: Sat, 15 Jun 2024 02:33:08 +0100 +Subject: [PATCH] misc: Implement grub_strlcpy() + +grub_strlcpy() acts the same way as strlcpy() does on most *NIX, +returning the length of src and ensuring dest is always NUL +terminated except when size is 0. + +Signed-off-by: B Horn +Reviewed-by: Daniel Kiper +--- + include/grub/misc.h | 39 +++++++++++++++++++++++++++++++++++++++ + 1 file changed, 39 insertions(+) + +diff --git a/include/grub/misc.h b/include/grub/misc.h +index 981526644..0592aa68f 100644 +--- a/include/grub/misc.h ++++ b/include/grub/misc.h +@@ -72,6 +72,45 @@ grub_stpcpy (char *dest, const char *src) + return d - 1; + } + ++static inline grub_size_t ++grub_strlcpy (char *dest, const char *src, grub_size_t size) ++{ ++ char *d = dest; ++ grub_size_t res = 0; ++ /* ++ * We do not subtract one from size here to avoid dealing with underflowing ++ * the value, which is why to_copy is always checked to be greater than one ++ * throughout this function. ++ */ ++ grub_size_t to_copy = size; ++ ++ /* Copy size - 1 bytes to dest. */ ++ if (to_copy > 1) ++ while ((*d++ = *src++) != '\0' && ++res && --to_copy > 1) ++ ; ++ ++ /* ++ * NUL terminate if size != 0. The previous step may have copied a NUL byte ++ * if it reached the end of the string, but we know dest[size - 1] must always ++ * be a NUL byte. ++ */ ++ if (size != 0) ++ dest[size - 1] = '\0'; ++ ++ /* If there is still space in dest, but are here, we reached the end of src. */ ++ if (to_copy > 1) ++ return res; ++ ++ /* ++ * If we haven't reached the end of the string, iterate through to determine ++ * the strings total length. ++ */ ++ while (*src++ != '\0' && ++res) ++ ; ++ ++ return res; ++} ++ + /* XXX: If grub_memmove is too slow, we must implement grub_memcpy. */ + static inline void * + grub_memcpy (void *dest, const void *src, grub_size_t n) diff --git a/0356-fs-ufs-Fix-a-heap-OOB-write.patch b/0356-fs-ufs-Fix-a-heap-OOB-write.patch new file mode 100644 index 0000000..9d6e7d9 --- /dev/null +++ b/0356-fs-ufs-Fix-a-heap-OOB-write.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: B Horn +Date: Sun, 12 May 2024 02:03:33 +0100 +Subject: [PATCH] fs/ufs: Fix a heap OOB write + +grub_strcpy() was used to copy a symlink name from the filesystem +image to a heap allocated buffer. This led to a OOB write to adjacent +heap allocations. Fix by using grub_strlcpy(). + +Fixes: CVE-2024-45781 + +Reported-by: B Horn +Signed-off-by: B Horn +Reviewed-by: Daniel Kiper +--- + grub-core/fs/ufs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/fs/ufs.c b/grub-core/fs/ufs.c +index 34a698b71..47272665e 100644 +--- a/grub-core/fs/ufs.c ++++ b/grub-core/fs/ufs.c +@@ -463,7 +463,7 @@ grub_ufs_lookup_symlink (struct grub_ufs_data *data, int ino) + /* Check against zero is paylindromic, no need to swap. */ + if (data->inode.nblocks == 0 + && INODE_SIZE (data) <= sizeof (data->inode.symlink)) +- grub_strcpy (symlink, (char *) data->inode.symlink); ++ grub_strlcpy (symlink, (char *) data->inode.symlink, sz); + else + { + if (grub_ufs_read_file (data, 0, 0, 0, sz, symlink) < 0) diff --git a/0357-fs-hfs-Fix-stack-OOB-write-with-grub_strcpy.patch b/0357-fs-hfs-Fix-stack-OOB-write-with-grub_strcpy.patch new file mode 100644 index 0000000..cc956ca --- /dev/null +++ b/0357-fs-hfs-Fix-stack-OOB-write-with-grub_strcpy.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: B Horn +Date: Sun, 12 May 2024 02:48:33 +0100 +Subject: [PATCH] fs/hfs: Fix stack OOB write with grub_strcpy() + +Replaced with grub_strlcpy(). + +Fixes: CVE-2024-45782 +Fixes: CVE-2024-56737 +Fixes: https://savannah.gnu.org/bugs/?66599 + +Reported-by: B Horn +Signed-off-by: B Horn +Reviewed-by: Daniel Kiper +--- + grub-core/fs/hfs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/fs/hfs.c b/grub-core/fs/hfs.c +index f419965d1..bb7af5f67 100644 +--- a/grub-core/fs/hfs.c ++++ b/grub-core/fs/hfs.c +@@ -379,7 +379,7 @@ grub_hfs_mount (grub_disk_t disk) + volume name. */ + key.parent_dir = grub_cpu_to_be32_compile_time (1); + key.strlen = data->sblock.volname[0]; +- grub_strcpy ((char *) key.str, (char *) (data->sblock.volname + 1)); ++ grub_strlcpy ((char *) key.str, (char *) (data->sblock.volname + 1), sizeof (key.str)); + + if (grub_hfs_find_node (data, (char *) &key, data->cat_root, + 0, (char *) &dir, sizeof (dir)) == 0) diff --git a/0358-fs-tar-Initialize-name-in-grub_cpio_find_file.patch b/0358-fs-tar-Initialize-name-in-grub_cpio_find_file.patch new file mode 100644 index 0000000..6433d2d --- /dev/null +++ b/0358-fs-tar-Initialize-name-in-grub_cpio_find_file.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: B Horn +Date: Sun, 12 May 2024 02:47:54 +0100 +Subject: [PATCH] fs/tar: Initialize name in grub_cpio_find_file() + +It was possible to iterate through grub_cpio_find_file() without +allocating name and not setting mode to GRUB_ARCHELP_ATTR_END, which +would cause the uninitialized value for name to be used as an argument +for canonicalize() in grub_archelp_dir(). + +Reported-by: B Horn +Signed-off-by: B Horn +Reviewed-by: Daniel Kiper +--- + grub-core/fs/tar.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/grub-core/fs/tar.c b/grub-core/fs/tar.c +index c551ed6b5..646bce5eb 100644 +--- a/grub-core/fs/tar.c ++++ b/grub-core/fs/tar.c +@@ -78,6 +78,7 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name, + int reread = 0, have_longname = 0, have_longlink = 0; + + data->hofs = data->next_hofs; ++ *name = NULL; + + for (reread = 0; reread < 3; reread++) + { +@@ -202,6 +203,10 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name, + } + return GRUB_ERR_NONE; + } ++ ++ if (*name == NULL) ++ return grub_error (GRUB_ERR_BAD_FS, "invalid tar archive"); ++ + return GRUB_ERR_NONE; + } + diff --git a/0359-fs-tar-Integer-overflow-leads-to-heap-OOB-write.patch b/0359-fs-tar-Integer-overflow-leads-to-heap-OOB-write.patch new file mode 100644 index 0000000..b059e49 --- /dev/null +++ b/0359-fs-tar-Integer-overflow-leads-to-heap-OOB-write.patch @@ -0,0 +1,89 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lidong Chen +Date: Fri, 22 Nov 2024 06:27:58 +0000 +Subject: [PATCH] fs/tar: Integer overflow leads to heap OOB write + +Both namesize and linksize are derived from hd.size, a 12-digit octal +number parsed by read_number(). Later direct arithmetic calculation like +"namesize + 1" and "linksize + 1" may exceed the maximum value of +grub_size_t leading to heap OOB write. This patch fixes the issue by +using grub_add() and checking for an overflow. + +Fixes: CVE-2024-45780 + +Reported-by: Nils Langius +Signed-off-by: Lidong Chen +Reviewed-by: Daniel Kiper +Reviewed-by: Alec Brown +--- + grub-core/fs/tar.c | 23 ++++++++++++++++++----- + 1 file changed, 18 insertions(+), 5 deletions(-) + +diff --git a/grub-core/fs/tar.c b/grub-core/fs/tar.c +index 646bce5eb..386c09022 100644 +--- a/grub-core/fs/tar.c ++++ b/grub-core/fs/tar.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -76,6 +77,7 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name, + { + struct head hd; + int reread = 0, have_longname = 0, have_longlink = 0; ++ grub_size_t sz; + + data->hofs = data->next_hofs; + *name = NULL; +@@ -98,7 +100,11 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name, + { + grub_err_t err; + grub_size_t namesize = read_number (hd.size, sizeof (hd.size)); +- *name = grub_malloc (namesize + 1); ++ ++ if (grub_add (namesize, 1, &sz)) ++ return grub_error (GRUB_ERR_BAD_FS, N_("name size overflow")); ++ ++ *name = grub_malloc (sz); + if (*name == NULL) + return grub_errno; + err = grub_disk_read (data->disk, 0, +@@ -118,15 +124,19 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name, + { + grub_err_t err; + grub_size_t linksize = read_number (hd.size, sizeof (hd.size)); +- if (data->linkname_alloc < linksize + 1) ++ ++ if (grub_add (linksize, 1, &sz)) ++ return grub_error (GRUB_ERR_BAD_FS, N_("link size overflow")); ++ ++ if (data->linkname_alloc < sz) + { + char *n; +- n = grub_calloc (2, linksize + 1); ++ n = grub_calloc (2, sz); + if (!n) + return grub_errno; + grub_free (data->linkname); + data->linkname = n; +- data->linkname_alloc = 2 * (linksize + 1); ++ data->linkname_alloc = 2 * (sz); + } + + err = grub_disk_read (data->disk, 0, +@@ -149,7 +159,10 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name, + while (extra_size < sizeof (hd.prefix) + && hd.prefix[extra_size]) + extra_size++; +- *name = grub_malloc (sizeof (hd.name) + extra_size + 2); ++ ++ if (grub_add (sizeof (hd.name) + 2, extra_size, &sz)) ++ return grub_error (GRUB_ERR_BAD_FS, N_("long name size overflow")); ++ *name = grub_malloc (sz); + if (*name == NULL) + return grub_errno; + if (hd.prefix[0]) diff --git a/0360-fs-f2fs-Set-a-grub_errno-if-mount-fails.patch b/0360-fs-f2fs-Set-a-grub_errno-if-mount-fails.patch new file mode 100644 index 0000000..89e87c7 --- /dev/null +++ b/0360-fs-f2fs-Set-a-grub_errno-if-mount-fails.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: B Horn +Date: Sun, 12 May 2024 06:15:03 +0100 +Subject: [PATCH] fs/f2fs: Set a grub_errno if mount fails + +It was previously possible for grub_errno to not be set when +grub_f2fs_mount() failed if nat_bitmap_ptr() returned NULL. + +This issue is solved by ensuring a grub_errno is set in the fail case. + +Reported-by: B Horn +Signed-off-by: B Horn +Reviewed-by: Daniel Kiper +--- + grub-core/fs/f2fs.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c +index df6beb544..f7daa9435 100644 +--- a/grub-core/fs/f2fs.c ++++ b/grub-core/fs/f2fs.c +@@ -872,6 +872,9 @@ grub_f2fs_mount (grub_disk_t disk) + return data; + + fail: ++ if (grub_errno == GRUB_ERR_NONE) ++ grub_error (GRUB_ERR_BAD_FS, "not a F2FS filesystem"); ++ + grub_free (data); + + return NULL; diff --git a/0361-fs-hfsplus-Set-a-grub_errno-if-mount-fails.patch b/0361-fs-hfsplus-Set-a-grub_errno-if-mount-fails.patch new file mode 100644 index 0000000..62a3437 --- /dev/null +++ b/0361-fs-hfsplus-Set-a-grub_errno-if-mount-fails.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: B Horn +Date: Sun, 12 May 2024 06:22:51 +0100 +Subject: [PATCH] fs/hfsplus: Set a grub_errno if mount fails + +It was possible for mount to fail but not set grub_errno. This led to +a possible double decrement of the module reference count if the NULL +page was mapped. + +Fixing in general as a similar bug was fixed in commit 61b13c187 +(fs/hfsplus: Set grub_errno to prevent NULL pointer access) and there +are likely more variants around. + +Fixes: CVE-2024-45783 + +Reported-by: B Horn +Signed-off-by: B Horn +Reviewed-by: Daniel Kiper +--- + grub-core/fs/hfsplus.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/fs/hfsplus.c b/grub-core/fs/hfsplus.c +index 19c7b3367..e7fd98a07 100644 +--- a/grub-core/fs/hfsplus.c ++++ b/grub-core/fs/hfsplus.c +@@ -393,7 +393,7 @@ grub_hfsplus_mount (grub_disk_t disk) + + fail: + +- if (grub_errno == GRUB_ERR_OUT_OF_RANGE) ++ if (grub_errno == GRUB_ERR_OUT_OF_RANGE || grub_errno == GRUB_ERR_NONE) + grub_error (GRUB_ERR_BAD_FS, "not a HFS+ filesystem"); + + grub_free (data); diff --git a/0362-fs-iso9660-Set-a-grub_errno-if-mount-fails.patch b/0362-fs-iso9660-Set-a-grub_errno-if-mount-fails.patch new file mode 100644 index 0000000..c7b2bdc --- /dev/null +++ b/0362-fs-iso9660-Set-a-grub_errno-if-mount-fails.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: B Horn +Date: Sun, 12 May 2024 06:37:08 +0100 +Subject: [PATCH] fs/iso9660: Set a grub_errno if mount fails + +It was possible for a grub_errno to not be set if mount of an ISO 9660 +filesystem failed when set_rockridge() returned 0. + +This isn't known to be exploitable as the other filesystems due to +filesystem helper checking the requested file type. Though fixing +as a precaution. + +Reported-by: B Horn +Signed-off-by: B Horn +Reviewed-by: Daniel Kiper +--- + grub-core/fs/iso9660.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/fs/iso9660.c b/grub-core/fs/iso9660.c +index ac011950a..82cf1a271 100644 +--- a/grub-core/fs/iso9660.c ++++ b/grub-core/fs/iso9660.c +@@ -491,6 +491,9 @@ grub_iso9660_mount (grub_disk_t disk) + return data; + + fail: ++ if (grub_errno == GRUB_ERR_NONE) ++ grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem"); ++ + grub_free (data); + return 0; + } diff --git a/0363-fs-iso9660-Fix-invalid-free.patch b/0363-fs-iso9660-Fix-invalid-free.patch new file mode 100644 index 0000000..521183e --- /dev/null +++ b/0363-fs-iso9660-Fix-invalid-free.patch @@ -0,0 +1,50 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Fri, 31 May 2024 15:14:42 +0800 +Subject: [PATCH] fs/iso9660: Fix invalid free + +The ctx->filename can point to either a string literal or a dynamically +allocated string. The ctx->filename_alloc field is used to indicate the +type of allocation. + +An issue has been identified where ctx->filename is reassigned to +a string literal in susp_iterate_dir() but ctx->filename_alloc is not +correctly handled. This oversight causes a memory leak and an invalid +free operation later. + +The fix involves checking ctx->filename_alloc, freeing the allocated +string if necessary and clearing ctx->filename_alloc for string literals. + +Reported-by: Daniel Axtens +Signed-off-by: Michael Chang +Reviewed-by: Daniel Kiper +--- + grub-core/fs/iso9660.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/grub-core/fs/iso9660.c b/grub-core/fs/iso9660.c +index 82cf1a271..7a59a65a5 100644 +--- a/grub-core/fs/iso9660.c ++++ b/grub-core/fs/iso9660.c +@@ -568,9 +568,19 @@ susp_iterate_dir (struct grub_iso9660_susp_entry *entry, + filename type is stored. */ + /* FIXME: Fix this slightly improper cast. */ + if (entry->data[0] & GRUB_ISO9660_RR_DOT) +- ctx->filename = (char *) "."; ++ { ++ if (ctx->filename_alloc) ++ grub_free (ctx->filename); ++ ctx->filename_alloc = 0; ++ ctx->filename = (char *) "."; ++ } + else if (entry->data[0] & GRUB_ISO9660_RR_DOTDOT) +- ctx->filename = (char *) ".."; ++ { ++ if (ctx->filename_alloc) ++ grub_free (ctx->filename); ++ ctx->filename_alloc = 0; ++ ctx->filename = (char *) ".."; ++ } + else if (entry->len >= 5) + { + grub_size_t off = 0, csize = 1; diff --git a/0364-fs-jfs-Fix-OOB-read-in-jfs_getent.patch b/0364-fs-jfs-Fix-OOB-read-in-jfs_getent.patch new file mode 100644 index 0000000..49464e7 --- /dev/null +++ b/0364-fs-jfs-Fix-OOB-read-in-jfs_getent.patch @@ -0,0 +1,63 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lidong Chen +Date: Fri, 22 Nov 2024 06:27:59 +0000 +Subject: [PATCH] fs/jfs: Fix OOB read in jfs_getent() + +The JFS fuzzing revealed an OOB read in grub_jfs_getent(). The crash +was caused by an invalid leaf nodes count, diro->dirpage->header.count, +which was larger than the maximum number of leaf nodes allowed in an +inode. This fix is to ensure that the leaf nodes count is validated in +grub_jfs_opendir() before calling grub_jfs_getent(). + +On the occasion replace existing raw numbers with newly defined constant. + +Signed-off-by: Lidong Chen +Reviewed-by: Daniel Kiper +Reviewed-by: Alec Brown +--- + grub-core/fs/jfs.c | 17 +++++++++++++++-- + 1 file changed, 15 insertions(+), 2 deletions(-) + +diff --git a/grub-core/fs/jfs.c b/grub-core/fs/jfs.c +index 6f7c43904..32dec7fb7 100644 +--- a/grub-core/fs/jfs.c ++++ b/grub-core/fs/jfs.c +@@ -41,6 +41,12 @@ GRUB_MOD_LICENSE ("GPLv3+"); + + #define GRUB_JFS_TREE_LEAF 2 + ++/* ++ * Define max entries stored in-line in an inode. ++ * https://jfs.sourceforge.net/project/pub/jfslayout.pdf ++ */ ++#define GRUB_JFS_INODE_INLINE_ENTRIES 8 ++ + struct grub_jfs_sblock + { + /* The magic for JFS. It should contain the string "JFS1". */ +@@ -203,9 +209,9 @@ struct grub_jfs_inode + grub_uint8_t freecnt; + grub_uint8_t freelist; + grub_uint32_t idotdot; +- grub_uint8_t sorted[8]; ++ grub_uint8_t sorted[GRUB_JFS_INODE_INLINE_ENTRIES]; + } header; +- struct grub_jfs_leaf_dirent dirents[8]; ++ struct grub_jfs_leaf_dirent dirents[GRUB_JFS_INODE_INLINE_ENTRIES]; + } GRUB_PACKED dir; + /* Fast symlink. */ + struct +@@ -453,6 +459,13 @@ grub_jfs_opendir (struct grub_jfs_data *data, struct grub_jfs_inode *inode) + /* Check if the entire tree is contained within the inode. */ + if (inode->file.tree.flags & GRUB_JFS_TREE_LEAF) + { ++ if (inode->dir.header.count > GRUB_JFS_INODE_INLINE_ENTRIES) ++ { ++ grub_free (diro); ++ grub_error (GRUB_ERR_BAD_FS, N_("invalid JFS inode")); ++ return 0; ++ } ++ + diro->leaf = inode->dir.dirents; + diro->next_leaf = (struct grub_jfs_leaf_next_dirent *) de; + diro->sorted = inode->dir.header.sorted; diff --git a/0365-fs-jfs-Fix-OOB-read-caused-by-invalid-dir-slot-index.patch b/0365-fs-jfs-Fix-OOB-read-caused-by-invalid-dir-slot-index.patch new file mode 100644 index 0000000..029e848 --- /dev/null +++ b/0365-fs-jfs-Fix-OOB-read-caused-by-invalid-dir-slot-index.patch @@ -0,0 +1,64 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lidong Chen +Date: Fri, 22 Nov 2024 06:28:00 +0000 +Subject: [PATCH] fs/jfs: Fix OOB read caused by invalid dir slot index + +While fuzz testing JFS with ASAN enabled an OOB read was detected in +grub_jfs_opendir(). The issue occurred due to an invalid directory slot +index in the first entry of the sorted directory slot array in the inode +directory header. The fix ensures the slot index is validated before +accessing it. Given that an internal or a leaf node in a directory B+ +tree is a 4 KiB in size and each directory slot is always 32 bytes, the +max number of slots in a node is 128. The validation ensures that the +slot index doesn't exceed this limit. + +[1] https://jfs.sourceforge.net/project/pub/jfslayout.pdf + + JFS will allocate 4K of disk space for an internal node of the B+ tree. + An internal node looks the same as a leaf node. + - page 10 + + Fixed number of Directory Slots depending on the size of the node. These are + the slots to be used for storing the directory slot array and the directory + entries or router entries. A directory slot is always 32 bytes. + ... + A Directory Slot Array which is a sorted array of indices to the directory + slots that are currently in use. + ... + An internal or a leaf node in the directory B+ tree is a 4K page. + - page 25 + +Signed-off-by: Lidong Chen +Reviewed-by: Daniel Kiper +Reviewed-by: Alec Brown +--- + grub-core/fs/jfs.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/grub-core/fs/jfs.c b/grub-core/fs/jfs.c +index 32dec7fb7..88fb884df 100644 +--- a/grub-core/fs/jfs.c ++++ b/grub-core/fs/jfs.c +@@ -46,6 +46,7 @@ GRUB_MOD_LICENSE ("GPLv3+"); + * https://jfs.sourceforge.net/project/pub/jfslayout.pdf + */ + #define GRUB_JFS_INODE_INLINE_ENTRIES 8 ++#define GRUB_JFS_DIR_MAX_SLOTS 128 + + struct grub_jfs_sblock + { +@@ -481,6 +482,14 @@ grub_jfs_opendir (struct grub_jfs_data *data, struct grub_jfs_inode *inode) + return 0; + } + ++ if (inode->dir.header.sorted[0] >= GRUB_JFS_DIR_MAX_SLOTS) ++ { ++ grub_error (GRUB_ERR_BAD_FS, N_("invalid directory slot index")); ++ grub_free (diro->dirpage); ++ grub_free (diro); ++ return 0; ++ } ++ + blk = grub_le_to_cpu32 (de[inode->dir.header.sorted[0]].ex.blk2); + blk <<= (grub_le_to_cpu16 (data->sblock.log2_blksz) - GRUB_DISK_SECTOR_BITS); + diff --git a/0366-fs-jfs-Use-full-40-bits-offset-and-address-for-a-dat.patch b/0366-fs-jfs-Use-full-40-bits-offset-and-address-for-a-dat.patch new file mode 100644 index 0000000..ed387ae --- /dev/null +++ b/0366-fs-jfs-Use-full-40-bits-offset-and-address-for-a-dat.patch @@ -0,0 +1,128 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lidong Chen +Date: Mon, 16 Dec 2024 20:22:39 +0000 +Subject: [PATCH] fs/jfs: Use full 40 bits offset and address for a data extent + +An extent's logical offset and address are represented as a 40-bit value +split into two parts: the most significant 8 bits and the least +significant 32 bits. Currently the JFS code uses only the least +significant 32 bits value for offsets and addresses assuming the data +size will never exceed the 32-bit range. This approach ignores the most +significant 8 bits potentially leading to incorrect offsets and +addresses for larger values. The patch fixes it by incorporating the +most significant 8 bits into the calculation to get the full 40-bits +value for offsets and addresses. + +https://jfs.sourceforge.net/project/pub/jfslayout.pdf + + "off1,off2 is a 40-bit field, containing the logical offset of the first + block in the extent. + ... + addr1,addr2 is a 40-bit field, containing the address of the extent." + +Signed-off-by: Lidong Chen +Reviewed-by: Alec Brown +Reviewed-by: Ross Philipson +Reviewed-by: Daniel Kiper +--- + grub-core/fs/jfs.c | 41 +++++++++++++++++++++++++++++------------ + 1 file changed, 29 insertions(+), 12 deletions(-) + +diff --git a/grub-core/fs/jfs.c b/grub-core/fs/jfs.c +index 88fb884df..2bde48d45 100644 +--- a/grub-core/fs/jfs.c ++++ b/grub-core/fs/jfs.c +@@ -265,6 +265,20 @@ static grub_dl_t my_mod; + + static grub_err_t grub_jfs_lookup_symlink (struct grub_jfs_data *data, grub_uint32_t ino); + ++/* ++ * An extent's offset, physical and logical, is represented as a 40-bit value. ++ * This 40-bit value is split into two parts: ++ * - offset1: the most signficant 8 bits of the offset, ++ * - offset2: the least significant 32 bits of the offset. ++ * ++ * This function calculates and returns the 64-bit offset of an extent. ++ */ ++static grub_uint64_t ++get_ext_offset (grub_uint8_t offset1, grub_uint32_t offset2) ++{ ++ return (((grub_uint64_t) offset1 << 32) | grub_le_to_cpu32 (offset2)); ++} ++ + static grub_int64_t + getblk (struct grub_jfs_treehead *treehead, + struct grub_jfs_tree_extent *extents, +@@ -274,22 +288,25 @@ getblk (struct grub_jfs_treehead *treehead, + { + int found = -1; + int i; ++ grub_uint64_t ext_offset, ext_blk; + + for (i = 0; i < grub_le_to_cpu16 (treehead->count) - 2 && + i < max_extents; i++) + { ++ ext_offset = get_ext_offset (extents[i].offset1, extents[i].offset2); ++ ext_blk = get_ext_offset (extents[i].extent.blk1, extents[i].extent.blk2); ++ + if (treehead->flags & GRUB_JFS_TREE_LEAF) + { + /* Read the leafnode. */ +- if (grub_le_to_cpu32 (extents[i].offset2) <= blk ++ if (ext_offset <= blk + && ((grub_le_to_cpu16 (extents[i].extent.length)) + + (extents[i].extent.length2 << 16) +- + grub_le_to_cpu32 (extents[i].offset2)) > blk) +- return (blk - grub_le_to_cpu32 (extents[i].offset2) +- + grub_le_to_cpu32 (extents[i].extent.blk2)); ++ + ext_offset) > blk) ++ return (blk - ext_offset + ext_blk); + } + else +- if (blk >= grub_le_to_cpu32 (extents[i].offset2)) ++ if (blk >= ext_offset) + found = i; + } + +@@ -307,10 +324,9 @@ getblk (struct grub_jfs_treehead *treehead, + return -1; + + if (!grub_disk_read (data->disk, +- ((grub_disk_addr_t) grub_le_to_cpu32 (extents[found].extent.blk2)) +- << (grub_le_to_cpu16 (data->sblock.log2_blksz) +- - GRUB_DISK_SECTOR_BITS), 0, +- sizeof (*tree), (char *) tree)) ++ (grub_disk_addr_t) ext_blk ++ << (grub_le_to_cpu16 (data->sblock.log2_blksz) - GRUB_DISK_SECTOR_BITS), ++ 0, sizeof (*tree), (char *) tree)) + { + if (grub_memcmp (&tree->treehead, treehead, sizeof (struct grub_jfs_treehead)) || + grub_memcmp (&tree->extents, extents, 254 * sizeof (struct grub_jfs_tree_extent))) +@@ -361,7 +377,7 @@ grub_jfs_read_inode (struct grub_jfs_data *data, grub_uint32_t ino, + sizeof (iag_inodes), &iag_inodes)) + return grub_errno; + +- inoblk = grub_le_to_cpu32 (iag_inodes[inoext].blk2); ++ inoblk = get_ext_offset (iag_inodes[inoext].blk1, iag_inodes[inoext].blk2); + inoblk <<= (grub_le_to_cpu16 (data->sblock.log2_blksz) + - GRUB_DISK_SECTOR_BITS); + inoblk += inonum; +@@ -490,7 +506,8 @@ grub_jfs_opendir (struct grub_jfs_data *data, struct grub_jfs_inode *inode) + return 0; + } + +- blk = grub_le_to_cpu32 (de[inode->dir.header.sorted[0]].ex.blk2); ++ blk = get_ext_offset (de[inode->dir.header.sorted[0]].ex.blk1, ++ de[inode->dir.header.sorted[0]].ex.blk2); + blk <<= (grub_le_to_cpu16 (data->sblock.log2_blksz) - GRUB_DISK_SECTOR_BITS); + + /* Read in the nodes until we are on the leaf node level. */ +@@ -508,7 +525,7 @@ grub_jfs_opendir (struct grub_jfs_data *data, struct grub_jfs_inode *inode) + + de = (struct grub_jfs_internal_dirent *) diro->dirpage->dirent; + index = diro->dirpage->sorted[diro->dirpage->header.sindex * 32]; +- blk = (grub_le_to_cpu32 (de[index].ex.blk2) ++ blk = (get_ext_offset (de[index].ex.blk1, de[index].ex.blk2) + << (grub_le_to_cpu16 (data->sblock.log2_blksz) + - GRUB_DISK_SECTOR_BITS)); + } while (!(diro->dirpage->header.flags & GRUB_JFS_TREE_LEAF)); diff --git a/0367-fs-jfs-Inconsistent-signed-unsigned-types-usage-in-r.patch b/0367-fs-jfs-Inconsistent-signed-unsigned-types-usage-in-r.patch new file mode 100644 index 0000000..33c684b --- /dev/null +++ b/0367-fs-jfs-Inconsistent-signed-unsigned-types-usage-in-r.patch @@ -0,0 +1,85 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lidong Chen +Date: Mon, 16 Dec 2024 20:22:40 +0000 +Subject: [PATCH] fs/jfs: Inconsistent signed/unsigned types usage in return + values + +The getblk() returns a value of type grub_int64_t which is assigned to +iagblk and inoblk, both of type grub_uint64_t, in grub_jfs_read_inode() +via grub_jfs_blkno(). This patch fixes the type mismatch in the +functions. Additionally, the getblk() will return 0 instead of -1 on +failure cases. This change is safe because grub_errno is always set in +getblk() to indicate errors and it is later checked in the callers. + +Signed-off-by: Lidong Chen +Reviewed-by: Alec Brown +Reviewed-by: Ross Philipson +Reviewed-by: Daniel Kiper +--- + grub-core/fs/jfs.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +diff --git a/grub-core/fs/jfs.c b/grub-core/fs/jfs.c +index 2bde48d45..70a2f4947 100644 +--- a/grub-core/fs/jfs.c ++++ b/grub-core/fs/jfs.c +@@ -279,7 +279,7 @@ get_ext_offset (grub_uint8_t offset1, grub_uint32_t offset2) + return (((grub_uint64_t) offset1 << 32) | grub_le_to_cpu32 (offset2)); + } + +-static grub_int64_t ++static grub_uint64_t + getblk (struct grub_jfs_treehead *treehead, + struct grub_jfs_tree_extent *extents, + int max_extents, +@@ -290,6 +290,8 @@ getblk (struct grub_jfs_treehead *treehead, + int i; + grub_uint64_t ext_offset, ext_blk; + ++ grub_errno = GRUB_ERR_NONE; ++ + for (i = 0; i < grub_le_to_cpu16 (treehead->count) - 2 && + i < max_extents; i++) + { +@@ -312,7 +314,7 @@ getblk (struct grub_jfs_treehead *treehead, + + if (found != -1) + { +- grub_int64_t ret = -1; ++ grub_uint64_t ret = 0; + struct + { + struct grub_jfs_treehead treehead; +@@ -321,7 +323,7 @@ getblk (struct grub_jfs_treehead *treehead, + + tree = grub_zalloc (sizeof (*tree)); + if (!tree) +- return -1; ++ return 0; + + if (!grub_disk_read (data->disk, + (grub_disk_addr_t) ext_blk +@@ -334,19 +336,20 @@ getblk (struct grub_jfs_treehead *treehead, + else + { + grub_error (GRUB_ERR_BAD_FS, "jfs: infinite recursion detected"); +- ret = -1; ++ ret = 0; + } + } + grub_free (tree); + return ret; + } + +- return -1; ++ grub_error (GRUB_ERR_READ_ERROR, "jfs: block %" PRIuGRUB_UINT64_T " not found", blk); ++ return 0; + } + + /* Get the block number for the block BLK in the node INODE in the + mounted filesystem DATA. */ +-static grub_int64_t ++static grub_uint64_t + grub_jfs_blkno (struct grub_jfs_data *data, struct grub_jfs_inode *inode, + grub_uint64_t blk) + { diff --git a/0368-fs-ext2-Fix-out-of-bounds-read-for-inline-extents.patch b/0368-fs-ext2-Fix-out-of-bounds-read-for-inline-extents.patch new file mode 100644 index 0000000..6aa086b --- /dev/null +++ b/0368-fs-ext2-Fix-out-of-bounds-read-for-inline-extents.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Fri, 31 May 2024 15:14:23 +0800 +Subject: [PATCH] fs/ext2: Fix out-of-bounds read for inline extents + +When inline extents are used, i.e. the extent tree depth equals zero, +a maximum of four entries can fit into the inode's data block. If the +extent header states a number of entries greater than four the current +ext2 implementation causes an out-of-bounds read. Fix this issue by +capping the number of extents to four when reading inline extents. + +Reported-by: Daniel Axtens +Signed-off-by: Michael Chang +Reviewed-by: Daniel Kiper +--- + grub-core/fs/ext2.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/grub-core/fs/ext2.c b/grub-core/fs/ext2.c +index 731d346f8..eac639e36 100644 +--- a/grub-core/fs/ext2.c ++++ b/grub-core/fs/ext2.c +@@ -481,6 +481,8 @@ grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) + struct grub_ext4_extent *ext; + int i; + grub_disk_addr_t ret; ++ grub_uint16_t nent; ++ const grub_uint16_t max_inline_ext = sizeof (inode->blocks) / sizeof (*ext) - 1; /* Minus 1 extent header. */ + + leaf = grub_ext4_find_leaf (data, (struct grub_ext4_extent_header *) inode->blocks.dir_blocks, fileblock); + if (! leaf) +@@ -490,7 +492,13 @@ grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) + } + + ext = (struct grub_ext4_extent *) (leaf + 1); +- for (i = 0; i < grub_le_to_cpu16 (leaf->entries); i++) ++ ++ nent = grub_le_to_cpu16 (leaf->entries); ++ ++ if (leaf->depth == 0) ++ nent = grub_min (nent, max_inline_ext); ++ ++ for (i = 0; i < nent; i++) + { + if (fileblock < grub_le_to_cpu32 (ext[i].block)) + break; diff --git a/0369-fs-ntfs-Fix-out-of-bounds-read.patch b/0369-fs-ntfs-Fix-out-of-bounds-read.patch new file mode 100644 index 0000000..bd3b418 --- /dev/null +++ b/0369-fs-ntfs-Fix-out-of-bounds-read.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Mon, 3 Jun 2024 12:12:06 +0800 +Subject: [PATCH] fs/ntfs: Fix out-of-bounds read + +When parsing NTFS file records the presence of the 0xFF marker indicates +the end of the attribute list. This value signifies that there are no +more attributes to process. + +However, when the end marker is missing due to corrupted metadata the +loop continues to read beyond the attribute list resulting in out-of-bounds +reads and potentially entering an infinite loop. + +This patch adds a check to provide a stop condition for the loop ensuring +it stops at the end of the attribute list or at the end of the Master File +Table. This guards against out-of-bounds reads and prevents infinite loops. + +Reported-by: Daniel Axtens +Signed-off-by: Michael Chang +Reviewed-by: Daniel Kiper +--- + grub-core/fs/ntfs.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index deb058ac9..976ad1dc4 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -139,6 +139,8 @@ free_attr (struct grub_ntfs_attr *at) + static grub_uint8_t * + find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + { ++ grub_uint8_t *mft_end; ++ + if (at->flags & GRUB_NTFS_AF_ALST) + { + retry: +@@ -191,7 +193,8 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + return NULL; + } + at->attr_cur = at->attr_nxt; +- while (*at->attr_cur != 0xFF) ++ mft_end = at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR); ++ while (at->attr_cur < mft_end && *at->attr_cur != 0xFF) + { + at->attr_nxt += u16at (at->attr_cur, 4); + if (*at->attr_cur == GRUB_NTFS_AT_ATTRIBUTE_LIST) diff --git a/0370-fs-ntfs-Track-the-end-of-the-MFT-attribute-buffer.patch b/0370-fs-ntfs-Track-the-end-of-the-MFT-attribute-buffer.patch new file mode 100644 index 0000000..7f7e47f --- /dev/null +++ b/0370-fs-ntfs-Track-the-end-of-the-MFT-attribute-buffer.patch @@ -0,0 +1,141 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: B Horn +Date: Tue, 7 Jan 2025 11:38:34 +0000 +Subject: [PATCH] fs/ntfs: Track the end of the MFT attribute buffer + +The end of the attribute buffer should be stored alongside the rest of +the attribute struct as right now it is not possible to implement bounds +checking when accessing attributes sequentially. + +This is done via: + - updating init_attr() to set at->end and check is is not initially out of bounds, + - implementing checks as init_attr() had its type change in its callers, + - updating the value of at->end when needed. + +Signed-off-by: B Horn +Reviewed-by: Daniel Kiper +--- + grub-core/fs/ntfs.c | 34 ++++++++++++++++++++++++++++------ + include/grub/ntfs.h | 1 + + 2 files changed, 29 insertions(+), 6 deletions(-) + +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index 976ad1dc4..562b4f7eb 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -119,13 +119,20 @@ static grub_err_t read_data (struct grub_ntfs_attr *at, grub_uint8_t *pa, + grub_disk_read_hook_t read_hook, + void *read_hook_data); + +-static void ++static grub_err_t + init_attr (struct grub_ntfs_attr *at, struct grub_ntfs_file *mft) + { + at->mft = mft; + at->flags = (mft == &mft->data->mmft) ? GRUB_NTFS_AF_MMFT : 0; + at->attr_nxt = mft->buf + first_attr_off (mft->buf); ++ at->end = mft->buf + (mft->data->mft_size << GRUB_NTFS_BLK_SHR); ++ ++ if (at->attr_nxt > at->end) ++ return grub_error (GRUB_ERR_BAD_FS, "attributes start outside the MFT"); ++ + at->attr_end = at->emft_buf = at->edat_buf = at->sbuf = NULL; ++ ++ return GRUB_ERR_NONE; + } + + static void +@@ -239,6 +246,10 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + pa_end = at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR); + } + at->flags |= GRUB_NTFS_AF_ALST; ++ ++ /* From this point on pa_end is the end of the buffer */ ++ at->end = pa_end; ++ + while (at->attr_nxt < at->attr_end) + { + if ((*at->attr_nxt == attr) || (attr == 0)) +@@ -298,7 +309,9 @@ locate_attr (struct grub_ntfs_attr *at, struct grub_ntfs_file *mft, + { + grub_uint8_t *pa; + +- init_attr (at, mft); ++ if (init_attr (at, mft) != GRUB_ERR_NONE) ++ return NULL; ++ + pa = find_attr (at, attr); + if (pa == NULL) + return NULL; +@@ -314,7 +327,8 @@ locate_attr (struct grub_ntfs_attr *at, struct grub_ntfs_file *mft, + } + grub_errno = GRUB_ERR_NONE; + free_attr (at); +- init_attr (at, mft); ++ if (init_attr (at, mft) != GRUB_ERR_NONE) ++ return NULL; + pa = find_attr (at, attr); + } + return pa; +@@ -585,7 +599,7 @@ init_file (struct grub_ntfs_file *mft, grub_uint64_t mftno) + mft->attr.attr_end = 0; /* Don't jump to attribute list */ + } + else +- init_attr (&mft->attr, mft); ++ return init_attr (&mft->attr, mft); + + return 0; + } +@@ -807,7 +821,9 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, + bmp = NULL; + + at = &attr; +- init_attr (at, mft); ++ if (init_attr (at, mft) != GRUB_ERR_NONE) ++ return 0; ++ + while (1) + { + cur_pos = find_attr (at, GRUB_NTFS_AT_INDEX_ROOT); +@@ -838,7 +854,9 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, + bitmap = NULL; + bitmap_len = 0; + free_attr (at); ++ /* No need to check errors here, as it will already be fine */ + init_attr (at, mft); ++ + while ((cur_pos = find_attr (at, GRUB_NTFS_AT_BITMAP)) != NULL) + { + int ofs; +@@ -1203,6 +1221,7 @@ grub_ntfs_label (grub_device_t device, char **label) + struct grub_ntfs_data *data = 0; + struct grub_fshelp_node *mft = 0; + grub_uint8_t *pa; ++ grub_err_t err; + + grub_dl_ref (my_mod); + +@@ -1228,7 +1247,10 @@ grub_ntfs_label (grub_device_t device, char **label) + goto fail; + } + +- init_attr (&mft->attr, mft); ++ err = init_attr (&mft->attr, mft); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ + pa = find_attr (&mft->attr, GRUB_NTFS_AT_VOLUME_NAME); + + if (pa >= mft->buf + (mft->data->mft_size << GRUB_NTFS_BLK_SHR)) +diff --git a/include/grub/ntfs.h b/include/grub/ntfs.h +index d1a6af696..ec1c4db38 100644 +--- a/include/grub/ntfs.h ++++ b/include/grub/ntfs.h +@@ -134,6 +134,7 @@ struct grub_ntfs_attr + grub_uint8_t *attr_cur, *attr_nxt, *attr_end; + grub_uint32_t save_pos; + grub_uint8_t *sbuf; ++ grub_uint8_t *end; + struct grub_ntfs_file *mft; + }; + diff --git a/0371-fs-ntfs-Use-a-helper-function-to-access-attributes.patch b/0371-fs-ntfs-Use-a-helper-function-to-access-attributes.patch new file mode 100644 index 0000000..59e2462 --- /dev/null +++ b/0371-fs-ntfs-Use-a-helper-function-to-access-attributes.patch @@ -0,0 +1,183 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: B Horn +Date: Tue, 14 May 2024 12:39:56 +0100 +Subject: [PATCH] fs/ntfs: Use a helper function to access attributes + +Right now to access the next attribute the code reads the length of the +current attribute and adds that to the current pointer. This is error +prone as bounds checking needs to be performed all over the place. So, +implement a helper and ensure its used across find_attr() and read_attr(). + +This commit does *not* implement full bounds checking. It is just the +preparation work for this to be added into the helper. + +Signed-off-by: B Horn +Reviewed-by: Daniel Kiper +--- + grub-core/fs/ntfs.c | 69 +++++++++++++++++++++++++++++++++++++++++++---------- + include/grub/ntfs.h | 2 ++ + 2 files changed, 58 insertions(+), 13 deletions(-) + +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index 562b4f7eb..9311ba9ef 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -70,6 +70,25 @@ res_attr_data_len (void *res_attr_ptr) + return u32at (res_attr_ptr, 0x10); + } + ++/* Return the next attribute if it exists, otherwise return NULL. */ ++static grub_uint8_t * ++next_attribute (grub_uint8_t *curr_attribute, void *end) ++{ ++ grub_uint8_t *next = curr_attribute; ++ ++ /* ++ * Need to verify we aren't exceeding the end of the buffer by reading the ++ * header for the current attribute ++ */ ++ if (curr_attribute + GRUB_NTFS_ATTRIBUTE_HEADER_SIZE >= (grub_uint8_t *) end) ++ return NULL; ++ ++ next += u16at (curr_attribute, 4); ++ ++ return next; ++} ++ ++ + grub_ntfscomp_func_t grub_ntfscomp_func; + + static grub_err_t +@@ -151,13 +170,13 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + if (at->flags & GRUB_NTFS_AF_ALST) + { + retry: +- while (at->attr_nxt < at->attr_end) ++ while (at->attr_nxt) + { + at->attr_cur = at->attr_nxt; +- at->attr_nxt += u16at (at->attr_cur, 4); ++ at->attr_nxt = next_attribute (at->attr_cur, at->attr_end); + if ((*at->attr_cur == attr) || (attr == 0)) + { +- grub_uint8_t *new_pos; ++ grub_uint8_t *new_pos, *end; + + if (at->flags & GRUB_NTFS_AF_MMFT) + { +@@ -181,15 +200,36 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + return NULL; + } + ++ /* ++ * Only time emft_bufs is defined is in this function, with this ++ * size. ++ */ ++ grub_size_t emft_buf_size = ++ at->mft->data->mft_size << GRUB_NTFS_BLK_SHR; ++ ++ /* ++ * Needs to be enough space for the successful case to even ++ * bother. ++ */ ++ if (first_attr_off (at->emft_buf) >= (emft_buf_size - 0x18 - 2)) ++ { ++ grub_error (GRUB_ERR_BAD_FS, ++ "can\'t find 0x%X in attribute list", ++ (unsigned char) *at->attr_cur); ++ return NULL; ++ } ++ + new_pos = &at->emft_buf[first_attr_off (at->emft_buf)]; +- while (*new_pos != 0xFF) ++ end = &at->emft_buf[emft_buf_size]; ++ ++ while (new_pos && *new_pos != 0xFF) + { + if ((*new_pos == *at->attr_cur) + && (u16at (new_pos, 0xE) == u16at (at->attr_cur, 0x18))) + { + return new_pos; + } +- new_pos += u16at (new_pos, 4); ++ new_pos = next_attribute (new_pos, end); + } + grub_error (GRUB_ERR_BAD_FS, + "can\'t find 0x%X in attribute list", +@@ -203,7 +243,7 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + mft_end = at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR); + while (at->attr_cur < mft_end && *at->attr_cur != 0xFF) + { +- at->attr_nxt += u16at (at->attr_cur, 4); ++ at->attr_nxt = next_attribute (at->attr_cur, at->end); + if (*at->attr_cur == GRUB_NTFS_AT_ATTRIBUTE_LIST) + at->attr_end = at->attr_cur; + if ((*at->attr_cur == attr) || (attr == 0)) +@@ -250,13 +290,14 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + /* From this point on pa_end is the end of the buffer */ + at->end = pa_end; + +- while (at->attr_nxt < at->attr_end) ++ while (at->attr_nxt) + { + if ((*at->attr_nxt == attr) || (attr == 0)) + break; +- at->attr_nxt += u16at (at->attr_nxt, 4); ++ at->attr_nxt = next_attribute (at->attr_nxt, pa_end); + } +- if (at->attr_nxt >= at->attr_end) ++ ++ if (at->attr_nxt >= at->attr_end || at->attr_nxt == NULL) + return NULL; + + if ((at->flags & GRUB_NTFS_AF_MMFT) && (attr == GRUB_NTFS_AT_DATA)) +@@ -277,7 +318,8 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + grub_cpu_to_le32 (at->mft->data->mft_start + + 1)); + pa = at->attr_nxt + u16at (pa, 4); +- while (pa < at->attr_end) ++ ++ while (pa) + { + if (*pa != attr) + break; +@@ -293,7 +335,7 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + u32at (pa, 0x10) * (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR), + at->mft->data->mft_size << GRUB_NTFS_BLK_SHR, 0, 0, 0)) + return NULL; +- pa += u16at (pa, 4); ++ pa = next_attribute (pa, pa_end); + } + at->attr_nxt = at->attr_cur; + at->flags &= ~GRUB_NTFS_AF_GPOS; +@@ -530,14 +572,15 @@ read_attr (struct grub_ntfs_attr *at, grub_uint8_t *dest, grub_disk_addr_t ofs, + else + vcn = ofs >> (at->mft->data->log_spc + GRUB_NTFS_BLK_SHR); + pa = at->attr_nxt + u16at (at->attr_nxt, 4); +- while (pa < at->attr_end) ++ ++ while (pa) + { + if (*pa != attr) + break; + if (u32at (pa, 8) > vcn) + break; + at->attr_nxt = pa; +- pa += u16at (pa, 4); ++ pa = next_attribute (pa, at->attr_end); + } + } + pp = find_attr (at, attr); +diff --git a/include/grub/ntfs.h b/include/grub/ntfs.h +index ec1c4db38..2c8078403 100644 +--- a/include/grub/ntfs.h ++++ b/include/grub/ntfs.h +@@ -89,6 +89,8 @@ enum + #define GRUB_NTFS_COM_SEC (GRUB_NTFS_COM_LEN >> GRUB_NTFS_BLK_SHR) + #define GRUB_NTFS_LOG_COM_SEC (GRUB_NTFS_COM_LOG_LEN - GRUB_NTFS_BLK_SHR) + ++#define GRUB_NTFS_ATTRIBUTE_HEADER_SIZE 16 ++ + enum + { + GRUB_NTFS_AF_ALST = 1, diff --git a/0372-fs-ntfs-Implement-attribute-verification.patch b/0372-fs-ntfs-Implement-attribute-verification.patch new file mode 100644 index 0000000..1498a56 --- /dev/null +++ b/0372-fs-ntfs-Implement-attribute-verification.patch @@ -0,0 +1,245 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: B Horn +Date: Tue, 14 May 2024 12:39:56 +0100 +Subject: [PATCH] fs/ntfs: Implement attribute verification + +It was possible to read OOB when an attribute had a size that exceeded +the allocated buffer. This resolves that by making sure all attributes +that get read are fully in the allocated space by implementing +a function to validate them. + +Defining the offsets in include/grub/ntfs.h but they are only used in +the validation function and not across the rest of the NTFS code. + +Signed-off-by: B Horn +Reviewed-by: Daniel Kiper +--- + grub-core/fs/ntfs.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + include/grub/ntfs.h | 22 ++++++++ + 2 files changed, 175 insertions(+) + +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index 9311ba9ef..8fdb8f2ff 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -70,6 +70,149 @@ res_attr_data_len (void *res_attr_ptr) + return u32at (res_attr_ptr, 0x10); + } + ++/* ++ * Check if the attribute is valid and doesn't exceed the allocated region. ++ * This accounts for resident and non-resident data. ++ * ++ * This is based off the documentation from the linux-ntfs project: ++ * https://flatcap.github.io/linux-ntfs/ntfs/concepts/attribute_header.html ++ */ ++static bool ++validate_attribute (grub_uint8_t *attr, void *end) ++{ ++ grub_size_t attr_size = 0; ++ grub_size_t min_size = 0; ++ grub_size_t spare = (grub_uint8_t *) end - attr; ++ /* ++ * Just used as a temporary variable to try and deal with cases where someone ++ * tries to overlap fields. ++ */ ++ grub_size_t curr = 0; ++ ++ /* Need verify we can entirely read the attributes header. */ ++ if (attr + GRUB_NTFS_ATTRIBUTE_HEADER_SIZE >= (grub_uint8_t *) end) ++ goto fail; ++ ++ /* ++ * So, the rest of this code uses a 16bit int for the attribute length but ++ * from reading the all the documentation I could find it says this field is ++ * actually 32bit. But let's be consistent with the rest of the code. ++ * ++ * https://elixir.bootlin.com/linux/v6.10.7/source/fs/ntfs3/ntfs.h#L370 ++ */ ++ attr_size = u16at (attr, GRUB_NTFS_ATTRIBUTE_LENGTH); ++ ++ if (attr_size > spare) ++ goto fail; ++ ++ /* Not an error case, just reached the end of the attributes. */ ++ if (attr_size == 0) ++ return false; ++ ++ /* ++ * Extra validation by trying to calculate a minimum possible size for this ++ * attribute. +8 from the size of the resident data struct which is the ++ * minimum that can be added. ++ */ ++ min_size = GRUB_NTFS_ATTRIBUTE_HEADER_SIZE + 8; ++ ++ if (min_size > attr_size) ++ goto fail; ++ ++ /* Is the data is resident (0) or not (1). */ ++ if (attr[GRUB_NTFS_ATTRIBUTE_RESIDENT] == 0) ++ { ++ /* Read the offset and size of the attribute. */ ++ curr = u16at (attr, GRUB_NTFS_ATTRIBUTE_RES_OFFSET); ++ curr += u32at (attr, GRUB_NTFS_ATTRIBUTE_RES_LENGTH); ++ if (curr > min_size) ++ min_size = curr; ++ } ++ else ++ { ++ /* ++ * If the data is non-resident, the minimum size is 64 which is where ++ * the data runs start. We already have a minimum size of 24. So, just ++ * adding 40 to get to the real value. ++ */ ++ min_size += 40; ++ if (min_size > attr_size) ++ goto fail; ++ /* If the compression unit size is > 0, +8 bytes*/ ++ if (u16at (attr, GRUB_NTFS_ATTRIBUTE_COMPRESSION_UNIT_SIZE) > 0) ++ min_size += 8; ++ ++ /* ++ * Need to consider the data runs now. Each member of the run has byte ++ * that describes the size of the data length and offset. Each being ++ * 4 bits in the byte. ++ */ ++ curr = u16at (attr, GRUB_NTFS_ATTRIBUTE_DATA_RUNS); ++ ++ if (curr + 1 > min_size) ++ min_size = curr + 1; ++ ++ if (min_size > attr_size) ++ goto fail; ++ ++ /* ++ * Each attribute can store multiple data runs which are stored ++ * continuously in the attribute. They exist as one header byte ++ * with up to 14 bytes following it depending on the lengths. ++ * We stop when we hit a header that is just a NUL byte. ++ * ++ * https://flatcap.github.io/linux-ntfs/ntfs/concepts/data_runs.html ++ */ ++ while (attr[curr] != 0) ++ { ++ /* ++ * We stop when we hit a header that is just a NUL byte. The data ++ * run header is stored as a single byte where the top 4 bits refer ++ * to the number of bytes used to store the total length of the ++ * data run, and the number of bytes used to store the offset. ++ * These directly follow the header byte, so we use them to update ++ * the minimum size. ++ */ ++ min_size += (attr[curr] & 0x7) + ((attr[curr] >> 4) & 0x7); ++ curr += min_size; ++ min_size++; ++ if (min_size > attr_size) ++ goto fail; ++ } ++ } ++ ++ /* Name offset, doing this after data residence checks. */ ++ if (u16at (attr, GRUB_NTFS_ATTRIBUTE_NAME_OFFSET) != 0) ++ { ++ curr = u16at (attr, GRUB_NTFS_ATTRIBUTE_NAME_OFFSET); ++ /* ++ * Multiple the name length by 2 as its UTF-16. Can be zero if this in an ++ * unamed attribute. ++ */ ++ curr += attr[GRUB_NTFS_ATTRIBUTE_NAME_LENGTH] * 2; ++ if (curr > min_size) ++ min_size = curr; ++ } ++ ++ /* Padded to 8 bytes. */ ++ if (min_size % 8 != 0) ++ min_size += 8 - (min_size % 8); ++ ++ /* ++ * At this point min_size should be exactly attr_size but being flexible ++ * here to avoid any issues. ++ */ ++ if (min_size > attr_size) ++ goto fail; ++ ++ return true; ++ ++ fail: ++ grub_dprintf ("ntfs", "spare=%" PRIuGRUB_SIZE " min_size=%" PRIuGRUB_SIZE " attr_size=%" PRIuGRUB_SIZE "\n", ++ spare, min_size, attr_size); ++ return false; ++} ++ + /* Return the next attribute if it exists, otherwise return NULL. */ + static grub_uint8_t * + next_attribute (grub_uint8_t *curr_attribute, void *end) +@@ -84,6 +227,8 @@ next_attribute (grub_uint8_t *curr_attribute, void *end) + return NULL; + + next += u16at (curr_attribute, 4); ++ if (validate_attribute (next, end) == false) ++ return NULL; + + return next; + } +@@ -290,6 +435,9 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + /* From this point on pa_end is the end of the buffer */ + at->end = pa_end; + ++ if (validate_attribute (at->attr_nxt, pa_end) == false) ++ return NULL; ++ + while (at->attr_nxt) + { + if ((*at->attr_nxt == attr) || (attr == 0)) +@@ -319,6 +467,9 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + + 1)); + pa = at->attr_nxt + u16at (pa, 4); + ++ if (validate_attribute (pa, pa_end) == true) ++ pa = NULL; ++ + while (pa) + { + if (*pa != attr) +@@ -572,6 +723,8 @@ read_attr (struct grub_ntfs_attr *at, grub_uint8_t *dest, grub_disk_addr_t ofs, + else + vcn = ofs >> (at->mft->data->log_spc + GRUB_NTFS_BLK_SHR); + pa = at->attr_nxt + u16at (at->attr_nxt, 4); ++ if (validate_attribute (pa, at->attr_end) == false) ++ pa = NULL; + + while (pa) + { +diff --git a/include/grub/ntfs.h b/include/grub/ntfs.h +index 2c8078403..77b182acf 100644 +--- a/include/grub/ntfs.h ++++ b/include/grub/ntfs.h +@@ -91,6 +91,28 @@ enum + + #define GRUB_NTFS_ATTRIBUTE_HEADER_SIZE 16 + ++/* ++ * To make attribute validation clearer the offsets for each value in the ++ * attribute headers are defined as macros. ++ * ++ * These offsets are all from: ++ * https://flatcap.github.io/linux-ntfs/ntfs/concepts/attribute_header.html ++ */ ++ ++/* These offsets are part of the attribute header. */ ++#define GRUB_NTFS_ATTRIBUTE_LENGTH 4 ++#define GRUB_NTFS_ATTRIBUTE_RESIDENT 8 ++#define GRUB_NTFS_ATTRIBUTE_NAME_LENGTH 9 ++#define GRUB_NTFS_ATTRIBUTE_NAME_OFFSET 10 ++ ++/* Offsets for values needed for resident data. */ ++#define GRUB_NTFS_ATTRIBUTE_RES_LENGTH 16 ++#define GRUB_NTFS_ATTRIBUTE_RES_OFFSET 20 ++ ++/* Offsets for values needed for non-resident data. */ ++#define GRUB_NTFS_ATTRIBUTE_DATA_RUNS 32 ++#define GRUB_NTFS_ATTRIBUTE_COMPRESSION_UNIT_SIZE 34 ++ + enum + { + GRUB_NTFS_AF_ALST = 1, diff --git a/0373-fs-xfs-Fix-out-of-bounds-read.patch b/0373-fs-xfs-Fix-out-of-bounds-read.patch new file mode 100644 index 0000000..941a5a9 --- /dev/null +++ b/0373-fs-xfs-Fix-out-of-bounds-read.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Fri, 31 May 2024 15:14:57 +0800 +Subject: [PATCH] fs/xfs: Fix out-of-bounds read + +The number of records in the root key array read from disk was not being +validated against the size of the root node. This could lead to an +out-of-bounds read. + +This patch adds a check to ensure that the number of records in the root +key array does not exceed the expected size of a root node read from +disk. If this check detects an out-of-bounds condition the operation is +aborted to prevent random errors due to metadata corruption. + +Reported-by: Daniel Axtens +Signed-off-by: Michael Chang +Reviewed-by: Daniel Kiper +--- + grub-core/fs/xfs.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c +index e3816d1ec..43be00e99 100644 +--- a/grub-core/fs/xfs.c ++++ b/grub-core/fs/xfs.c +@@ -568,6 +568,17 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) + do + { + int i; ++ grub_addr_t keys_end, data_end; ++ ++ if (grub_mul (sizeof (grub_uint64_t), nrec, &keys_end) || ++ grub_add ((grub_addr_t) keys, keys_end, &keys_end) || ++ grub_add ((grub_addr_t) node->data, node->data->data_size, &data_end) || ++ keys_end > data_end) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "invalid number of XFS root keys"); ++ grub_free (leaf); ++ return 0; ++ } + + for (i = 0; i < nrec; i++) + { diff --git a/0374-fs-xfs-Ensuring-failing-to-mount-sets-a-grub_errno.patch b/0374-fs-xfs-Ensuring-failing-to-mount-sets-a-grub_errno.patch new file mode 100644 index 0000000..e73bdbf --- /dev/null +++ b/0374-fs-xfs-Ensuring-failing-to-mount-sets-a-grub_errno.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: B Horn +Date: Sun, 12 May 2024 06:03:58 +0100 +Subject: [PATCH] fs/xfs: Ensuring failing to mount sets a grub_errno + +It was previously possible for grub_xfs_mount() to return NULL without +setting grub_errno if the XFS version was invalid. This resulted in it +being possible for grub_dl_unref() to be called twice allowing the XFS +module to be unloaded while there were still references to it. + +Fixing this problem in general by ensuring a grub_errno is set if the +fail label is reached. + +Reported-by: B Horn +Signed-off-by: B Horn +Reviewed-by: Daniel Kiper +--- + grub-core/fs/xfs.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c +index 43be00e99..9d3420ece 100644 +--- a/grub-core/fs/xfs.c ++++ b/grub-core/fs/xfs.c +@@ -315,6 +315,8 @@ static int grub_xfs_sb_valid(struct grub_xfs_data *data) + } + return 1; + } ++ ++ grub_error (GRUB_ERR_BAD_FS, "unsupported XFS filesystem version"); + return 0; + } + +@@ -984,7 +986,7 @@ grub_xfs_mount (grub_disk_t disk) + return data; + fail: + +- if (grub_errno == GRUB_ERR_OUT_OF_RANGE) ++ if (grub_errno == GRUB_ERR_OUT_OF_RANGE || grub_errno == GRUB_ERR_NONE) + grub_error (GRUB_ERR_BAD_FS, "not an XFS filesystem"); + + grub_free (data); diff --git a/0375-kern-file-Ensure-file-data-is-set.patch b/0375-kern-file-Ensure-file-data-is-set.patch new file mode 100644 index 0000000..9436f5d --- /dev/null +++ b/0375-kern-file-Ensure-file-data-is-set.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: B Horn +Date: Sun, 12 May 2024 03:01:40 +0100 +Subject: [PATCH] kern/file: Ensure file->data is set + +This is to avoid a generic issue were some filesystems would not set +data and also not set a grub_errno. This meant it was possible for many +filesystems to grub_dl_unref() themselves multiple times resulting in +it being possible to unload the filesystems while there were still +references to them, e.g., via a loopback. + +Reported-by: B Horn +Signed-off-by: B Horn +Reviewed-by: Daniel Kiper +--- + grub-core/kern/file.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c +index 868ce3b63..1dc4339dc 100644 +--- a/grub-core/kern/file.c ++++ b/grub-core/kern/file.c +@@ -124,6 +124,9 @@ grub_file_open (const char *name, enum grub_file_type type) + if ((file->fs->fs_open) (file, file_name) != GRUB_ERR_NONE) + goto fail; + ++ if (file->data == NULL) ++ goto fail; ++ + file->name = grub_strdup (name); + grub_errno = GRUB_ERR_NONE; + diff --git a/0376-kern-file-Implement-filesystem-reference-counting.patch b/0376-kern-file-Implement-filesystem-reference-counting.patch new file mode 100644 index 0000000..8db4ab7 --- /dev/null +++ b/0376-kern-file-Implement-filesystem-reference-counting.patch @@ -0,0 +1,440 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: B Horn +Date: Tue, 11 Feb 2025 13:44:25 -0600 +Subject: [PATCH] kern/file: Implement filesystem reference counting + +The grub_file_open() and grub_file_close() should be the only places +that allow a reference to a filesystem to stay open. So, add grub_dl_t +to grub_fs_t and set this in the GRUB_MOD_INIT() for each filesystem to +avoid issues when filesystems forget to do it themselves or do not track +their own references, e.g. squash4. + +The fs_label(), fs_uuid(), fs_mtime() and fs_read() should all ref and +unref in the same function but it is essentially redundant in GRUB +single threaded model. + +Signed-off-by: B Horn +Reviewed-by: Daniel Kiper +--- + grub-core/fs/affs.c | 1 + + grub-core/fs/bfs.c | 1 + + grub-core/fs/btrfs.c | 1 + + grub-core/fs/cbfs.c | 1 + + grub-core/fs/cpio.c | 1 + + grub-core/fs/cpio_be.c | 1 + + grub-core/fs/ext2.c | 1 + + grub-core/fs/f2fs.c | 1 + + grub-core/fs/fat.c | 1 + + grub-core/fs/hfs.c | 1 + + grub-core/fs/hfsplus.c | 1 + + grub-core/fs/iso9660.c | 1 + + grub-core/fs/jfs.c | 1 + + grub-core/fs/minix.c | 1 + + grub-core/fs/newc.c | 1 + + grub-core/fs/nilfs2.c | 1 + + grub-core/fs/ntfs.c | 1 + + grub-core/fs/odc.c | 1 + + grub-core/fs/proc.c | 1 + + grub-core/fs/reiserfs.c | 1 + + grub-core/fs/romfs.c | 1 + + grub-core/fs/sfs.c | 1 + + grub-core/fs/squash4.c | 1 + + grub-core/fs/tar.c | 1 + + grub-core/fs/udf.c | 1 + + grub-core/fs/ufs.c | 1 + + grub-core/fs/xfs.c | 1 + + grub-core/fs/zfs/zfs.c | 1 + + grub-core/kern/file.c | 7 +++++++ + include/grub/fs.h | 4 ++++ + 30 files changed, 39 insertions(+) + +diff --git a/grub-core/fs/affs.c b/grub-core/fs/affs.c +index cafcd0fba..b1c64e77d 100644 +--- a/grub-core/fs/affs.c ++++ b/grub-core/fs/affs.c +@@ -699,6 +699,7 @@ static struct grub_fs grub_affs_fs = + + GRUB_MOD_INIT(affs) + { ++ grub_affs_fs.mod = mod; + grub_fs_register (&grub_affs_fs); + my_mod = mod; + } +diff --git a/grub-core/fs/bfs.c b/grub-core/fs/bfs.c +index 47dbe2011..17705812d 100644 +--- a/grub-core/fs/bfs.c ++++ b/grub-core/fs/bfs.c +@@ -1104,6 +1104,7 @@ GRUB_MOD_INIT (bfs) + { + COMPILE_TIME_ASSERT (1 << LOG_EXTENT_SIZE == + sizeof (struct grub_bfs_extent)); ++ grub_bfs_fs.mod = mod; + grub_fs_register (&grub_bfs_fs); + } + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index 47325f6ad..3ed37a4db 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -3365,6 +3365,7 @@ subvol_get_env (struct grub_env_var *var __attribute__ ((unused)), + + GRUB_MOD_INIT (btrfs) + { ++ grub_btrfs_fs.mod = mod; + grub_fs_register (&grub_btrfs_fs); + cmd_info = grub_register_command("btrfs-info", grub_cmd_btrfs_info, + "DEVICE", +diff --git a/grub-core/fs/cbfs.c b/grub-core/fs/cbfs.c +index 581215ef1..3e527cbf2 100644 +--- a/grub-core/fs/cbfs.c ++++ b/grub-core/fs/cbfs.c +@@ -390,6 +390,7 @@ GRUB_MOD_INIT (cbfs) + #if (defined (__i386__) || defined (__x86_64__)) && !defined (GRUB_UTIL) && !defined (GRUB_MACHINE_EMU) && !defined (GRUB_MACHINE_XEN) + init_cbfsdisk (); + #endif ++ grub_cbfs_fs.mod = mod; + grub_fs_register (&grub_cbfs_fs); + } + +diff --git a/grub-core/fs/cpio.c b/grub-core/fs/cpio.c +index dab5f9898..1799f7ff5 100644 +--- a/grub-core/fs/cpio.c ++++ b/grub-core/fs/cpio.c +@@ -52,6 +52,7 @@ read_number (const grub_uint16_t *arr, grub_size_t size) + + GRUB_MOD_INIT (cpio) + { ++ grub_cpio_fs.mod = mod; + grub_fs_register (&grub_cpio_fs); + } + +diff --git a/grub-core/fs/cpio_be.c b/grub-core/fs/cpio_be.c +index 846548892..7bed1b848 100644 +--- a/grub-core/fs/cpio_be.c ++++ b/grub-core/fs/cpio_be.c +@@ -52,6 +52,7 @@ read_number (const grub_uint16_t *arr, grub_size_t size) + + GRUB_MOD_INIT (cpio_be) + { ++ grub_cpio_fs.mod = mod; + grub_fs_register (&grub_cpio_fs); + } + +diff --git a/grub-core/fs/ext2.c b/grub-core/fs/ext2.c +index eac639e36..0ee22e675 100644 +--- a/grub-core/fs/ext2.c ++++ b/grub-core/fs/ext2.c +@@ -1113,6 +1113,7 @@ static struct grub_fs grub_ext2_fs = + + GRUB_MOD_INIT(ext2) + { ++ grub_ext2_fs.mod = mod; + grub_fs_register (&grub_ext2_fs); + my_mod = mod; + } +diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c +index f7daa9435..e5dcbc470 100644 +--- a/grub-core/fs/f2fs.c ++++ b/grub-core/fs/f2fs.c +@@ -1353,6 +1353,7 @@ static struct grub_fs grub_f2fs_fs = { + + GRUB_MOD_INIT (f2fs) + { ++ grub_f2fs_fs.mod = mod; + grub_fs_register (&grub_f2fs_fs); + my_mod = mod; + } +diff --git a/grub-core/fs/fat.c b/grub-core/fs/fat.c +index ff6200c5b..1cf355af4 100644 +--- a/grub-core/fs/fat.c ++++ b/grub-core/fs/fat.c +@@ -1312,6 +1312,7 @@ GRUB_MOD_INIT(fat) + #endif + { + COMPILE_TIME_ASSERT (sizeof (struct grub_fat_dir_entry) == 32); ++ grub_fat_fs.mod = mod; + grub_fs_register (&grub_fat_fs); + my_mod = mod; + } +diff --git a/grub-core/fs/hfs.c b/grub-core/fs/hfs.c +index bb7af5f67..3a9894443 100644 +--- a/grub-core/fs/hfs.c ++++ b/grub-core/fs/hfs.c +@@ -1434,6 +1434,7 @@ static struct grub_fs grub_hfs_fs = + + GRUB_MOD_INIT(hfs) + { ++ grub_hfs_fs.mod = mod; + if (!grub_is_lockdown ()) + grub_fs_register (&grub_hfs_fs); + my_mod = mod; +diff --git a/grub-core/fs/hfsplus.c b/grub-core/fs/hfsplus.c +index e7fd98a07..d5f90007b 100644 +--- a/grub-core/fs/hfsplus.c ++++ b/grub-core/fs/hfsplus.c +@@ -1150,6 +1150,7 @@ static struct grub_fs grub_hfsplus_fs = + + GRUB_MOD_INIT(hfsplus) + { ++ grub_hfsplus_fs.mod = mod; + grub_fs_register (&grub_hfsplus_fs); + my_mod = mod; + } +diff --git a/grub-core/fs/iso9660.c b/grub-core/fs/iso9660.c +index 7a59a65a5..0c0aae597 100644 +--- a/grub-core/fs/iso9660.c ++++ b/grub-core/fs/iso9660.c +@@ -1165,6 +1165,7 @@ static struct grub_fs grub_iso9660_fs = + + GRUB_MOD_INIT(iso9660) + { ++ grub_iso9660_fs.mod = mod; + grub_fs_register (&grub_iso9660_fs); + my_mod = mod; + } +diff --git a/grub-core/fs/jfs.c b/grub-core/fs/jfs.c +index 70a2f4947..b0283ac00 100644 +--- a/grub-core/fs/jfs.c ++++ b/grub-core/fs/jfs.c +@@ -1005,6 +1005,7 @@ static struct grub_fs grub_jfs_fs = + + GRUB_MOD_INIT(jfs) + { ++ grub_jfs_fs.mod = mod; + grub_fs_register (&grub_jfs_fs); + my_mod = mod; + } +diff --git a/grub-core/fs/minix.c b/grub-core/fs/minix.c +index 3cd18c85b..beb1a6378 100644 +--- a/grub-core/fs/minix.c ++++ b/grub-core/fs/minix.c +@@ -732,6 +732,7 @@ GRUB_MOD_INIT(minix) + #endif + #endif + { ++ grub_minix_fs.mod = mod; + grub_fs_register (&grub_minix_fs); + my_mod = mod; + } +diff --git a/grub-core/fs/newc.c b/grub-core/fs/newc.c +index 4fb8b2e3d..43b7f8b64 100644 +--- a/grub-core/fs/newc.c ++++ b/grub-core/fs/newc.c +@@ -64,6 +64,7 @@ read_number (const char *str, grub_size_t size) + + GRUB_MOD_INIT (newc) + { ++ grub_cpio_fs.mod = mod; + grub_fs_register (&grub_cpio_fs); + } + +diff --git a/grub-core/fs/nilfs2.c b/grub-core/fs/nilfs2.c +index 3c248a910..c44583ee8 100644 +--- a/grub-core/fs/nilfs2.c ++++ b/grub-core/fs/nilfs2.c +@@ -1231,6 +1231,7 @@ GRUB_MOD_INIT (nilfs2) + grub_nilfs2_dat_entry)); + COMPILE_TIME_ASSERT (1 << LOG_INODE_SIZE + == sizeof (struct grub_nilfs2_inode)); ++ grub_nilfs2_fs.mod = mod; + grub_fs_register (&grub_nilfs2_fs); + my_mod = mod; + } +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index 8fdb8f2ff..03e3e5c6a 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -1537,6 +1537,7 @@ static struct grub_fs grub_ntfs_fs = + + GRUB_MOD_INIT (ntfs) + { ++ grub_ntfs_fs.mod = mod; + grub_fs_register (&grub_ntfs_fs); + my_mod = mod; + } +diff --git a/grub-core/fs/odc.c b/grub-core/fs/odc.c +index 790000622..8e4e8aeac 100644 +--- a/grub-core/fs/odc.c ++++ b/grub-core/fs/odc.c +@@ -52,6 +52,7 @@ read_number (const char *str, grub_size_t size) + + GRUB_MOD_INIT (odc) + { ++ grub_cpio_fs.mod = mod; + grub_fs_register (&grub_cpio_fs); + } + +diff --git a/grub-core/fs/proc.c b/grub-core/fs/proc.c +index 5f516502d..bcde43349 100644 +--- a/grub-core/fs/proc.c ++++ b/grub-core/fs/proc.c +@@ -192,6 +192,7 @@ static struct grub_fs grub_procfs_fs = + + GRUB_MOD_INIT (procfs) + { ++ grub_procfs_fs.mod = mod; + grub_disk_dev_register (&grub_procfs_dev); + grub_fs_register (&grub_procfs_fs); + } +diff --git a/grub-core/fs/reiserfs.c b/grub-core/fs/reiserfs.c +index b8253da7f..d9a8bf602 100644 +--- a/grub-core/fs/reiserfs.c ++++ b/grub-core/fs/reiserfs.c +@@ -1407,6 +1407,7 @@ static struct grub_fs grub_reiserfs_fs = + + GRUB_MOD_INIT(reiserfs) + { ++ grub_reiserfs_fs.mod = mod; + grub_fs_register (&grub_reiserfs_fs); + my_mod = mod; + } +diff --git a/grub-core/fs/romfs.c b/grub-core/fs/romfs.c +index d97b8fbb8..a43546d95 100644 +--- a/grub-core/fs/romfs.c ++++ b/grub-core/fs/romfs.c +@@ -475,6 +475,7 @@ static struct grub_fs grub_romfs_fs = + + GRUB_MOD_INIT(romfs) + { ++ grub_romfs_fs.mod = mod; + grub_fs_register (&grub_romfs_fs); + } + +diff --git a/grub-core/fs/sfs.c b/grub-core/fs/sfs.c +index 983e88008..f0d7cac43 100644 +--- a/grub-core/fs/sfs.c ++++ b/grub-core/fs/sfs.c +@@ -779,6 +779,7 @@ static struct grub_fs grub_sfs_fs = + + GRUB_MOD_INIT(sfs) + { ++ grub_sfs_fs.mod = mod; + grub_fs_register (&grub_sfs_fs); + my_mod = mod; + } +diff --git a/grub-core/fs/squash4.c b/grub-core/fs/squash4.c +index 6dd731e23..ccfa3eea5 100644 +--- a/grub-core/fs/squash4.c ++++ b/grub-core/fs/squash4.c +@@ -1032,6 +1032,7 @@ static struct grub_fs grub_squash_fs = + + GRUB_MOD_INIT(squash4) + { ++ grub_squash_fs.mod = mod; + grub_fs_register (&grub_squash_fs); + } + +diff --git a/grub-core/fs/tar.c b/grub-core/fs/tar.c +index 386c09022..fd2ec1f74 100644 +--- a/grub-core/fs/tar.c ++++ b/grub-core/fs/tar.c +@@ -354,6 +354,7 @@ static struct grub_fs grub_cpio_fs = { + + GRUB_MOD_INIT (tar) + { ++ grub_cpio_fs.mod = mod; + grub_fs_register (&grub_cpio_fs); + } + +diff --git a/grub-core/fs/udf.c b/grub-core/fs/udf.c +index 2ac5c1d00..3d4b40263 100644 +--- a/grub-core/fs/udf.c ++++ b/grub-core/fs/udf.c +@@ -1382,6 +1382,7 @@ static struct grub_fs grub_udf_fs = { + + GRUB_MOD_INIT (udf) + { ++ grub_udf_fs.mod = mod; + grub_fs_register (&grub_udf_fs); + my_mod = mod; + } +diff --git a/grub-core/fs/ufs.c b/grub-core/fs/ufs.c +index 47272665e..7f72494cd 100644 +--- a/grub-core/fs/ufs.c ++++ b/grub-core/fs/ufs.c +@@ -899,6 +899,7 @@ GRUB_MOD_INIT(ufs1) + #endif + #endif + { ++ grub_ufs_fs.mod = mod; + grub_fs_register (&grub_ufs_fs); + my_mod = mod; + } +diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c +index 9d3420ece..7b0ea577e 100644 +--- a/grub-core/fs/xfs.c ++++ b/grub-core/fs/xfs.c +@@ -1220,6 +1220,7 @@ static struct grub_fs grub_xfs_fs = + + GRUB_MOD_INIT(xfs) + { ++ grub_xfs_fs.mod = mod; + grub_fs_register (&grub_xfs_fs); + my_mod = mod; + } +diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c +index cf4d2ab18..cbbd86730 100644 +--- a/grub-core/fs/zfs/zfs.c ++++ b/grub-core/fs/zfs/zfs.c +@@ -4394,6 +4394,7 @@ static struct grub_fs grub_zfs_fs = { + GRUB_MOD_INIT (zfs) + { + COMPILE_TIME_ASSERT (sizeof (zap_leaf_chunk_t) == ZAP_LEAF_CHUNKSIZE); ++ grub_zfs_fs.mod = mod; + grub_fs_register (&grub_zfs_fs); + #ifndef GRUB_UTIL + my_mod = mod; +diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c +index 1dc4339dc..58fae17ba 100644 +--- a/grub-core/kern/file.c ++++ b/grub-core/kern/file.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + + void (*EXPORT_VAR (grub_grubnet_fini)) (void); + +@@ -127,6 +128,9 @@ grub_file_open (const char *name, enum grub_file_type type) + if (file->data == NULL) + goto fail; + ++ if (file->fs->mod) ++ grub_dl_ref (file->fs->mod); ++ + file->name = grub_strdup (name); + grub_errno = GRUB_ERR_NONE; + +@@ -215,6 +219,9 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len) + grub_err_t + grub_file_close (grub_file_t file) + { ++ if (file->fs->mod) ++ grub_dl_unref (file->fs->mod); ++ + grub_dprintf ("file", "Closing `%s' ...\n", file->name); + if (file->fs->fs_close) + (file->fs->fs_close) (file); +diff --git a/include/grub/fs.h b/include/grub/fs.h +index 026bc3bb8..df4c93b16 100644 +--- a/include/grub/fs.h ++++ b/include/grub/fs.h +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + #include + /* For embedding types. */ +@@ -57,6 +58,9 @@ struct grub_fs + /* My name. */ + const char *name; + ++ /* My module */ ++ grub_dl_t mod; ++ + /* Call HOOK with each file under DIR. */ + grub_err_t (*fs_dir) (grub_device_t device, const char *path, + grub_fs_dir_hook_t hook, void *hook_data); diff --git a/0377-cli_lock-Add-build-option-to-block-command-line-inte.patch b/0377-cli_lock-Add-build-option-to-block-command-line-inte.patch new file mode 100644 index 0000000..6c8a451 --- /dev/null +++ b/0377-cli_lock-Add-build-option-to-block-command-line-inte.patch @@ -0,0 +1,367 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Alec Brown +Date: Wed, 24 Jan 2024 06:26:37 +0000 +Subject: [PATCH] cli_lock: Add build option to block command line interface + +Add functionality to disable command line interface access and editing of GRUB +menu entries if GRUB image is built with --disable-cli. + +Signed-off-by: Alec Brown +Reviewed-by: Vladimir Serbinenko +Reviewed-by: Daniel Kiper +--- + docs/grub.texi | 6 ++++-- + grub-core/kern/main.c | 28 ++++++++++++++++++++++++++++ + grub-core/kern/rescue_reader.c | 13 +++++++++++++ + grub-core/normal/auth.c | 3 +++ + grub-core/normal/menu_text.c | 31 +++++++++++++++++-------------- + include/grub/kernel.h | 1 + + include/grub/misc.h | 2 ++ + include/grub/util/install.h | 8 ++++++-- + util/grub-install-common.c | 11 ++++++++--- + util/grub-mkimage.c | 9 ++++++++- + util/mkimage.c | 15 ++++++++++++++- + 11 files changed, 104 insertions(+), 23 deletions(-) + +diff --git a/docs/grub.texi b/docs/grub.texi +index 825278a7f..b39cdf275 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -5948,8 +5948,10 @@ the GRUB command line, edit menu entries, and execute any menu entry. If + @samp{superusers} is set, then use of the command line and editing of menu + entries are automatically restricted to superusers. Setting @samp{superusers} + to empty string effectively disables both access to CLI and editing of menu +-entries. Note: The environment variable needs to be exported to also affect +-the section defined by the @samp{submenu} command (@pxref{submenu}). ++entries. Building a grub image with @samp{--disable-cli} option will also ++disable access to CLI and editing of menu entries, as well as disabling rescue ++mode. Note: The environment variable needs to be exported to also affect the ++section defined by the @samp{submenu} command (@pxref{submenu}). + + Other users may be allowed to execute specific menu entries by giving a list of + usernames (as above) using the @option{--users} option to the +diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c +index e94a2f78f..e4d4bf625 100644 +--- a/grub-core/kern/main.c ++++ b/grub-core/kern/main.c +@@ -30,11 +30,14 @@ + #include + #include + #include ++#include + + #ifdef GRUB_MACHINE_PCBIOS + #include + #endif + ++static bool cli_disabled = false; ++ + grub_addr_t + grub_modules_get_end (void) + { +@@ -299,6 +302,28 @@ grub_load_normal_mode (void) + grub_command_execute ("normal", 0, 0); + } + ++bool ++grub_is_cli_disabled (void) ++{ ++ return cli_disabled; ++} ++ ++static void ++check_is_cli_disabled (void) ++{ ++ struct grub_module_header *header; ++ header = 0; ++ ++ FOR_MODULES (header) ++ { ++ if (header->type == OBJ_TYPE_DISABLE_CLI) ++ { ++ cli_disabled = true; ++ return; ++ } ++ } ++} ++ + static void + reclaim_module_space (void) + { +@@ -356,6 +381,9 @@ grub_main (void) + + grub_boot_time ("After loading embedded modules."); + ++ /* Check if the CLI should be disabled */ ++ check_is_cli_disabled (); ++ + /* It is better to set the root device as soon as possible, + for convenience. */ + grub_set_prefix_and_root (); +diff --git a/grub-core/kern/rescue_reader.c b/grub-core/kern/rescue_reader.c +index dcd7d4439..4259857ba 100644 +--- a/grub-core/kern/rescue_reader.c ++++ b/grub-core/kern/rescue_reader.c +@@ -78,6 +78,19 @@ grub_rescue_read_line (char **line, int cont, + void __attribute__ ((noreturn)) + grub_rescue_run (void) + { ++ /* Stall if the CLI has been disabled */ ++ if (grub_is_cli_disabled ()) ++ { ++ grub_printf ("Rescue mode has been disabled...\n"); ++ ++ do ++ { ++ /* Do not optimize out the loop. */ ++ asm volatile (""); ++ } ++ while (1); ++ } ++ + grub_printf ("Entering rescue mode...\n"); + + while (1) +diff --git a/grub-core/normal/auth.c b/grub-core/normal/auth.c +index 6be678c0d..53f2d723f 100644 +--- a/grub-core/normal/auth.c ++++ b/grub-core/normal/auth.c +@@ -209,6 +209,9 @@ grub_auth_check_authentication (const char *userlist) + char entered[GRUB_AUTH_MAX_PASSLEN]; + struct grub_auth_user *user; + ++ if (grub_is_cli_disabled ()) ++ return GRUB_ACCESS_DENIED; ++ + grub_memset (login, 0, sizeof (login)); + + if (is_authenticated (userlist)) +diff --git a/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c +index 18240e76c..fd0d83999 100644 +--- a/grub-core/normal/menu_text.c ++++ b/grub-core/normal/menu_text.c +@@ -178,21 +178,24 @@ command-line or ESC to discard edits and return to the GRUB menu."), + + grub_free (msg_translated); + +- if (nested) ++ if (!grub_is_cli_disabled ()) + { +- ret += grub_print_message_indented_real +- (_("Press enter to boot the selected OS, " +- "`e' to edit the commands before booting " +- "or `c' for a command-line. ESC to return previous menu."), +- STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run); +- } +- else +- { +- ret += grub_print_message_indented_real +- (_("Press enter to boot the selected OS, " +- "`e' to edit the commands before booting " +- "or `c' for a command-line."), +- STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run); ++ if (nested) ++ { ++ ret += grub_print_message_indented_real ++ (_("Press enter to boot the selected OS, " ++ "`e' to edit the commands before booting " ++ "or `c' for a command-line. ESC to return previous menu."), ++ STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run); ++ } ++ else ++ { ++ ret += grub_print_message_indented_real ++ (_("Press enter to boot the selected OS, " ++ "`e' to edit the commands before booting " ++ "or `c' for a command-line."), ++ STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run); ++ } + } + } + return ret; +diff --git a/include/grub/kernel.h b/include/grub/kernel.h +index 98edc0863..f98a780da 100644 +--- a/include/grub/kernel.h ++++ b/include/grub/kernel.h +@@ -33,6 +33,7 @@ enum + OBJ_TYPE_DISABLE_SHIM_LOCK, + OBJ_TYPE_GPG_PUBKEY, + OBJ_TYPE_X509_PUBKEY, ++ OBJ_TYPE_DISABLE_CLI + }; + + /* The module header. */ +diff --git a/include/grub/misc.h b/include/grub/misc.h +index 0592aa68f..8c0ffed16 100644 +--- a/include/grub/misc.h ++++ b/include/grub/misc.h +@@ -409,6 +409,8 @@ grub_uint64_t EXPORT_FUNC(grub_divmod64) (grub_uint64_t n, + grub_uint64_t d, + grub_uint64_t *r); + ++extern bool EXPORT_FUNC(grub_is_cli_disabled) (void); ++ + /* Must match softdiv group in gentpl.py. */ + #if !defined(GRUB_MACHINE_EMU) && (defined(__arm__) || defined(__ia64__) || \ + (defined(__riscv) && (__riscv_xlen == 32))) +diff --git a/include/grub/util/install.h b/include/grub/util/install.h +index 51f3b13ac..b9627182a 100644 +--- a/include/grub/util/install.h ++++ b/include/grub/util/install.h +@@ -72,6 +72,8 @@ + { "appended-signature-size", GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,\ + "SIZE", 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), \ + 1}, \ ++ { "disable-cli", GRUB_INSTALL_OPTIONS_DISABLE_CLI, 0, 0, \ ++ N_("disabled command line interface access"), 0 }, \ + { "verbose", 'v', 0, 0, \ + N_("print verbose messages."), 1 } + +@@ -134,7 +136,8 @@ enum grub_install_options { + GRUB_INSTALL_OPTIONS_DTB, + GRUB_INSTALL_OPTIONS_SBAT, + GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, +- GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE ++ GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE, ++ GRUB_INSTALL_OPTIONS_DISABLE_CLI + }; + + extern char *grub_install_source_directory; +@@ -197,7 +200,8 @@ grub_install_generate_image (const char *dir, const char *prefix, + const struct grub_install_image_target_desc *image_target, + int note, size_t appsig_size, + grub_compression_t comp, const char *dtb_file, +- const char *sbat_path, const int disable_shim_lock); ++ const char *sbat_path, const int disable_shim_lock, ++ const int disable_cli); + + const struct grub_install_image_target_desc * + grub_install_get_image_target (const char *arg); +diff --git a/util/grub-install-common.c b/util/grub-install-common.c +index c603f5b30..221b889c8 100644 +--- a/util/grub-install-common.c ++++ b/util/grub-install-common.c +@@ -464,6 +464,7 @@ static char **x509keys; + static size_t nx509keys; + static grub_compression_t compression; + static size_t appsig_size; ++static int disable_cli; + + int + grub_install_parse (int key, char *arg) +@@ -509,6 +510,9 @@ grub_install_parse (int key, char *arg) + * (nx509keys + 1)); + x509keys[nx509keys++] = xstrdup (arg); + return 1; ++ case GRUB_INSTALL_OPTIONS_DISABLE_CLI: ++ disable_cli = 1; ++ return 1; + + case GRUB_INSTALL_OPTIONS_VERBOSITY: + verbosity++; +@@ -689,12 +693,13 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, + " --dtb '%s' " + "--sbat '%s' " + "--format '%s' --compression '%s' " +- "--appended-signature-size %zu %s %s %s\n", ++ "--appended-signature-size %zu %s %s %s %s\n", + dir, prefix, + outname, dtb ? : "", sbat ? : "", mkimage_target, + compnames[compression], appsig_size, + disable_shim_lock ? "--disable-shim-lock" : "", +- note ? "--note" : "", s); ++ note ? "--note" : "", ++ disable_cli ? " --disable-cli" : "", s); + free (s); + + tgt = grub_install_get_image_target (mkimage_target); +@@ -707,7 +712,7 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, + x509keys, nx509keys, + config_path, tgt, + note, appsig_size, compression, dtb, sbat, +- disable_shim_lock); ++ disable_shim_lock, disable_cli); + while (dc--) + grub_install_pop_module (); + } +diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c +index e1f111278..13bdc6cf0 100644 +--- a/util/grub-mkimage.c ++++ b/util/grub-mkimage.c +@@ -84,6 +84,7 @@ static struct argp_option options[] = { + {"compression", 'C', "(xz|none|auto)", 0, N_("choose the compression to use for core image"), 0}, + {"sbat", 's', N_("FILE"), 0, N_("SBAT metadata"), 0}, + {"disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, N_("disable shim_lock verifier"), 0}, ++ {"disable-cli", GRUB_INSTALL_OPTIONS_DISABLE_CLI, 0, 0, N_("disable command line interface access"), 0}, + {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, + {"appended-signature-size", 'S', N_("SIZE"), 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), 0}, + { 0, 0, 0, 0, 0, 0 } +@@ -133,6 +134,7 @@ struct arguments + int note; + int disable_shim_lock; + size_t appsig_size; ++ int disable_cli; + const struct grub_install_image_target_desc *image_target; + grub_compression_t comp; + }; +@@ -259,6 +261,10 @@ argp_parser (int key, char *arg, struct argp_state *state) + arguments->disable_shim_lock = 1; + break; + ++ case GRUB_INSTALL_OPTIONS_DISABLE_CLI: ++ arguments->disable_cli = 1; ++ break; ++ + case 'v': + verbosity++; + break; +@@ -347,7 +353,8 @@ main (int argc, char *argv[]) + arguments.image_target, arguments.note, + arguments.appsig_size, arguments.comp, + arguments.dtb, arguments.sbat, +- arguments.disable_shim_lock); ++ arguments.disable_shim_lock, ++ arguments.disable_cli); + + if (grub_util_file_sync (fp) < 0) + grub_util_error (_("cannot sync `%s': %s"), arguments.output ? : "stdout", +diff --git a/util/mkimage.c b/util/mkimage.c +index c3d33aaac..9ba1a8988 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -872,7 +872,7 @@ grub_install_generate_image (const char *dir, const char *prefix, + const struct grub_install_image_target_desc *image_target, + int note, size_t appsig_size, grub_compression_t comp, + const char *dtb_path, const char *sbat_path, +- int disable_shim_lock) ++ int disable_shim_lock, int disable_cli) + { + char *kernel_img, *core_img; + size_t total_module_size, core_size; +@@ -947,6 +947,9 @@ grub_install_generate_image (const char *dir, const char *prefix, + if (disable_shim_lock) + total_module_size += sizeof (struct grub_module_header); + ++ if (disable_cli) ++ total_module_size += sizeof (struct grub_module_header); ++ + if (config_path) + { + config_size = ALIGN_ADDR (grub_util_get_image_size (config_path) + 1); +@@ -1113,6 +1116,16 @@ grub_install_generate_image (const char *dir, const char *prefix, + offset += sizeof (*header); + } + ++ if (disable_cli) ++ { ++ struct grub_module_header *header; ++ ++ header = (struct grub_module_header *) (kernel_img + offset); ++ header->type = grub_host_to_target32 (OBJ_TYPE_DISABLE_CLI); ++ header->size = grub_host_to_target32 (sizeof (*header)); ++ offset += sizeof (*header); ++ } ++ + if (config_path) + { + struct grub_module_header *header; diff --git a/0378-cryptodisk-Refactor-to-discard-have_it-global.patch b/0378-cryptodisk-Refactor-to-discard-have_it-global.patch new file mode 100644 index 0000000..bb1f8de --- /dev/null +++ b/0378-cryptodisk-Refactor-to-discard-have_it-global.patch @@ -0,0 +1,184 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Thu, 9 Dec 2021 11:14:51 -0600 +Subject: [PATCH] cryptodisk: Refactor to discard have_it global + +The global "have_it" was never used by the crypto-backends, but was used to +determine if a crypto-backend successfully mounted a cryptodisk with a given +UUID. This is not needed however, because grub_device_iterate() will return +1 if and only if grub_cryptodisk_scan_device() returns 1. And +grub_cryptodisk_scan_device() will now only return 1 if a search_uuid has +been specified and a cryptodisk was successfully setup by a crypto-backend or +a cryptodisk of the requested UUID is already open. + +To implement this grub_cryptodisk_scan_device_real() is modified to return +a cryptodisk or NULL on failure and having the appropriate grub_errno set to +indicated failure. Note that grub_cryptodisk_scan_device_real() will fail now +with a new errno GRUB_ERR_BAD_MODULE when none of the cryptodisk backend +modules succeed in identifying the source disk. + +With this change grub_device_iterate() will return 1 when a crypto device is +successfully decrypted or when the source device has already been successfully +opened. Prior to this change, trying to mount an already successfully opened +device would trigger an error with the message "no such cryptodisk found", +which is at best misleading. The mount should silently succeed in this case, +which is what happens with this patch. + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 56 ++++++++++++++++++++++++++++----------------- + 1 file changed, 35 insertions(+), 21 deletions(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 90f82b2..9df3d31 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -983,7 +983,7 @@ grub_util_cryptodisk_get_uuid (grub_disk_t disk) + + #endif + +-static int check_boot, have_it; ++static int check_boot; + static char *search_uuid; + + static void +@@ -995,7 +995,7 @@ cryptodisk_close (grub_cryptodisk_t dev) + grub_free (dev); + } + +-static grub_err_t ++static grub_cryptodisk_t + grub_cryptodisk_scan_device_real (const char *name, grub_disk_t source) + { + grub_err_t err; +@@ -1005,13 +1005,13 @@ grub_cryptodisk_scan_device_real (const char *name, grub_disk_t source) + dev = grub_cryptodisk_get_by_source_disk (source); + + if (dev) +- return GRUB_ERR_NONE; ++ return dev; + + FOR_CRYPTODISK_DEVS (cr) + { + dev = cr->scan (source, search_uuid, check_boot); + if (grub_errno) +- return grub_errno; ++ return NULL; + if (!dev) + continue; + +@@ -1019,16 +1019,16 @@ grub_cryptodisk_scan_device_real (const char *name, grub_disk_t source) + if (err) + { + cryptodisk_close (dev); +- return err; ++ return NULL; + } + + grub_cryptodisk_insert (dev, name, source); + +- have_it = 1; +- +- return GRUB_ERR_NONE; ++ return dev; + } +- return GRUB_ERR_NONE; ++ ++ grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk module can handle this device"); ++ return NULL; + } + + #ifdef GRUB_UTIL +@@ -1082,8 +1082,10 @@ static int + grub_cryptodisk_scan_device (const char *name, + void *data __attribute__ ((unused))) + { +- grub_err_t err; ++ int ret = 0; + grub_disk_t source; ++ grub_cryptodisk_t dev; ++ grub_errno = GRUB_ERR_NONE; + + /* Try to open disk. */ + source = grub_disk_open (name); +@@ -1093,13 +1095,26 @@ grub_cryptodisk_scan_device (const char *name, + return 0; + } + +- err = grub_cryptodisk_scan_device_real (name, source); ++ dev = grub_cryptodisk_scan_device_real (name, source); ++ if (dev) ++ { ++ ret = (search_uuid != NULL && grub_strcasecmp (search_uuid, dev->uuid) == 0); ++ goto cleanup; ++ } + +- grub_disk_close (source); +- +- if (err) ++ /* ++ * Do not print error when err is GRUB_ERR_BAD_MODULE to avoid many unhelpful ++ * error messages. ++ */ ++ if (grub_errno == GRUB_ERR_BAD_MODULE) ++ grub_error_pop (); ++ ++ if (grub_errno != GRUB_ERR_NONE) + grub_print_error (); +- return have_it && search_uuid ? 1 : 0; ++ ++ cleanup: ++ grub_disk_close (source); ++ return ret; + } + + static grub_err_t +@@ -1110,9 +1125,9 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + if (argc < 1 && !state[1].set && !state[2].set) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); + +- have_it = 0; + if (state[0].set) + { ++ int found_uuid; + grub_cryptodisk_t dev; + + dev = grub_cryptodisk_get_by_uuid (args[0]); +@@ -1125,10 +1140,10 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + + check_boot = state[2].set; + search_uuid = args[0]; +- grub_device_iterate (&grub_cryptodisk_scan_device, NULL); ++ found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, NULL); + search_uuid = NULL; + +- if (!have_it) ++ if (!found_uuid) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such cryptodisk found"); + return GRUB_ERR_NONE; + } +@@ -1142,7 +1157,6 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + } + else + { +- grub_err_t err; + grub_disk_t disk; + grub_cryptodisk_t dev; + char *diskname; +@@ -1178,13 +1192,13 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + return GRUB_ERR_NONE; + } + +- err = grub_cryptodisk_scan_device_real (diskname, disk); ++ dev = grub_cryptodisk_scan_device_real (diskname, disk); + + grub_disk_close (disk); + if (disklast) + *disklast = ')'; + +- return err; ++ return (dev == NULL) ? grub_errno : GRUB_ERR_NONE; + } + } + diff --git a/0379-cryptodisk-Return-failure-in-cryptomount-when-no-cry.patch b/0379-cryptodisk-Return-failure-in-cryptomount-when-no-cry.patch new file mode 100644 index 0000000..62491c7 --- /dev/null +++ b/0379-cryptodisk-Return-failure-in-cryptomount-when-no-cry.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Thu, 9 Dec 2021 11:14:52 -0600 +Subject: [PATCH] cryptodisk: Return failure in cryptomount when no cryptodisk + modules are loaded + +This displays an error notifying the user that they'll want to load +a backend module to make cryptomount useful. + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 9df3d31..2749187 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -1125,6 +1125,9 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + if (argc < 1 && !state[1].set && !state[2].set) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); + ++ if (grub_cryptodisk_list == NULL) ++ return grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk modules loaded"); ++ + if (state[0].set) + { + int found_uuid; diff --git a/0380-cryptodisk-Improve-error-messaging-in-cryptomount-in.patch b/0380-cryptodisk-Improve-error-messaging-in-cryptomount-in.patch new file mode 100644 index 0000000..058a853 --- /dev/null +++ b/0380-cryptodisk-Improve-error-messaging-in-cryptomount-in.patch @@ -0,0 +1,55 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Thu, 9 Dec 2021 11:14:53 -0600 +Subject: [PATCH] cryptodisk: Improve error messaging in cryptomount + invocations + +Update such that "cryptomount -u UUID" will not print two error messages +when an invalid passphrase is given and the most relevant error message +will be displayed. + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 21 +++++++++++++++++---- + 1 file changed, 17 insertions(+), 4 deletions(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 2749187..3a896c6 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -1109,7 +1109,10 @@ grub_cryptodisk_scan_device (const char *name, + if (grub_errno == GRUB_ERR_BAD_MODULE) + grub_error_pop (); + +- if (grub_errno != GRUB_ERR_NONE) ++ if (search_uuid != NULL) ++ /* Push error onto stack to save for cryptomount. */ ++ grub_error_push (); ++ else + grub_print_error (); + + cleanup: +@@ -1146,9 +1149,19 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, NULL); + search_uuid = NULL; + +- if (!found_uuid) +- return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such cryptodisk found"); +- return GRUB_ERR_NONE; ++ if (found_uuid) ++ return GRUB_ERR_NONE; ++ else if (grub_errno == GRUB_ERR_NONE) ++ { ++ /* ++ * Try to pop the next error on the stack. If there is not one, then ++ * no device matched the given UUID. ++ */ ++ grub_error_pop (); ++ if (grub_errno == GRUB_ERR_NONE) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such cryptodisk found"); ++ } ++ return grub_errno; + } + else if (state[1].set || (argc == 0 && state[2].set)) + { diff --git a/0381-cryptodisk-Improve-cryptomount-u-error-message.patch b/0381-cryptodisk-Improve-cryptomount-u-error-message.patch new file mode 100644 index 0000000..add2603 --- /dev/null +++ b/0381-cryptodisk-Improve-cryptomount-u-error-message.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Thu, 9 Dec 2021 11:14:54 -0600 +Subject: [PATCH] cryptodisk: Improve cryptomount -u error message + +When a cryptmount is specified with a UUID, but no cryptodisk backends find +a disk with that UUID, return a more detailed message giving telling the +user that they might not have a needed cryptobackend module loaded. + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 3a896c6..5a9780b 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -1159,7 +1159,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + */ + grub_error_pop (); + if (grub_errno == GRUB_ERR_NONE) +- return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such cryptodisk found"); ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such cryptodisk found, perhaps a needed disk or cryptodisk module is not loaded"); + } + return grub_errno; + } diff --git a/0382-cryptodisk-Add-infrastructure-to-pass-data-from-cryp.patch b/0382-cryptodisk-Add-infrastructure-to-pass-data-from-cryp.patch new file mode 100644 index 0000000..add5bb1 --- /dev/null +++ b/0382-cryptodisk-Add-infrastructure-to-pass-data-from-cryp.patch @@ -0,0 +1,249 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Thu, 9 Dec 2021 11:14:55 -0600 +Subject: [PATCH] cryptodisk: Add infrastructure to pass data from cryptomount + to cryptodisk modules + +Previously, the cryptomount arguments were passed by global variable and +function call argument, neither of which are ideal. This change passes data +via a grub_cryptomount_args struct, which can be added to over time as +opposed to continually adding arguments to the cryptodisk scan and +recover_key. + +As an example, passing a password as a cryptomount argument is implemented. +However, the backends are not implemented, so testing this will return a not +implemented error. + +Also, add comments to cryptomount argument parsing to make it more obvious +which argument states are being handled. + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 31 +++++++++++++++++++++---------- + grub-core/disk/geli.c | 6 +++++- + grub-core/disk/luks.c | 7 ++++++- + grub-core/disk/luks2.c | 7 ++++++- + include/grub/cryptodisk.h | 9 ++++++++- + 5 files changed, 46 insertions(+), 14 deletions(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 5a9780b..14c661a 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -41,6 +41,7 @@ static const struct grub_arg_option options[] = + /* TRANSLATORS: It's still restricted to cryptodisks only. */ + {"all", 'a', 0, N_("Mount all."), 0, 0}, + {"boot", 'b', 0, N_("Mount all volumes with `boot' flag set."), 0, 0}, ++ {"password", 'p', 0, N_("Password to open volumes."), 0, ARG_TYPE_STRING}, + {0, 0, 0, 0, 0, 0} + }; + +@@ -996,7 +997,9 @@ cryptodisk_close (grub_cryptodisk_t dev) + } + + static grub_cryptodisk_t +-grub_cryptodisk_scan_device_real (const char *name, grub_disk_t source) ++grub_cryptodisk_scan_device_real (const char *name, ++ grub_disk_t source, ++ grub_cryptomount_args_t cargs) + { + grub_err_t err; + grub_cryptodisk_t dev; +@@ -1015,7 +1018,7 @@ grub_cryptodisk_scan_device_real (const char *name, grub_disk_t source) + if (!dev) + continue; + +- err = cr->recover_key (source, dev); ++ err = cr->recover_key (source, dev, cargs); + if (err) + { + cryptodisk_close (dev); +@@ -1080,11 +1083,12 @@ grub_cryptodisk_cheat_mount (const char *sourcedev, const char *cheat) + + static int + grub_cryptodisk_scan_device (const char *name, +- void *data __attribute__ ((unused))) ++ void *data) + { + int ret = 0; + grub_disk_t source; + grub_cryptodisk_t dev; ++ grub_cryptomount_args_t cargs = data; + grub_errno = GRUB_ERR_NONE; + + /* Try to open disk. */ +@@ -1095,7 +1099,7 @@ grub_cryptodisk_scan_device (const char *name, + return 0; + } + +- dev = grub_cryptodisk_scan_device_real (name, source); ++ dev = grub_cryptodisk_scan_device_real (name, source, cargs); + if (dev) + { + ret = (search_uuid != NULL && grub_strcasecmp (search_uuid, dev->uuid) == 0); +@@ -1124,6 +1128,7 @@ static grub_err_t + grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + { + struct grub_arg_list *state = ctxt->state; ++ struct grub_cryptomount_args cargs = {0}; + + if (argc < 1 && !state[1].set && !state[2].set) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); +@@ -1131,7 +1136,13 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + if (grub_cryptodisk_list == NULL) + return grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk modules loaded"); + +- if (state[0].set) ++ if (state[3].set) /* password */ ++ { ++ cargs.key_data = (grub_uint8_t *) state[3].arg; ++ cargs.key_len = grub_strlen (state[3].arg); ++ } ++ ++ if (state[0].set) /* uuid */ + { + int found_uuid; + grub_cryptodisk_t dev; +@@ -1146,7 +1157,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + + check_boot = state[2].set; + search_uuid = args[0]; +- found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, NULL); ++ found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, &cargs); + search_uuid = NULL; + + if (found_uuid) +@@ -1163,11 +1174,11 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + } + return grub_errno; + } +- else if (state[1].set || (argc == 0 && state[2].set)) ++ else if (state[1].set || (argc == 0 && state[2].set)) /* -a|-b */ + { + search_uuid = NULL; + check_boot = state[2].set; +- grub_device_iterate (&grub_cryptodisk_scan_device, NULL); ++ grub_device_iterate (&grub_cryptodisk_scan_device, &cargs); + search_uuid = NULL; + return GRUB_ERR_NONE; + } +@@ -1208,7 +1219,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + return GRUB_ERR_NONE; + } + +- dev = grub_cryptodisk_scan_device_real (diskname, disk); ++ dev = grub_cryptodisk_scan_device_real (diskname, disk, &cargs); + + grub_disk_close (disk); + if (disklast) +@@ -1347,7 +1358,7 @@ GRUB_MOD_INIT (cryptodisk) + { + grub_disk_dev_register (&grub_cryptodisk_dev); + cmd = grub_register_extcmd ("cryptomount", grub_cmd_cryptomount, 0, +- N_("SOURCE|-u UUID|-a|-b"), ++ N_("[-p password] "), + N_("Mount a crypto device."), options); + grub_procfs_register ("luks_script", &luks_script); + } +diff --git a/grub-core/disk/geli.c b/grub-core/disk/geli.c +index 2f34a35..777da3a 100644 +--- a/grub-core/disk/geli.c ++++ b/grub-core/disk/geli.c +@@ -398,7 +398,7 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid, + } + + static grub_err_t +-recover_key (grub_disk_t source, grub_cryptodisk_t dev) ++recover_key (grub_disk_t source, grub_cryptodisk_t dev, grub_cryptomount_args_t cargs) + { + grub_size_t keysize; + grub_uint8_t digest[GRUB_CRYPTO_MAX_MDLEN]; +@@ -414,6 +414,10 @@ recover_key (grub_disk_t source, grub_cryptodisk_t dev) + grub_disk_addr_t sector; + grub_err_t err; + ++ /* Keyfiles are not implemented yet */ ++ if (cargs->key_data != NULL || cargs->key_len) ++ return GRUB_ERR_NOT_IMPLEMENTED_YET; ++ + if (dev->cipher->cipher->blocksize > GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE) + return grub_error (GRUB_ERR_BUG, "cipher block is too long"); + +diff --git a/grub-core/disk/luks.c b/grub-core/disk/luks.c +index 13103ea..c5858fc 100644 +--- a/grub-core/disk/luks.c ++++ b/grub-core/disk/luks.c +@@ -152,7 +152,8 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid, + + static grub_err_t + luks_recover_key (grub_disk_t source, +- grub_cryptodisk_t dev) ++ grub_cryptodisk_t dev, ++ grub_cryptomount_args_t cargs) + { + struct grub_luks_phdr header; + grub_size_t keysize; +@@ -165,6 +166,10 @@ luks_recover_key (grub_disk_t source, + grub_size_t max_stripes = 1; + char *tmp; + ++ /* Keyfiles are not implemented yet */ ++ if (cargs->key_data != NULL || cargs->key_len) ++ return GRUB_ERR_NOT_IMPLEMENTED_YET; ++ + err = grub_disk_read (source, 0, 0, sizeof (header), &header); + if (err) + return err; +diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c +index c917a5f..8a9f42d 100644 +--- a/grub-core/disk/luks2.c ++++ b/grub-core/disk/luks2.c +@@ -542,7 +542,8 @@ luks2_decrypt_key (grub_uint8_t *out_key, + + static grub_err_t + luks2_recover_key (grub_disk_t source, +- grub_cryptodisk_t crypt) ++ grub_cryptodisk_t crypt, ++ grub_cryptomount_args_t cargs) + { + grub_uint8_t candidate_key[GRUB_CRYPTODISK_MAX_KEYLEN]; + char passphrase[MAX_PASSPHRASE], cipher[32]; +@@ -556,6 +557,10 @@ luks2_recover_key (grub_disk_t source, + grub_json_t *json = NULL, keyslots; + grub_err_t ret; + ++ /* Keyfiles are not implemented yet */ ++ if (cargs->key_data != NULL || cargs->key_len) ++ return GRUB_ERR_NOT_IMPLEMENTED_YET; ++ + ret = luks2_read_header (source, &header); + if (ret) + return ret; +diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h +index dcf17fb..282f8ac 100644 +--- a/include/grub/cryptodisk.h ++++ b/include/grub/cryptodisk.h +@@ -66,6 +66,13 @@ typedef gcry_err_code_t + (*grub_cryptodisk_rekey_func_t) (struct grub_cryptodisk *dev, + grub_uint64_t zoneno); + ++struct grub_cryptomount_args ++{ ++ grub_uint8_t *key_data; ++ grub_size_t key_len; ++}; ++typedef struct grub_cryptomount_args *grub_cryptomount_args_t; ++ + struct grub_cryptodisk + { + struct grub_cryptodisk *next; +@@ -119,7 +126,7 @@ struct grub_cryptodisk_dev + + grub_cryptodisk_t (*scan) (grub_disk_t disk, const char *check_uuid, + int boot_only); +- grub_err_t (*recover_key) (grub_disk_t disk, grub_cryptodisk_t dev); ++ grub_err_t (*recover_key) (grub_disk_t disk, grub_cryptodisk_t dev, grub_cryptomount_args_t cargs); + }; + typedef struct grub_cryptodisk_dev *grub_cryptodisk_dev_t; + diff --git a/0383-cryptodisk-Refactor-password-input-out-of-crypto-dev.patch b/0383-cryptodisk-Refactor-password-input-out-of-crypto-dev.patch new file mode 100644 index 0000000..47b0a2b --- /dev/null +++ b/0383-cryptodisk-Refactor-password-input-out-of-crypto-dev.patch @@ -0,0 +1,339 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Thu, 9 Dec 2021 11:14:56 -0600 +Subject: [PATCH] cryptodisk: Refactor password input out of crypto dev modules + into cryptodisk + +The crypto device modules should only be setting up the crypto devices and +not getting user input. This has the added benefit of simplifying the code +such that three essentially duplicate pieces of code are merged into one. + +Add documentation of passphrase option for cryptomount as it is now usable. + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + docs/grub.texi | 8 ++++--- + grub-core/disk/cryptodisk.c | 56 ++++++++++++++++++++++++++++++++++++--------- + grub-core/disk/geli.c | 26 ++++----------------- + grub-core/disk/luks.c | 27 ++++------------------ + grub-core/disk/luks2.c | 25 ++++---------------- + include/grub/cryptodisk.h | 1 + + 6 files changed, 64 insertions(+), 79 deletions(-) + +diff --git a/docs/grub.texi b/docs/grub.texi +index b39cdf2..3c7d99e 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -4329,9 +4329,11 @@ Alias for @code{hashsum --hash crc32 arg @dots{}}. See command @command{hashsum} + @node cryptomount + @subsection cryptomount + +-@deffn Command cryptomount device|@option{-u} uuid|@option{-a}|@option{-b} +-Setup access to encrypted device. If necessary, passphrase +-is requested interactively. Option @var{device} configures specific grub device ++@deffn Command cryptomount [@option{-p} password] device|@option{-u} uuid|@option{-a}|@option{-b} ++Setup access to encrypted device. If @option{-p} is not given, a passphrase ++is requested interactively. Otherwise, the given @var{password} will be used and ++no passphrase will be requested interactively. ++Option @var{device} configures specific grub device + (@pxref{Naming convention}); option @option{-u} @var{uuid} configures device + with specified @var{uuid}; option @option{-a} configures all detected encrypted + devices; option @option{-b} configures all geli containers that have boot flag set. +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 14c661a..d12368a 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -1001,9 +1001,11 @@ grub_cryptodisk_scan_device_real (const char *name, + grub_disk_t source, + grub_cryptomount_args_t cargs) + { +- grub_err_t err; ++ grub_err_t ret = GRUB_ERR_NONE; + grub_cryptodisk_t dev; + grub_cryptodisk_dev_t cr; ++ int askpass = 0; ++ char *part = NULL; + + dev = grub_cryptodisk_get_by_source_disk (source); + +@@ -1017,21 +1019,53 @@ grub_cryptodisk_scan_device_real (const char *name, + return NULL; + if (!dev) + continue; +- +- err = cr->recover_key (source, dev, cargs); +- if (err) +- { +- cryptodisk_close (dev); +- return NULL; +- } ++ ++ if (!cargs->key_len) ++ { ++ /* Get the passphrase from the user, if no key data. */ ++ askpass = 1; ++ if (source->partition != NULL) ++ part = grub_partition_get_name (source->partition); ++ grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name, ++ source->partition != NULL ? "," : "", ++ part != NULL ? part : "", ++ dev->uuid); ++ grub_free (part); ++ ++ cargs->key_data = grub_malloc (GRUB_CRYPTODISK_MAX_PASSPHRASE); ++ if (cargs->key_data == NULL) ++ return NULL; ++ ++ if (!grub_password_get ((char *) cargs->key_data, GRUB_CRYPTODISK_MAX_PASSPHRASE)) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "passphrase not supplied"); ++ goto error; ++ } ++ cargs->key_len = grub_strlen ((char *) cargs->key_data); ++ } ++ ++ ret = cr->recover_key (source, dev, cargs); ++ if (ret != GRUB_ERR_NONE) ++ goto error; + + grub_cryptodisk_insert (dev, name, source); + +- return dev; ++ goto cleanup; + } +- + grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk module can handle this device"); +- return NULL; ++ goto cleanup; ++ ++ error: ++ cryptodisk_close (dev); ++ dev = NULL; ++ ++ cleanup: ++ if (askpass) ++ { ++ cargs->key_len = 0; ++ grub_free (cargs->key_data); ++ } ++ return dev; + } + + #ifdef GRUB_UTIL +diff --git a/grub-core/disk/geli.c b/grub-core/disk/geli.c +index 777da3a..7299a47 100644 +--- a/grub-core/disk/geli.c ++++ b/grub-core/disk/geli.c +@@ -135,8 +135,6 @@ const char *algorithms[] = { + [0x16] = "aes" + }; + +-#define MAX_PASSPHRASE 256 +- + static gcry_err_code_t + geli_rekey (struct grub_cryptodisk *dev, grub_uint64_t zoneno) + { +@@ -406,17 +404,14 @@ recover_key (grub_disk_t source, grub_cryptodisk_t dev, grub_cryptomount_args_t + grub_uint8_t verify_key[GRUB_CRYPTO_MAX_MDLEN]; + grub_uint8_t zero[GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE]; + grub_uint8_t geli_cipher_key[64]; +- char passphrase[MAX_PASSPHRASE] = ""; + unsigned i; + gcry_err_code_t gcry_err; + struct grub_geli_phdr header; +- char *tmp; + grub_disk_addr_t sector; + grub_err_t err; + +- /* Keyfiles are not implemented yet */ +- if (cargs->key_data != NULL || cargs->key_len) +- return GRUB_ERR_NOT_IMPLEMENTED_YET; ++ if (cargs->key_data == NULL || cargs->key_len == 0) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no key data"); + + if (dev->cipher->cipher->blocksize > GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE) + return grub_error (GRUB_ERR_BUG, "cipher block is too long"); +@@ -438,23 +433,12 @@ recover_key (grub_disk_t source, grub_cryptodisk_t dev, grub_cryptomount_args_t + + grub_puts_ (N_("Attempting to decrypt master key...")); + +- /* Get the passphrase from the user. */ +- tmp = NULL; +- if (source->partition) +- tmp = grub_partition_get_name (source->partition); +- grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name, +- source->partition ? "," : "", tmp ? : "", +- dev->uuid); +- grub_free (tmp); +- if (!grub_password_get (passphrase, MAX_PASSPHRASE)) +- return grub_error (GRUB_ERR_BAD_ARGUMENT, "Passphrase not supplied"); +- + /* Calculate the PBKDF2 of the user supplied passphrase. */ + if (grub_le_to_cpu32 (header.niter) != 0) + { + grub_uint8_t pbkdf_key[64]; +- gcry_err = grub_crypto_pbkdf2 (dev->hash, (grub_uint8_t *) passphrase, +- grub_strlen (passphrase), ++ gcry_err = grub_crypto_pbkdf2 (dev->hash, cargs->key_data, ++ cargs->key_len, + header.salt, + sizeof (header.salt), + grub_le_to_cpu32 (header.niter), +@@ -477,7 +461,7 @@ recover_key (grub_disk_t source, grub_cryptodisk_t dev, grub_cryptomount_args_t + return grub_crypto_gcry_error (GPG_ERR_OUT_OF_MEMORY); + + grub_crypto_hmac_write (hnd, header.salt, sizeof (header.salt)); +- grub_crypto_hmac_write (hnd, passphrase, grub_strlen (passphrase)); ++ grub_crypto_hmac_write (hnd, cargs->key_data, cargs->key_len); + + gcry_err = grub_crypto_hmac_fini (hnd, geomkey); + if (gcry_err) +diff --git a/grub-core/disk/luks.c b/grub-core/disk/luks.c +index c5858fc..39a7af6 100644 +--- a/grub-core/disk/luks.c ++++ b/grub-core/disk/luks.c +@@ -29,8 +29,6 @@ + + GRUB_MOD_LICENSE ("GPLv3+"); + +-#define MAX_PASSPHRASE 256 +- + #define LUKS_KEY_ENABLED 0x00AC71F3 + + /* On disk LUKS header */ +@@ -158,17 +156,14 @@ luks_recover_key (grub_disk_t source, + struct grub_luks_phdr header; + grub_size_t keysize; + grub_uint8_t *split_key = NULL; +- char passphrase[MAX_PASSPHRASE] = ""; + grub_uint8_t candidate_digest[sizeof (header.mkDigest)]; + unsigned i; + grub_size_t length; + grub_err_t err; + grub_size_t max_stripes = 1; +- char *tmp; + +- /* Keyfiles are not implemented yet */ +- if (cargs->key_data != NULL || cargs->key_len) +- return GRUB_ERR_NOT_IMPLEMENTED_YET; ++ if (cargs->key_data == NULL || cargs->key_len == 0) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no key data"); + + err = grub_disk_read (source, 0, 0, sizeof (header), &header); + if (err) +@@ -188,20 +183,6 @@ luks_recover_key (grub_disk_t source, + if (!split_key) + return grub_errno; + +- /* Get the passphrase from the user. */ +- tmp = NULL; +- if (source->partition) +- tmp = grub_partition_get_name (source->partition); +- grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name, +- source->partition ? "," : "", tmp ? : "", +- dev->uuid); +- grub_free (tmp); +- if (!grub_password_get (passphrase, MAX_PASSPHRASE)) +- { +- grub_free (split_key); +- return grub_error (GRUB_ERR_BAD_ARGUMENT, "Passphrase not supplied"); +- } +- + /* Try to recover master key from each active keyslot. */ + for (i = 0; i < ARRAY_SIZE (header.keyblock); i++) + { +@@ -216,8 +197,8 @@ luks_recover_key (grub_disk_t source, + grub_dprintf ("luks", "Trying keyslot %d\n", i); + + /* Calculate the PBKDF2 of the user supplied passphrase. */ +- gcry_err = grub_crypto_pbkdf2 (dev->hash, (grub_uint8_t *) passphrase, +- grub_strlen (passphrase), ++ gcry_err = grub_crypto_pbkdf2 (dev->hash, cargs->key_data, ++ cargs->key_len, + header.keyblock[i].passwordSalt, + sizeof (header.keyblock[i].passwordSalt), + grub_be_to_cpu32 (header.keyblock[i]. +diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c +index 8a9f42d..0425100 100644 +--- a/grub-core/disk/luks2.c ++++ b/grub-core/disk/luks2.c +@@ -35,8 +35,6 @@ GRUB_MOD_LICENSE ("GPLv3+"); + #define LUKS_MAGIC_1ST "LUKS\xBA\xBE" + #define LUKS_MAGIC_2ND "SKUL\xBA\xBE" + +-#define MAX_PASSPHRASE 256 +- + enum grub_luks2_kdf_type + { + LUKS2_KDF_TYPE_ARGON2I, +@@ -546,8 +544,7 @@ luks2_recover_key (grub_disk_t source, + grub_cryptomount_args_t cargs) + { + grub_uint8_t candidate_key[GRUB_CRYPTODISK_MAX_KEYLEN]; +- char passphrase[MAX_PASSPHRASE], cipher[32]; +- char *json_header = NULL, *part = NULL, *ptr; ++ char cipher[32], *json_header = NULL, *ptr; + grub_size_t candidate_key_len = 0, json_idx, size; + grub_luks2_header_t header; + grub_luks2_keyslot_t keyslot; +@@ -557,9 +554,8 @@ luks2_recover_key (grub_disk_t source, + grub_json_t *json = NULL, keyslots; + grub_err_t ret; + +- /* Keyfiles are not implemented yet */ +- if (cargs->key_data != NULL || cargs->key_len) +- return GRUB_ERR_NOT_IMPLEMENTED_YET; ++ if (cargs->key_data == NULL || cargs->key_len == 0) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no key data"); + + ret = luks2_read_header (source, &header); + if (ret) +@@ -586,18 +582,6 @@ luks2_recover_key (grub_disk_t source, + goto err; + } + +- /* Get the passphrase from the user. */ +- if (source->partition) +- part = grub_partition_get_name (source->partition); +- grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name, +- source->partition ? "," : "", part ? : "", +- crypt->uuid); +- if (!grub_password_get (passphrase, MAX_PASSPHRASE)) +- { +- ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Passphrase not supplied"); +- goto err; +- } +- + if (grub_json_getvalue (&keyslots, json, "keyslots") || + grub_json_getsize (&size, &keyslots)) + { +@@ -722,7 +706,7 @@ luks2_recover_key (grub_disk_t source, + } + + ret = luks2_decrypt_key (candidate_key, source, crypt, &keyslot, +- (const grub_uint8_t *) passphrase, grub_strlen (passphrase)); ++ cargs->key_data, cargs->key_len); + if (ret) + { + grub_dprintf ("luks2", "Decryption with keyslot \"%" PRIuGRUB_UINT64_T "\" failed: %s\n", +@@ -774,7 +758,6 @@ luks2_recover_key (grub_disk_t source, + } + + err: +- grub_free (part); + grub_free (json_header); + grub_json_free (json); + return ret; +diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h +index 282f8ac..5bd9706 100644 +--- a/include/grub/cryptodisk.h ++++ b/include/grub/cryptodisk.h +@@ -59,6 +59,7 @@ typedef enum + #define GRUB_CRYPTODISK_GF_LOG_BYTES (GRUB_CRYPTODISK_GF_LOG_SIZE - 3) + #define GRUB_CRYPTODISK_GF_BYTES (1U << GRUB_CRYPTODISK_GF_LOG_BYTES) + #define GRUB_CRYPTODISK_MAX_KEYLEN 128 ++#define GRUB_CRYPTODISK_MAX_PASSPHRASE 256 + + struct grub_cryptodisk; + diff --git a/0384-luks2-Add-debug-message-to-align-with-luks-and-geli-.patch b/0384-luks2-Add-debug-message-to-align-with-luks-and-geli-.patch new file mode 100644 index 0000000..cec1e2d --- /dev/null +++ b/0384-luks2-Add-debug-message-to-align-with-luks-and-geli-.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Thu, 9 Dec 2021 11:14:50 -0600 +Subject: [PATCH] luks2: Add debug message to align with luks and geli modules + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + grub-core/disk/luks2.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c +index 0425100..caed4d4 100644 +--- a/grub-core/disk/luks2.c ++++ b/grub-core/disk/luks2.c +@@ -368,7 +368,10 @@ luks2_scan (grub_disk_t disk, const char *check_uuid, int check_boot) + uuid[j] = '\0'; + + if (check_uuid && grub_strcasecmp (check_uuid, uuid) != 0) +- return NULL; ++ { ++ grub_dprintf ("luks2", "%s != %s\n", uuid, check_uuid); ++ return NULL; ++ } + + cryptodisk = grub_zalloc (sizeof (*cryptodisk)); + if (!cryptodisk) diff --git a/0385-cryptodisk-Move-global-variables-into-grub_cryptomou.patch b/0385-cryptodisk-Move-global-variables-into-grub_cryptomou.patch new file mode 100644 index 0000000..8942422 --- /dev/null +++ b/0385-cryptodisk-Move-global-variables-into-grub_cryptomou.patch @@ -0,0 +1,245 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Thu, 9 Dec 2021 11:14:57 -0600 +Subject: [PATCH] cryptodisk: Move global variables into grub_cryptomount_args + struct + +Note that cargs.search_uuid does not need to be initialized in various parts +of the cryptomount argument parsing, just once when cargs is declared with +a struct initializer. The previous code used a global variable which would +retain the value across cryptomount invocations. + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 24 +++++++++--------------- + grub-core/disk/geli.c | 9 ++++----- + grub-core/disk/luks.c | 9 ++++----- + grub-core/disk/luks2.c | 8 ++++---- + include/grub/cryptodisk.h | 9 +++++++-- + 5 files changed, 28 insertions(+), 31 deletions(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index d12368a..7ca8804 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -984,9 +984,6 @@ grub_util_cryptodisk_get_uuid (grub_disk_t disk) + + #endif + +-static int check_boot; +-static char *search_uuid; +- + static void + cryptodisk_close (grub_cryptodisk_t dev) + { +@@ -1014,7 +1011,7 @@ grub_cryptodisk_scan_device_real (const char *name, + + FOR_CRYPTODISK_DEVS (cr) + { +- dev = cr->scan (source, search_uuid, check_boot); ++ dev = cr->scan (source, cargs); + if (grub_errno) + return NULL; + if (!dev) +@@ -1077,6 +1074,7 @@ grub_cryptodisk_cheat_mount (const char *sourcedev, const char *cheat) + grub_cryptodisk_t dev; + grub_cryptodisk_dev_t cr; + grub_disk_t source; ++ struct grub_cryptomount_args cargs = {0}; + + /* Try to open disk. */ + source = grub_disk_open (sourcedev); +@@ -1093,7 +1091,7 @@ grub_cryptodisk_cheat_mount (const char *sourcedev, const char *cheat) + + FOR_CRYPTODISK_DEVS (cr) + { +- dev = cr->scan (source, search_uuid, check_boot); ++ dev = cr->scan (source, &cargs); + if (grub_errno) + return grub_errno; + if (!dev) +@@ -1136,7 +1134,7 @@ grub_cryptodisk_scan_device (const char *name, + dev = grub_cryptodisk_scan_device_real (name, source, cargs); + if (dev) + { +- ret = (search_uuid != NULL && grub_strcasecmp (search_uuid, dev->uuid) == 0); ++ ret = (cargs->search_uuid != NULL && grub_strcasecmp (cargs->search_uuid, dev->uuid) == 0); + goto cleanup; + } + +@@ -1147,7 +1145,7 @@ grub_cryptodisk_scan_device (const char *name, + if (grub_errno == GRUB_ERR_BAD_MODULE) + grub_error_pop (); + +- if (search_uuid != NULL) ++ if (cargs->search_uuid != NULL) + /* Push error onto stack to save for cryptomount. */ + grub_error_push (); + else +@@ -1189,10 +1187,9 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + return GRUB_ERR_NONE; + } + +- check_boot = state[2].set; +- search_uuid = args[0]; ++ cargs.check_boot = state[2].set; ++ cargs.search_uuid = args[0]; + found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, &cargs); +- search_uuid = NULL; + + if (found_uuid) + return GRUB_ERR_NONE; +@@ -1210,10 +1207,8 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + } + else if (state[1].set || (argc == 0 && state[2].set)) /* -a|-b */ + { +- search_uuid = NULL; +- check_boot = state[2].set; ++ cargs.check_boot = state[2].set; + grub_device_iterate (&grub_cryptodisk_scan_device, &cargs); +- search_uuid = NULL; + return GRUB_ERR_NONE; + } + else +@@ -1224,8 +1219,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + char *disklast = NULL; + grub_size_t len; + +- search_uuid = NULL; +- check_boot = state[2].set; ++ cargs.check_boot = state[2].set; + diskname = args[0]; + len = grub_strlen (diskname); + if (len && diskname[0] == '(' && diskname[len - 1] == ')') +diff --git a/grub-core/disk/geli.c b/grub-core/disk/geli.c +index 7299a47..23789c4 100644 +--- a/grub-core/disk/geli.c ++++ b/grub-core/disk/geli.c +@@ -240,8 +240,7 @@ grub_util_get_geli_uuid (const char *dev) + #endif + + static grub_cryptodisk_t +-configure_ciphers (grub_disk_t disk, const char *check_uuid, +- int boot_only) ++configure_ciphers (grub_disk_t disk, grub_cryptomount_args_t cargs) + { + grub_cryptodisk_t newdev; + struct grub_geli_phdr header; +@@ -289,7 +288,7 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid, + return NULL; + } + +- if (boot_only && !(grub_le_to_cpu32 (header.flags) & GRUB_GELI_FLAGS_BOOT)) ++ if (cargs->check_boot && !(grub_le_to_cpu32 (header.flags) & GRUB_GELI_FLAGS_BOOT)) + { + grub_dprintf ("geli", "not a boot volume\n"); + return NULL; +@@ -302,9 +301,9 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid, + return NULL; + } + +- if (check_uuid && grub_strcasecmp (check_uuid, uuid) != 0) ++ if (cargs->search_uuid != NULL && grub_strcasecmp (cargs->search_uuid, uuid) != 0) + { +- grub_dprintf ("geli", "%s != %s\n", uuid, check_uuid); ++ grub_dprintf ("geli", "%s != %s\n", uuid, cargs->search_uuid); + return NULL; + } + +diff --git a/grub-core/disk/luks.c b/grub-core/disk/luks.c +index 39a7af6..f0feb38 100644 +--- a/grub-core/disk/luks.c ++++ b/grub-core/disk/luks.c +@@ -63,8 +63,7 @@ gcry_err_code_t AF_merge (const gcry_md_spec_t * hash, grub_uint8_t * src, + grub_size_t blocknumbers); + + static grub_cryptodisk_t +-configure_ciphers (grub_disk_t disk, const char *check_uuid, +- int check_boot) ++configure_ciphers (grub_disk_t disk, grub_cryptomount_args_t cargs) + { + grub_cryptodisk_t newdev; + const char *iptr; +@@ -76,7 +75,7 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid, + char hashspec[sizeof (header.hashSpec) + 1]; + grub_err_t err; + +- if (check_boot) ++ if (cargs->check_boot) + return NULL; + + /* Read the LUKS header. */ +@@ -103,9 +102,9 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid, + } + *optr = 0; + +- if (check_uuid && grub_strcasecmp (check_uuid, uuid) != 0) ++ if (cargs->search_uuid != NULL && grub_strcasecmp (cargs->search_uuid, uuid) != 0) + { +- grub_dprintf ("luks", "%s != %s\n", uuid, check_uuid); ++ grub_dprintf ("luks", "%s != %s\n", uuid, cargs->search_uuid); + return NULL; + } + +diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c +index caed4d4..bf741d7 100644 +--- a/grub-core/disk/luks2.c ++++ b/grub-core/disk/luks2.c +@@ -346,14 +346,14 @@ luks2_read_header (grub_disk_t disk, grub_luks2_header_t *outhdr) + } + + static grub_cryptodisk_t +-luks2_scan (grub_disk_t disk, const char *check_uuid, int check_boot) ++luks2_scan (grub_disk_t disk, grub_cryptomount_args_t cargs) + { + grub_cryptodisk_t cryptodisk; + grub_luks2_header_t header; + char uuid[sizeof (header.uuid) + 1]; + grub_size_t i, j; + +- if (check_boot) ++ if (cargs->check_boot) + return NULL; + + if (luks2_read_header (disk, &header)) +@@ -367,9 +367,9 @@ luks2_scan (grub_disk_t disk, const char *check_uuid, int check_boot) + uuid[j++] = header.uuid[i]; + uuid[j] = '\0'; + +- if (check_uuid && grub_strcasecmp (check_uuid, uuid) != 0) ++ if (cargs->search_uuid != NULL && grub_strcasecmp (cargs->search_uuid, uuid) != 0) + { +- grub_dprintf ("luks2", "%s != %s\n", uuid, check_uuid); ++ grub_dprintf ("luks2", "%s != %s\n", uuid, cargs->search_uuid); + return NULL; + } + +diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h +index 5bd9706..c6524c9 100644 +--- a/include/grub/cryptodisk.h ++++ b/include/grub/cryptodisk.h +@@ -69,7 +69,13 @@ typedef gcry_err_code_t + + struct grub_cryptomount_args + { ++ /* scan: Flag to indicate that only bootable volumes should be decrypted */ ++ grub_uint32_t check_boot : 1; ++ /* scan: Only volumes matching this UUID should be decrpyted */ ++ char *search_uuid; ++ /* recover_key: Key data used to decrypt voume */ + grub_uint8_t *key_data; ++ /* recover_key: Length of key_data */ + grub_size_t key_len; + }; + typedef struct grub_cryptomount_args *grub_cryptomount_args_t; +@@ -125,8 +131,7 @@ struct grub_cryptodisk_dev + struct grub_cryptodisk_dev *next; + struct grub_cryptodisk_dev **prev; + +- grub_cryptodisk_t (*scan) (grub_disk_t disk, const char *check_uuid, +- int boot_only); ++ grub_cryptodisk_t (*scan) (grub_disk_t disk, grub_cryptomount_args_t cargs); + grub_err_t (*recover_key) (grub_disk_t disk, grub_cryptodisk_t dev, grub_cryptomount_args_t cargs); + }; + typedef struct grub_cryptodisk_dev *grub_cryptodisk_dev_t; diff --git a/0386-cryptodisk-Improve-handling-of-partition-name-in-cry.patch b/0386-cryptodisk-Improve-handling-of-partition-name-in-cry.patch new file mode 100644 index 0000000..5c56861 --- /dev/null +++ b/0386-cryptodisk-Improve-handling-of-partition-name-in-cry.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Thu, 9 Dec 2021 11:14:58 -0600 +Subject: [PATCH] cryptodisk: Improve handling of partition name in cryptomount + password prompt + +Call grub_partition_get_name() unconditionally to initialize the part +variable. Then part will only be NULL when grub_partition_get_name() errors. +Note that when source->partition is NULL, then grub_partition_get_name() +returns an allocated empty string. So no comma or partition will be printed, +as desired. + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 7ca8804..4970973 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -1021,11 +1021,10 @@ grub_cryptodisk_scan_device_real (const char *name, + { + /* Get the passphrase from the user, if no key data. */ + askpass = 1; +- if (source->partition != NULL) +- part = grub_partition_get_name (source->partition); ++ part = grub_partition_get_name (source->partition); + grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name, + source->partition != NULL ? "," : "", +- part != NULL ? part : "", ++ part != NULL ? part : N_("UNKNOWN"), + dev->uuid); + grub_free (part); + diff --git a/0387-cryptodisk-Fix-Coverity-use-after-free-bug.patch b/0387-cryptodisk-Fix-Coverity-use-after-free-bug.patch new file mode 100644 index 0000000..e194f28 --- /dev/null +++ b/0387-cryptodisk-Fix-Coverity-use-after-free-bug.patch @@ -0,0 +1,72 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Sat, 1 Jan 2022 15:48:25 -0600 +Subject: [PATCH] cryptodisk: Fix Coverity use after free bug + +The Coverity output is: + + *** CID 366905: Memory - illegal accesses (USE_AFTER_FREE) + /grub-core/disk/cryptodisk.c: 1064 in grub_cryptodisk_scan_device_real() + 1058 cleanup: + 1059 if (askpass) + 1060 { + 1061 cargs->key_len = 0; + 1062 grub_free (cargs->key_data); + 1063 } + >>> CID 366905: Memory - illegal accesses (USE_AFTER_FREE) + >>> Using freed pointer "dev". + 1064 return dev; + 1065 } + 1066 + 1067 #ifdef GRUB_UTIL + 1068 #include + 1069 grub_err_t + +Here the "dev" variable can point to a freed cryptodisk device if the +function grub_cryptodisk_insert() fails. This can happen only on a OOM +condition, but when this happens grub_cryptodisk_insert() calls grub_free on +the passed device. Since grub_cryptodisk_scan_device_real() assumes that +grub_cryptodisk_insert() is always successful, it will return the device, +though the device was freed. + +Change grub_cryptodisk_insert() to not free the passed device on failure. +Then on grub_cryptodisk_insert() failure, free the device pointer. This is +done by going to the label "error", which will call cryptodisk_close() to +free the device and set the device pointer to NULL, so that a pointer to +freed memory is not returned. + +Fixes: CID 366905 + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 4970973..e7c4795 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -889,10 +889,7 @@ grub_cryptodisk_insert (grub_cryptodisk_t newdev, const char *name, + { + newdev->source = grub_strdup (name); + if (!newdev->source) +- { +- grub_free (newdev); +- return grub_errno; +- } ++ return grub_errno; + + newdev->id = last_cryptodisk_id++; + newdev->source_id = source->id; +@@ -1044,7 +1041,9 @@ grub_cryptodisk_scan_device_real (const char *name, + if (ret != GRUB_ERR_NONE) + goto error; + +- grub_cryptodisk_insert (dev, name, source); ++ ret = grub_cryptodisk_insert (dev, name, source); ++ if (ret != GRUB_ERR_NONE) ++ goto error; + + goto cleanup; + } diff --git a/0388-disk-cryptodisk-Add-options-to-cryptomount-to-suppor.patch b/0388-disk-cryptodisk-Add-options-to-cryptomount-to-suppor.patch new file mode 100644 index 0000000..025a96a --- /dev/null +++ b/0388-disk-cryptodisk-Add-options-to-cryptomount-to-suppor.patch @@ -0,0 +1,155 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: John Lane +Date: Fri, 20 May 2022 14:32:17 -0500 +Subject: [PATCH] disk/cryptodisk: Add options to cryptomount to support + keyfiles + +Add the options --key-file, --keyfile-offset, and --keyfile-size to +cryptomount and code to put read the requested key file data and pass +via the cargs struct. Note, key file data is for all intents and purposes +equivalent to a password given to cryptomount. So there is no need to +enable support for key files in the various crypto backends (e.g. LUKS1) +because the key data is passed just as if it were a password. + +Signed-off-by: John Lane +Signed-off-by: Denis 'GNUtoo' Carikli +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 81 ++++++++++++++++++++++++++++++++++++++++++++- + include/grub/cryptodisk.h | 2 ++ + include/grub/file.h | 2 ++ + 3 files changed, 84 insertions(+), 1 deletion(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index e7c4795..0706afa 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -42,6 +42,9 @@ static const struct grub_arg_option options[] = + {"all", 'a', 0, N_("Mount all."), 0, 0}, + {"boot", 'b', 0, N_("Mount all volumes with `boot' flag set."), 0, 0}, + {"password", 'p', 0, N_("Password to open volumes."), 0, ARG_TYPE_STRING}, ++ {"key-file", 'k', 0, N_("Key file"), 0, ARG_TYPE_STRING}, ++ {"keyfile-offset", 'O', 0, N_("Key file offset (bytes)"), 0, ARG_TYPE_INT}, ++ {"keyfile-size", 'S', 0, N_("Key file data size (bytes)"), 0, ARG_TYPE_INT}, + {0, 0, 0, 0, 0, 0} + }; + +@@ -1172,6 +1175,80 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + cargs.key_len = grub_strlen (state[3].arg); + } + ++ if (state[4].set) /* keyfile */ ++ { ++ const char *p = NULL; ++ grub_file_t keyfile; ++ unsigned long long keyfile_offset = 0, keyfile_size = 0; ++ ++ if (state[5].set) /* keyfile-offset */ ++ { ++ grub_errno = GRUB_ERR_NONE; ++ keyfile_offset = grub_strtoull (state[5].arg, &p, 0); ++ ++ if (state[5].arg[0] == '\0' || *p != '\0') ++ return grub_error (grub_errno, ++ N_("non-numeric or invalid keyfile offset `%s'"), ++ state[5].arg); ++ } ++ ++ if (state[6].set) /* keyfile-size */ ++ { ++ grub_errno = GRUB_ERR_NONE; ++ keyfile_size = grub_strtoull (state[6].arg, &p, 0); ++ ++ if (state[6].arg[0] == '\0' || *p != '\0') ++ return grub_error (grub_errno, ++ N_("non-numeric or invalid keyfile size `%s'"), ++ state[6].arg); ++ ++ if (keyfile_size == 0) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("key file size is 0")); ++ ++ if (keyfile_size > GRUB_CRYPTODISK_MAX_KEYFILE_SIZE) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("key file size exceeds maximum (%d)"), ++ GRUB_CRYPTODISK_MAX_KEYFILE_SIZE); ++ } ++ ++ keyfile = grub_file_open (state[4].arg, ++ GRUB_FILE_TYPE_CRYPTODISK_ENCRYPTION_KEY); ++ if (keyfile == NULL) ++ return grub_errno; ++ ++ if (keyfile_offset > keyfile->size) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("Keyfile offset, %llu, is greater than" ++ "keyfile size, %" PRIuGRUB_UINT64_T), ++ keyfile_offset, keyfile->size); ++ ++ if (grub_file_seek (keyfile, (grub_off_t) keyfile_offset) == (grub_off_t) -1) ++ return grub_errno; ++ ++ if (keyfile_size != 0) ++ { ++ if (keyfile_size > (keyfile->size - keyfile_offset)) ++ return grub_error (GRUB_ERR_FILE_READ_ERROR, ++ N_("keyfile is too small: requested %llu bytes," ++ " but the file only has %" PRIuGRUB_UINT64_T ++ " bytes left at offset %llu"), ++ keyfile_size, ++ (grub_off_t) (keyfile->size - keyfile_offset), ++ keyfile_offset); ++ ++ cargs.key_len = keyfile_size; ++ } ++ else ++ cargs.key_len = keyfile->size - keyfile_offset; ++ ++ cargs.key_data = grub_malloc (cargs.key_len); ++ if (cargs.key_data == NULL) ++ return GRUB_ERR_OUT_OF_MEMORY; ++ ++ if (grub_file_read (keyfile, cargs.key_data, cargs.key_len) != (grub_ssize_t) cargs.key_len) ++ return grub_error (GRUB_ERR_FILE_READ_ERROR, (N_("failed to read key file"))); ++ } ++ + if (state[0].set) /* uuid */ + { + int found_uuid; +@@ -1384,7 +1461,9 @@ GRUB_MOD_INIT (cryptodisk) + { + grub_disk_dev_register (&grub_cryptodisk_dev); + cmd = grub_register_extcmd ("cryptomount", grub_cmd_cryptomount, 0, +- N_("[-p password] "), ++ N_("[ [-p password] | [-k keyfile" ++ " [-O keyoffset] [-S keysize] ] ]" ++ " "), + N_("Mount a crypto device."), options); + grub_procfs_register ("luks_script", &luks_script); + } +diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h +index c6524c9..467065f 100644 +--- a/include/grub/cryptodisk.h ++++ b/include/grub/cryptodisk.h +@@ -61,6 +61,8 @@ typedef enum + #define GRUB_CRYPTODISK_MAX_KEYLEN 128 + #define GRUB_CRYPTODISK_MAX_PASSPHRASE 256 + ++#define GRUB_CRYPTODISK_MAX_KEYFILE_SIZE 8192 ++ + struct grub_cryptodisk; + + typedef gcry_err_code_t +diff --git a/include/grub/file.h b/include/grub/file.h +index 96827a4..2e9fff7 100644 +--- a/include/grub/file.h ++++ b/include/grub/file.h +@@ -92,6 +92,8 @@ enum grub_file_type + GRUB_FILE_TYPE_FONT, + /* File holding encryption key for encrypted ZFS. */ + GRUB_FILE_TYPE_ZFS_ENCRYPTION_KEY, ++ /* File holding the encryption key. */ ++ GRUB_FILE_TYPE_CRYPTODISK_ENCRYPTION_KEY, + /* File we open n grub-fstest. */ + GRUB_FILE_TYPE_FSTEST, + /* File we open n grub-mount. */ diff --git a/0389-disk-cryptodisk-Use-enum-constants-as-indexes-into-c.patch b/0389-disk-cryptodisk-Use-enum-constants-as-indexes-into-c.patch new file mode 100644 index 0000000..a39be4e --- /dev/null +++ b/0389-disk-cryptodisk-Use-enum-constants-as-indexes-into-c.patch @@ -0,0 +1,140 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Fri, 20 May 2022 14:32:18 -0500 +Subject: [PATCH] disk/cryptodisk: Use enum constants as indexes into + cryptomount option array + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 49 +++++++++++++++++++++++++++------------------ + 1 file changed, 30 insertions(+), 19 deletions(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 0706afa..9db5f65 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -35,6 +35,17 @@ GRUB_MOD_LICENSE ("GPLv3+"); + + grub_cryptodisk_dev_t grub_cryptodisk_list; + ++enum ++ { ++ OPTION_UUID, ++ OPTION_ALL, ++ OPTION_BOOT, ++ OPTION_PASSWORD, ++ OPTION_KEYFILE, ++ OPTION_KEYFILE_OFFSET, ++ OPTION_KEYFILE_SIZE ++ }; ++ + static const struct grub_arg_option options[] = + { + {"uuid", 'u', 0, N_("Mount by UUID."), 0, 0}, +@@ -1163,44 +1174,44 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + struct grub_arg_list *state = ctxt->state; + struct grub_cryptomount_args cargs = {0}; + +- if (argc < 1 && !state[1].set && !state[2].set) ++ if (argc < 1 && !state[OPTION_ALL].set && !state[OPTION_BOOT].set) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); + + if (grub_cryptodisk_list == NULL) + return grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk modules loaded"); + +- if (state[3].set) /* password */ ++ if (state[OPTION_PASSWORD].set) /* password */ + { +- cargs.key_data = (grub_uint8_t *) state[3].arg; +- cargs.key_len = grub_strlen (state[3].arg); ++ cargs.key_data = (grub_uint8_t *) state[OPTION_PASSWORD].arg; ++ cargs.key_len = grub_strlen (state[OPTION_PASSWORD].arg); + } + +- if (state[4].set) /* keyfile */ ++ if (state[OPTION_KEYFILE].set) /* keyfile */ + { + const char *p = NULL; + grub_file_t keyfile; + unsigned long long keyfile_offset = 0, keyfile_size = 0; + +- if (state[5].set) /* keyfile-offset */ ++ if (state[OPTION_KEYFILE_OFFSET].set) /* keyfile-offset */ + { + grub_errno = GRUB_ERR_NONE; +- keyfile_offset = grub_strtoull (state[5].arg, &p, 0); ++ keyfile_offset = grub_strtoull (state[OPTION_KEYFILE_OFFSET].arg, &p, 0); + +- if (state[5].arg[0] == '\0' || *p != '\0') ++ if (state[OPTION_KEYFILE_OFFSET].arg[0] == '\0' || *p != '\0') + return grub_error (grub_errno, + N_("non-numeric or invalid keyfile offset `%s'"), +- state[5].arg); ++ state[OPTION_KEYFILE_OFFSET].arg); + } + +- if (state[6].set) /* keyfile-size */ ++ if (state[OPTION_KEYFILE_SIZE].set) /* keyfile-size */ + { + grub_errno = GRUB_ERR_NONE; +- keyfile_size = grub_strtoull (state[6].arg, &p, 0); ++ keyfile_size = grub_strtoull (state[OPTION_KEYFILE_SIZE].arg, &p, 0); + +- if (state[6].arg[0] == '\0' || *p != '\0') ++ if (state[OPTION_KEYFILE_SIZE].arg[0] == '\0' || *p != '\0') + return grub_error (grub_errno, + N_("non-numeric or invalid keyfile size `%s'"), +- state[6].arg); ++ state[OPTION_KEYFILE_SIZE].arg); + + if (keyfile_size == 0) + return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("key file size is 0")); +@@ -1211,7 +1222,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + GRUB_CRYPTODISK_MAX_KEYFILE_SIZE); + } + +- keyfile = grub_file_open (state[4].arg, ++ keyfile = grub_file_open (state[OPTION_KEYFILE].arg, + GRUB_FILE_TYPE_CRYPTODISK_ENCRYPTION_KEY); + if (keyfile == NULL) + return grub_errno; +@@ -1249,7 +1260,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + return grub_error (GRUB_ERR_FILE_READ_ERROR, (N_("failed to read key file"))); + } + +- if (state[0].set) /* uuid */ ++ if (state[OPTION_UUID].set) /* uuid */ + { + int found_uuid; + grub_cryptodisk_t dev; +@@ -1262,7 +1273,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + return GRUB_ERR_NONE; + } + +- cargs.check_boot = state[2].set; ++ cargs.check_boot = state[OPTION_BOOT].set; + cargs.search_uuid = args[0]; + found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, &cargs); + +@@ -1280,9 +1291,9 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + } + return grub_errno; + } +- else if (state[1].set || (argc == 0 && state[2].set)) /* -a|-b */ ++ else if (state[OPTION_ALL].set || (argc == 0 && state[OPTION_BOOT].set)) /* -a|-b */ + { +- cargs.check_boot = state[2].set; ++ cargs.check_boot = state[OPTION_BOOT].set; + grub_device_iterate (&grub_cryptodisk_scan_device, &cargs); + return GRUB_ERR_NONE; + } +@@ -1294,7 +1305,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + char *disklast = NULL; + grub_size_t len; + +- cargs.check_boot = state[2].set; ++ cargs.check_boot = state[OPTION_BOOT].set; + diskname = args[0]; + len = grub_strlen (diskname); + if (len && diskname[0] == '(' && diskname[len - 1] == ')') diff --git a/0390-cryptodisk-Add-support-for-using-detached-header-fil.patch b/0390-cryptodisk-Add-support-for-using-detached-header-fil.patch new file mode 100644 index 0000000..d052e92 --- /dev/null +++ b/0390-cryptodisk-Add-support-for-using-detached-header-fil.patch @@ -0,0 +1,259 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Wed, 8 Jun 2022 10:34:03 -0500 +Subject: [PATCH] cryptodisk: Add support for using detached header files + +Using the disk read hook mechanism, setup a read hook on the source disk +which will read from the given header file during the scan and recovery +cryptodisk backend functions. Disk read hooks are executed after the data +has been read from the disk. This is okay, because the read hook is given +the read buffer before its sent back to the caller. In this case, the hook +can then overwrite the data read from the disk device with data from the +header file sent in as the read hook data. This is transparent to the +read caller. Since the callers of this function have just opened the +source disk, there are no current read hooks, so there's no need to +save/restore them nor consider if they should be called or not. + +This hook assumes that the header is at the start of the volume, which +is not the case for some formats (e.g. GELI). So GELI will return an +error if a detached header is specified. It also can only be used +with formats where the detached header file can be written to the +first blocks of the volume and the volume could still be unlocked. +So the header file can not be formatted differently from the on-disk +header. If these assumpts are not met, detached header file processing +must be specially handled in the cryptodisk backend module. + +The hook will be called potentially many times by a backend. This is fine +because of the assumptions mentioned and the read hook reads from absolute +offsets and is stateless. + +Also add a --header (short -H) option to cryptomount which takes a file +argument. + +Signed-off-by: Glenn Washburn +Reviewed-by: Patrick Steinhardt +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 92 +++++++++++++++++++++++++++++++++++++++++++-- + grub-core/disk/geli.c | 4 ++ + include/grub/cryptodisk.h | 2 + + include/grub/file.h | 2 + + 4 files changed, 96 insertions(+), 4 deletions(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 9db5f65..3d8472e 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -43,7 +43,8 @@ enum + OPTION_PASSWORD, + OPTION_KEYFILE, + OPTION_KEYFILE_OFFSET, +- OPTION_KEYFILE_SIZE ++ OPTION_KEYFILE_SIZE, ++ OPTION_HEADER + }; + + static const struct grub_arg_option options[] = +@@ -56,9 +57,16 @@ static const struct grub_arg_option options[] = + {"key-file", 'k', 0, N_("Key file"), 0, ARG_TYPE_STRING}, + {"keyfile-offset", 'O', 0, N_("Key file offset (bytes)"), 0, ARG_TYPE_INT}, + {"keyfile-size", 'S', 0, N_("Key file data size (bytes)"), 0, ARG_TYPE_INT}, ++ {"header", 'H', 0, N_("Read header from file"), 0, ARG_TYPE_STRING}, + {0, 0, 0, 0, 0, 0} + }; + ++struct cryptodisk_read_hook_ctx ++{ ++ grub_file_t hdr_file; ++}; ++typedef struct cryptodisk_read_hook_ctx *cryptodisk_read_hook_ctx_t; ++ + /* Our irreducible polynom is x^128+x^7+x^2+x+1. Lowest byte of it is: */ + #define GF_POLYNOM 0x87 + static inline int GF_PER_SECTOR (const struct grub_cryptodisk *dev) +@@ -1004,6 +1012,30 @@ cryptodisk_close (grub_cryptodisk_t dev) + grub_free (dev); + } + ++static grub_err_t ++cryptodisk_read_hook (grub_disk_addr_t sector, unsigned offset, ++ unsigned length, char *buf, void *data) ++{ ++ cryptodisk_read_hook_ctx_t ctx = data; ++ ++ if (ctx->hdr_file == NULL) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("header file not found")); ++ ++ if (grub_file_seek (ctx->hdr_file, ++ (sector * GRUB_DISK_SECTOR_SIZE) + offset) ++ == (grub_off_t) -1) ++ return grub_errno; ++ ++ if (grub_file_read (ctx->hdr_file, buf, length) != (grub_ssize_t) length) ++ { ++ if (grub_errno == GRUB_ERR_NONE) ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("header file too small")); ++ return grub_errno; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ + static grub_cryptodisk_t + grub_cryptodisk_scan_device_real (const char *name, + grub_disk_t source, +@@ -1012,6 +1044,7 @@ grub_cryptodisk_scan_device_real (const char *name, + grub_err_t ret = GRUB_ERR_NONE; + grub_cryptodisk_t dev; + grub_cryptodisk_dev_t cr; ++ struct cryptodisk_read_hook_ctx read_hook_data = {0}; + int askpass = 0; + char *part = NULL; + +@@ -1020,11 +1053,46 @@ grub_cryptodisk_scan_device_real (const char *name, + if (dev) + return dev; + ++ if (cargs->hdr_file != NULL) ++ { ++ /* ++ * Set read hook to read header from a file instead of the source disk. ++ * Disk read hooks are executed after the data has been read from the ++ * disk. This is okay, because the read hook is given the read buffer ++ * before its sent back to the caller. In this case, the hook can then ++ * overwrite the data read from the disk device with data from the ++ * header file sent in as the read hook data. This is transparent to the ++ * read caller. Since the callers of this function have just opened the ++ * source disk, there are no current read hooks, so there's no need to ++ * save/restore them nor consider if they should be called or not. ++ * ++ * This hook assumes that the header is at the start of the volume, which ++ * is not the case for some formats (eg. GELI). It also can only be used ++ * with formats where the detached header file can be written to the ++ * first blocks of the volume and the volume could still be unlocked. ++ * So the header file can not be formatted differently from the on-disk ++ * header. If these assumpts are not met, detached header file processing ++ * must be specially handled in the cryptodisk backend module. ++ * ++ * This hook needs only be set once and will be called potentially many ++ * times by a backend. This is fine because of the assumptions mentioned ++ * and the read hook reads from absolute offsets and is stateless. ++ */ ++ read_hook_data.hdr_file = cargs->hdr_file; ++ source->read_hook = cryptodisk_read_hook; ++ source->read_hook_data = (void *) &read_hook_data; ++ } ++ + FOR_CRYPTODISK_DEVS (cr) + { ++ /* ++ * Loop through each cryptodisk backend that is registered (ie. loaded). ++ * If the scan returns NULL, then the backend being tested does not ++ * recognize the source disk, so move on to the next backend. ++ */ + dev = cr->scan (source, cargs); + if (grub_errno) +- return NULL; ++ goto error_no_close; + if (!dev) + continue; + +@@ -1041,7 +1109,7 @@ grub_cryptodisk_scan_device_real (const char *name, + + cargs->key_data = grub_malloc (GRUB_CRYPTODISK_MAX_PASSPHRASE); + if (cargs->key_data == NULL) +- return NULL; ++ goto error_no_close; + + if (!grub_password_get ((char *) cargs->key_data, GRUB_CRYPTODISK_MAX_PASSPHRASE)) + { +@@ -1066,9 +1134,13 @@ grub_cryptodisk_scan_device_real (const char *name, + + error: + cryptodisk_close (dev); ++ error_no_close: + dev = NULL; + + cleanup: ++ if (cargs->hdr_file != NULL) ++ source->read_hook = NULL; ++ + if (askpass) + { + cargs->key_len = 0; +@@ -1260,6 +1332,18 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + return grub_error (GRUB_ERR_FILE_READ_ERROR, (N_("failed to read key file"))); + } + ++ if (state[OPTION_HEADER].set) /* header */ ++ { ++ if (state[OPTION_UUID].set) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("cannot use UUID lookup with detached header")); ++ ++ cargs.hdr_file = grub_file_open (state[OPTION_HEADER].arg, ++ GRUB_FILE_TYPE_CRYPTODISK_DETACHED_HEADER); ++ if (cargs.hdr_file == NULL) ++ return grub_errno; ++ } ++ + if (state[OPTION_UUID].set) /* uuid */ + { + int found_uuid; +@@ -1473,7 +1557,7 @@ GRUB_MOD_INIT (cryptodisk) + grub_disk_dev_register (&grub_cryptodisk_dev); + cmd = grub_register_extcmd ("cryptomount", grub_cmd_cryptomount, 0, + N_("[ [-p password] | [-k keyfile" +- " [-O keyoffset] [-S keysize] ] ]" ++ " [-O keyoffset] [-S keysize] ] ] [-H file]" + " "), + N_("Mount a crypto device."), options); + grub_procfs_register ("luks_script", &luks_script); +diff --git a/grub-core/disk/geli.c b/grub-core/disk/geli.c +index 23789c4..52dd504 100644 +--- a/grub-core/disk/geli.c ++++ b/grub-core/disk/geli.c +@@ -252,6 +252,10 @@ configure_ciphers (grub_disk_t disk, grub_cryptomount_args_t cargs) + grub_disk_addr_t sector; + grub_err_t err; + ++ /* Detached headers are not implemented yet */ ++ if (cargs->hdr_file != NULL) ++ return NULL; ++ + if (2 * GRUB_MD_SHA256->mdlen + 1 > GRUB_CRYPTODISK_MAX_UUID_LENGTH) + return NULL; + +diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h +index 467065f..d94df68 100644 +--- a/include/grub/cryptodisk.h ++++ b/include/grub/cryptodisk.h +@@ -20,6 +20,7 @@ + #define GRUB_CRYPTODISK_HEADER 1 + + #include ++#include + #include + #include + #ifdef GRUB_UTIL +@@ -79,6 +80,7 @@ struct grub_cryptomount_args + grub_uint8_t *key_data; + /* recover_key: Length of key_data */ + grub_size_t key_len; ++ grub_file_t hdr_file; + }; + typedef struct grub_cryptomount_args *grub_cryptomount_args_t; + +diff --git a/include/grub/file.h b/include/grub/file.h +index 2e9fff7..d678de0 100644 +--- a/include/grub/file.h ++++ b/include/grub/file.h +@@ -94,6 +94,8 @@ enum grub_file_type + GRUB_FILE_TYPE_ZFS_ENCRYPTION_KEY, + /* File holding the encryption key. */ + GRUB_FILE_TYPE_CRYPTODISK_ENCRYPTION_KEY, ++ /* File holding the encryption metadata header */ ++ GRUB_FILE_TYPE_CRYPTODISK_DETACHED_HEADER, + /* File we open n grub-fstest. */ + GRUB_FILE_TYPE_FSTEST, + /* File we open n grub-mount. */ diff --git a/0391-disk-cryptodisk-Support-encrypted-volumes-using-deta.patch b/0391-disk-cryptodisk-Support-encrypted-volumes-using-deta.patch new file mode 100644 index 0000000..f87220c --- /dev/null +++ b/0391-disk-cryptodisk-Support-encrypted-volumes-using-deta.patch @@ -0,0 +1,51 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Sun, 7 Aug 2022 00:18:52 -0500 +Subject: [PATCH] disk/cryptodisk: Support encrypted volumes using detached + headers on a partition + +Update the read hook to take into account encrypted volumes on a partition. +GRUB disk read hooks supply an absolute sector number at which the read is +started from. If the encrypted volume is in a partition, the sector number +given to the read hook will be offset by the number of the sector at the +start of the partition. The read hook then needs to subtract the partition +start from the supplied sector to get the correct start sector for the read +into the detached header file. + +Reported-by: brutser +Signed-off-by: Glenn Washburn +Tested-by: brutser +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 3d8472e..42370db 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -64,6 +64,7 @@ static const struct grub_arg_option options[] = + struct cryptodisk_read_hook_ctx + { + grub_file_t hdr_file; ++ grub_disk_addr_t part_start; + }; + typedef struct cryptodisk_read_hook_ctx *cryptodisk_read_hook_ctx_t; + +@@ -1022,7 +1023,7 @@ cryptodisk_read_hook (grub_disk_addr_t sector, unsigned offset, + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("header file not found")); + + if (grub_file_seek (ctx->hdr_file, +- (sector * GRUB_DISK_SECTOR_SIZE) + offset) ++ ((sector - ctx->part_start) * GRUB_DISK_SECTOR_SIZE) + offset) + == (grub_off_t) -1) + return grub_errno; + +@@ -1078,6 +1079,7 @@ grub_cryptodisk_scan_device_real (const char *name, + * times by a backend. This is fine because of the assumptions mentioned + * and the read hook reads from absolute offsets and is stateless. + */ ++ read_hook_data.part_start = grub_partition_get_start (source->partition); + read_hook_data.hdr_file = cargs->hdr_file; + source->read_hook = cryptodisk_read_hook; + source->read_hook_data = (void *) &read_hook_data; diff --git a/0392-disk-cryptodisk-Allows-UUIDs-to-be-compared-in-a-das.patch b/0392-disk-cryptodisk-Allows-UUIDs-to-be-compared-in-a-das.patch new file mode 100644 index 0000000..58b7d05 --- /dev/null +++ b/0392-disk-cryptodisk-Allows-UUIDs-to-be-compared-in-a-das.patch @@ -0,0 +1,200 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Fri, 19 Aug 2022 18:06:15 -0500 +Subject: [PATCH] disk/cryptodisk: Allows UUIDs to be compared in a + dash-insensitive manner + +A user can now specify UUID strings with dashes, instead of having to remove +dashes. This is backwards-compatibility preserving and also fixes a source +of user confusion over the inconsistency with how UUIDs are specified +between file system UUIDs and cryptomount UUIDs. Since cryptsetup, the +reference implementation for LUKS, displays and generates UUIDs with dashes +there has been additional confusion when using the UUID strings from +cryptsetup as exact input into GRUB does not find the expected cryptodisk. + +A new function grub_uuidcasecmp() is added that is general enough to be used +other places where UUIDs are being compared. + +Signed-off-by: Glenn Washburn +Reviewed-by: Patrick Steinhardt +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 4 ++-- + grub-core/disk/geli.c | 2 +- + grub-core/disk/luks.c | 21 ++++----------------- + grub-core/disk/luks2.c | 15 ++++----------- + include/grub/misc.h | 30 ++++++++++++++++++++++++++++++ + 5 files changed, 41 insertions(+), 31 deletions(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 42370db..17b5034 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -702,7 +702,7 @@ grub_cryptodisk_open (const char *name, grub_disk_t disk) + if (grub_memcmp (name, "cryptouuid/", sizeof ("cryptouuid/") - 1) == 0) + { + for (dev = cryptodisk_list; dev != NULL; dev = dev->next) +- if (grub_strcasecmp (name + sizeof ("cryptouuid/") - 1, dev->uuid) == 0) ++ if (grub_uuidcasecmp (name + sizeof ("cryptouuid/") - 1, dev->uuid, sizeof (dev->uuid)) == 0) + break; + } + else +@@ -929,7 +929,7 @@ grub_cryptodisk_get_by_uuid (const char *uuid) + { + grub_cryptodisk_t dev; + for (dev = cryptodisk_list; dev != NULL; dev = dev->next) +- if (grub_strcasecmp (dev->uuid, uuid) == 0) ++ if (grub_uuidcasecmp (dev->uuid, uuid, sizeof (dev->uuid)) == 0) + return dev; + return NULL; + } +diff --git a/grub-core/disk/geli.c b/grub-core/disk/geli.c +index 52dd504..bd18b19 100644 +--- a/grub-core/disk/geli.c ++++ b/grub-core/disk/geli.c +@@ -305,7 +305,7 @@ configure_ciphers (grub_disk_t disk, grub_cryptomount_args_t cargs) + return NULL; + } + +- if (cargs->search_uuid != NULL && grub_strcasecmp (cargs->search_uuid, uuid) != 0) ++ if (cargs->search_uuid != NULL && grub_uuidcasecmp (cargs->search_uuid, uuid, sizeof (uuid)) != 0) + { + grub_dprintf ("geli", "%s != %s\n", uuid, cargs->search_uuid); + return NULL; +diff --git a/grub-core/disk/luks.c b/grub-core/disk/luks.c +index f0feb38..f6a0cbc 100644 +--- a/grub-core/disk/luks.c ++++ b/grub-core/disk/luks.c +@@ -66,10 +66,7 @@ static grub_cryptodisk_t + configure_ciphers (grub_disk_t disk, grub_cryptomount_args_t cargs) + { + grub_cryptodisk_t newdev; +- const char *iptr; + struct grub_luks_phdr header; +- char *optr; +- char uuid[sizeof (header.uuid) + 1]; + char ciphername[sizeof (header.cipherName) + 1]; + char ciphermode[sizeof (header.cipherMode) + 1]; + char hashspec[sizeof (header.hashSpec) + 1]; +@@ -92,19 +89,9 @@ configure_ciphers (grub_disk_t disk, grub_cryptomount_args_t cargs) + || grub_be_to_cpu16 (header.version) != 1) + return NULL; + +- grub_memset (uuid, 0, sizeof (uuid)); +- optr = uuid; +- for (iptr = header.uuid; iptr < &header.uuid[ARRAY_SIZE (header.uuid)]; +- iptr++) ++ if (cargs->search_uuid != NULL && grub_uuidcasecmp (cargs->search_uuid, header.uuid, sizeof (header.uuid)) != 0) + { +- if (*iptr != '-') +- *optr++ = *iptr; +- } +- *optr = 0; +- +- if (cargs->search_uuid != NULL && grub_strcasecmp (cargs->search_uuid, uuid) != 0) +- { +- grub_dprintf ("luks", "%s != %s\n", uuid, cargs->search_uuid); ++ grub_dprintf ("luks", "%s != %s\n", header.uuid, cargs->search_uuid); + return NULL; + } + +@@ -123,7 +110,7 @@ configure_ciphers (grub_disk_t disk, grub_cryptomount_args_t cargs) + newdev->source_disk = NULL; + newdev->log_sector_size = GRUB_LUKS1_LOG_SECTOR_SIZE; + newdev->total_sectors = grub_disk_native_sectors (disk) - newdev->offset_sectors; +- grub_memcpy (newdev->uuid, uuid, sizeof (uuid)); ++ grub_memcpy (newdev->uuid, header.uuid, sizeof (header.uuid)); + newdev->modname = "luks"; + + /* Configure the hash used for the AF splitter and HMAC. */ +@@ -143,7 +130,7 @@ configure_ciphers (grub_disk_t disk, grub_cryptomount_args_t cargs) + return NULL; + } + +- COMPILE_TIME_ASSERT (sizeof (newdev->uuid) >= sizeof (uuid)); ++ COMPILE_TIME_ASSERT (sizeof (newdev->uuid) >= sizeof (header.uuid)); + return newdev; + } + +diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c +index bf741d7..ac3ab09 100644 +--- a/grub-core/disk/luks2.c ++++ b/grub-core/disk/luks2.c +@@ -350,8 +350,6 @@ luks2_scan (grub_disk_t disk, grub_cryptomount_args_t cargs) + { + grub_cryptodisk_t cryptodisk; + grub_luks2_header_t header; +- char uuid[sizeof (header.uuid) + 1]; +- grub_size_t i, j; + + if (cargs->check_boot) + return NULL; +@@ -362,14 +360,9 @@ luks2_scan (grub_disk_t disk, grub_cryptomount_args_t cargs) + return NULL; + } + +- for (i = 0, j = 0; i < sizeof (header.uuid); i++) +- if (header.uuid[i] != '-') +- uuid[j++] = header.uuid[i]; +- uuid[j] = '\0'; +- +- if (cargs->search_uuid != NULL && grub_strcasecmp (cargs->search_uuid, uuid) != 0) ++ if (cargs->search_uuid != NULL && grub_uuidcasecmp (cargs->search_uuid, header.uuid, sizeof (header.uuid)) != 0) + { +- grub_dprintf ("luks2", "%s != %s\n", uuid, cargs->search_uuid); ++ grub_dprintf ("luks2", "%s != %s\n", header.uuid, cargs->search_uuid); + return NULL; + } + +@@ -377,8 +370,8 @@ luks2_scan (grub_disk_t disk, grub_cryptomount_args_t cargs) + if (!cryptodisk) + return NULL; + +- COMPILE_TIME_ASSERT (sizeof (cryptodisk->uuid) >= sizeof (uuid)); +- grub_memcpy (cryptodisk->uuid, uuid, sizeof (uuid)); ++ COMPILE_TIME_ASSERT (sizeof (cryptodisk->uuid) >= sizeof (header.uuid)); ++ grub_memcpy (cryptodisk->uuid, header.uuid, sizeof (header.uuid)); + + cryptodisk->modname = "luks2"; + return cryptodisk; +diff --git a/include/grub/misc.h b/include/grub/misc.h +index 8c0ffed..fae4910 100644 +--- a/include/grub/misc.h ++++ b/include/grub/misc.h +@@ -290,6 +290,36 @@ grub_strncasecmp (const char *s1, const char *s2, grub_size_t n) + - (int) grub_tolower ((grub_uint8_t) *s2); + } + ++/* ++ * Do a case insensitive compare of two UUID strings by ignoring all dashes. ++ * Note that the parameter n, is the number of significant characters to ++ * compare, where significant characters are any except the dash. ++ */ ++static inline int ++grub_uuidcasecmp (const char *uuid1, const char *uuid2, grub_size_t n) ++{ ++ if (n == 0) ++ return 0; ++ ++ while (*uuid1 && *uuid2 && --n) ++ { ++ /* Skip forward to non-dash on both UUIDs. */ ++ while ('-' == *uuid1) ++ ++uuid1; ++ ++ while ('-' == *uuid2) ++ ++uuid2; ++ ++ if (grub_tolower ((grub_uint8_t) *uuid1) != grub_tolower ((grub_uint8_t) *uuid2)) ++ break; ++ ++ uuid1++; ++ uuid2++; ++ } ++ ++ return (int) grub_tolower ((grub_uint8_t) *uuid1) - (int) grub_tolower ((grub_uint8_t) *uuid2); ++} ++ + /* + * Note that these differ from the C standard's definitions of strtol, + * strtoul(), and strtoull() by the addition of two const qualifiers on the end diff --git a/0393-disk-cryptodisk-Fix-unintentional-integer-overflow.patch b/0393-disk-cryptodisk-Fix-unintentional-integer-overflow.patch new file mode 100644 index 0000000..1b8806c --- /dev/null +++ b/0393-disk-cryptodisk-Fix-unintentional-integer-overflow.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Alec Brown +Date: Fri, 14 Oct 2022 17:47:08 -0400 +Subject: [PATCH] disk/cryptodisk: Fix unintentional integer overflow + +In the function grub_cryptodisk_endecrypt(), a for loop is incrementing the +variable i by (1U << log_sector_size). The variable i is of type grub_size_t +which is a 64-bit unsigned integer on x86_64 architecture. On the other hand, 1U +is a 32-bit unsigned integer. By performing a left shift on a 32-bit value and +assigning it to a 64-bit variable, the 64-bit variable may have incorrect values +in the high 32-bits if the shift has an overflow. To avoid this, we replace 1U +with (grub_size_t)1. + +Fixes: CID 307788 + +Signed-off-by: Alec Brown +Reviewed-by: Darren Kenny +Reviewed-by: Patrick Steinhardt +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 17b5034..e23c618 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -262,7 +262,7 @@ grub_cryptodisk_endecrypt (struct grub_cryptodisk *dev, + return (do_encrypt ? grub_crypto_ecb_encrypt (dev->cipher, data, data, len) + : grub_crypto_ecb_decrypt (dev->cipher, data, data, len)); + +- for (i = 0; i < len; i += (1U << log_sector_size)) ++ for (i = 0; i < len; i += ((grub_size_t) 1 << log_sector_size)) + { + grub_size_t sz = ((dev->cipher->cipher->blocksize + + sizeof (grub_uint32_t) - 1) diff --git a/0394-disk-cryptodisk-When-cheatmounting-use-the-sector-in.patch b/0394-disk-cryptodisk-When-cheatmounting-use-the-sector-in.patch new file mode 100644 index 0000000..0998559 --- /dev/null +++ b/0394-disk-cryptodisk-When-cheatmounting-use-the-sector-in.patch @@ -0,0 +1,73 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Fabian Vogt +Date: Thu, 12 Jan 2023 17:05:07 -0600 +Subject: [PATCH] disk/cryptodisk: When cheatmounting, use the sector info of + the cheat device + +When using grub-probe with cryptodisk, the mapped block device from the host +is used directly instead of decrypting the source device in GRUB code. +In that case, the sector size and count of the host device needs to be used. +This is especially important when using LUKS2, which does not assign +total_sectors and log_sector_size when scanning, but only later when the +segments in the JSON area are evaluated. With an unset log_sector_size, +grub_device_open() complains. + +This fixes grub-probe failing with +"error: sector sizes of 1 bytes aren't supported yet.". + +Signed-off-by: Fabian Vogt +Reviewed-by: Patrick Steinhardt +Tested-by: Glenn Washburn +Reviewed-by: Glenn Washburn +Reviewed-by: Patrick Steinhardt +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 20 ++++++++++++++++++-- + 1 file changed, 18 insertions(+), 2 deletions(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index e23c618..2384792 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -718,16 +718,31 @@ grub_cryptodisk_open (const char *name, grub_disk_t disk) + if (!dev) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "No such device"); + +- disk->log_sector_size = dev->log_sector_size; +- + #ifdef GRUB_UTIL + if (dev->cheat) + { ++ grub_uint64_t cheat_dev_size; ++ unsigned int cheat_log_sector_size; ++ + if (!GRUB_UTIL_FD_IS_VALID (dev->cheat_fd)) + dev->cheat_fd = grub_util_fd_open (dev->cheat, GRUB_UTIL_FD_O_RDONLY); + if (!GRUB_UTIL_FD_IS_VALID (dev->cheat_fd)) + return grub_error (GRUB_ERR_IO, N_("cannot open `%s': %s"), + dev->cheat, grub_util_fd_strerror ()); ++ ++ /* Use the sector size and count of the cheat device. */ ++ cheat_dev_size = grub_util_get_fd_size (dev->cheat_fd, dev->cheat, &cheat_log_sector_size); ++ if (cheat_dev_size == -1) ++ { ++ const char *errmsg = grub_util_fd_strerror (); ++ grub_util_fd_close (dev->cheat_fd); ++ dev->cheat_fd = GRUB_UTIL_FD_INVALID; ++ return grub_error (GRUB_ERR_IO, N_("failed to query size of device `%s': %s"), ++ dev->cheat, errmsg); ++ } ++ ++ dev->log_sector_size = cheat_log_sector_size; ++ dev->total_sectors = cheat_dev_size >> cheat_log_sector_size; + } + #endif + +@@ -741,6 +756,7 @@ grub_cryptodisk_open (const char *name, grub_disk_t disk) + } + + disk->data = dev; ++ disk->log_sector_size = dev->log_sector_size; + disk->total_sectors = dev->total_sectors; + disk->max_agglomerate = GRUB_DISK_MAX_MAX_AGGLOMERATE; + disk->id = dev->id; diff --git a/0395-disk-cryptodisk-Fix-missing-change-when-updating-to-.patch b/0395-disk-cryptodisk-Fix-missing-change-when-updating-to-.patch new file mode 100644 index 0000000..3102d48 --- /dev/null +++ b/0395-disk-cryptodisk-Fix-missing-change-when-updating-to-.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Fri, 18 Aug 2023 12:27:22 -0500 +Subject: [PATCH] disk/cryptodisk: Fix missing change when updating to use + grub_uuidcasecmp() + +This was causing the cryptomount command to return failure even though +the crypto device was successfully added. Of course, this meant that any +script using the return code would behave unexpectedly. + +Fixes: 3cf2e848bc03 (disk/cryptodisk: Allows UUIDs to be compared in a dash-insensitive manner) + +Suggested-by: Olaf Hering +Signed-off-by: Glenn Washburn +Reviewed-by: Patrich Steinhardt +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 2384792..bbe39a8 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -1236,7 +1236,8 @@ grub_cryptodisk_scan_device (const char *name, + dev = grub_cryptodisk_scan_device_real (name, source, cargs); + if (dev) + { +- ret = (cargs->search_uuid != NULL && grub_strcasecmp (cargs->search_uuid, dev->uuid) == 0); ++ ret = (cargs->search_uuid != NULL ++ && grub_uuidcasecmp (cargs->search_uuid, dev->uuid, sizeof (dev->uuid)) == 0); + goto cleanup; + } + diff --git a/0396-disk-cryptodisk-Optimize-luks_script_get.patch b/0396-disk-cryptodisk-Optimize-luks_script_get.patch new file mode 100644 index 0000000..1d7f78a --- /dev/null +++ b/0396-disk-cryptodisk-Optimize-luks_script_get.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Fri, 14 Jul 2023 15:49:17 -0500 +Subject: [PATCH] disk/cryptodisk: Optimize luks_script_get() + +Use the return value of grub_snprintf() to move the string pointer forward, +instead of incrementing the string pointer iteratively until a NULL byte is +reached. Move the space out of the format string argument, a small +optimization, but also makes the spacing clearer. Also, use the new +PRIxGRUB_OFFSET instead of PRIuGRUB_UINT64_T to accurately reflect the +format string for this type. + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index bbe39a8..751fe9b 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -1504,9 +1504,8 @@ luks_script_get (grub_size_t *sz) + ptr = grub_stpcpy (ptr, "luks_mount "); + ptr = grub_stpcpy (ptr, i->uuid); + *ptr++ = ' '; +- grub_snprintf (ptr, 21, "%" PRIuGRUB_UINT64_T " ", i->offset_sectors); +- while (*ptr) +- ptr++; ++ ptr += grub_snprintf (ptr, 21, "%" PRIxGRUB_OFFSET, i->offset_sectors); ++ *ptr++ = ' '; + for (iptr = i->cipher->cipher->name; *iptr; iptr++) + *ptr++ = grub_tolower (*iptr); + switch (i->mode) diff --git a/0397-disk-cryptodisk-Add-support-for-LUKS2-in-proc-luks_s.patch b/0397-disk-cryptodisk-Add-support-for-LUKS2-in-proc-luks_s.patch new file mode 100644 index 0000000..5e1fc64 --- /dev/null +++ b/0397-disk-cryptodisk-Add-support-for-LUKS2-in-proc-luks_s.patch @@ -0,0 +1,69 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Fri, 14 Jul 2023 15:49:18 -0500 +Subject: [PATCH] disk/cryptodisk: Add support for LUKS2 in (proc)/luks_script + +The sector size in bytes is added to each line and it is allowed to be +6 decimal digits long, which covers the most common cases of 512 and 4096 +byte sectors with space for two additional digits as future-proofing. The +size allocation is updated to reflect this additional field. Also make +clearer the size allocation calculation. + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 24 +++++++++++++++++++----- + 1 file changed, 19 insertions(+), 5 deletions(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 751fe9b..49af8a9 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -1479,12 +1479,22 @@ luks_script_get (grub_size_t *sz) + *sz = 0; + + for (i = cryptodisk_list; i != NULL; i = i->next) +- if (grub_strcmp (i->modname, "luks") == 0) ++ if (grub_strcmp (i->modname, "luks") == 0 || ++ grub_strcmp (i->modname, "luks2") == 0) + { +- size += sizeof ("luks_mount "); ++ size += grub_strlen (i->modname); ++ size += sizeof ("_mount"); + size += grub_strlen (i->uuid); + size += grub_strlen (i->cipher->cipher->name); +- size += 54; ++ /* ++ * Add space in the line for (in order) spaces, cipher mode, cipher IV ++ * mode, sector offset, sector size and the trailing newline. This is ++ * an upper bound on the size of this data. There are 15 extra bytes ++ * in an earlier version of this code that are unaccounted for. It is ++ * left in the calculations in case it is needed. At worst, its short- ++ * lived wasted space. ++ */ ++ size += 5 + 5 + 8 + 20 + 6 + 1 + 15; + if (i->essiv_hash) + size += grub_strlen (i->essiv_hash->name); + size += i->keysize * 2; +@@ -1497,15 +1507,19 @@ luks_script_get (grub_size_t *sz) + ptr = ret; + + for (i = cryptodisk_list; i != NULL; i = i->next) +- if (grub_strcmp (i->modname, "luks") == 0) ++ if (grub_strcmp (i->modname, "luks") == 0 || ++ grub_strcmp (i->modname, "luks2") == 0) + { + unsigned j; + const char *iptr; +- ptr = grub_stpcpy (ptr, "luks_mount "); ++ ptr = grub_stpcpy (ptr, i->modname); ++ ptr = grub_stpcpy (ptr, "_mount "); + ptr = grub_stpcpy (ptr, i->uuid); + *ptr++ = ' '; + ptr += grub_snprintf (ptr, 21, "%" PRIxGRUB_OFFSET, i->offset_sectors); + *ptr++ = ' '; ++ ptr += grub_snprintf (ptr, 7, "%u", 1 << i->log_sector_size); ++ *ptr++ = ' '; + for (iptr = i->cipher->cipher->name; *iptr; iptr++) + *ptr++ = grub_tolower (*iptr); + switch (i->mode) diff --git a/0398-disk-cryptodisk-Require-authentication-after-TPM-unl.patch b/0398-disk-cryptodisk-Require-authentication-after-TPM-unl.patch new file mode 100644 index 0000000..27e56b1 --- /dev/null +++ b/0398-disk-cryptodisk-Require-authentication-after-TPM-unl.patch @@ -0,0 +1,337 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Tue, 11 Feb 2025 15:08:06 -0600 +Subject: [PATCH] disk/cryptodisk: Require authentication after TPM unlock for + CLI access + +The GRUB may use TPM to verify the integrity of boot components and the +result can determine whether a previously sealed key can be released. If +everything checks out, showing nothing has been tampered with, the key +is released and GRUB unlocks the encrypted root partition for the next +stage of booting. + +However, the liberal Command Line Interface (CLI) can be misused by +anyone in this case to access files in the encrypted partition one way +or another. Despite efforts to keep the CLI secure by preventing utility +command output from leaking file content, many techniques in the wild +could still be used to exploit the CLI, enabling attacks or learning +methods to attack. It's nearly impossible to account for all scenarios +where a hack could be applied. + +Therefore, to mitigate potential misuse of the CLI after the root device +has been successfully unlocked via TPM, the user should be required to +authenticate using the LUKS password. This added layer of security +ensures that only authorized users can access the CLI reducing the risk +of exploitation or unauthorized access to the encrypted partition. + +Fixes: CVE-2024-49504 + +Signed-off-by: Michael Chang +Reviewed-by: Daniel Kiper +--- + docs/grub.texi | 29 +++++++++++++++ + grub-core/disk/cryptodisk.c | 87 ++++++++++++++++++++++++++++++++++++++++++- + grub-core/kern/main.c | 12 ++++++ + grub-core/normal/auth.c | 30 +++++++++++++++ + grub-core/normal/main.c | 4 ++ + grub-core/normal/menu_entry.c | 4 ++ + include/grub/auth.h | 1 + + include/grub/cryptodisk.h | 3 ++ + include/grub/misc.h | 2 + + 9 files changed, 171 insertions(+), 1 deletion(-) + +diff --git a/docs/grub.texi b/docs/grub.texi +index 3c7d99e..d3faecb 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -6312,6 +6312,35 @@ sign-file SHA256 grub.key certificate.der core.elf.unsigned core.elf.signed + As with UEFI secure boot, it is necessary to build in the required modules, + or sign them separately. + ++@subsection Command line and menuentry editor protection ++ ++The TPM key protector provides full disk encryption support on servers or ++virtual machine images, meanwhile keeping the boot process unattended. This ++prevents service disruptions by eliminating the need for manual password input ++during startup, improving system uptime and continuity. It is achieved by TPM, ++which verifies the integrity of boot components by checking cryptographic ++hashes against securely stored values, to confirm the disks are unlocked in a ++trusted state. ++ ++However, for users to access the system interactively, some form of ++authentication is still required, as the disks are not unlocked by an ++authorized user. This raised concerns about using an unprotected ++@samp{command-line interface} (@pxref{Command-line interface}), as anyone could ++execute commands to access decrypted data. To address this issue, the LUKS ++password is used to ensure that only authorized users are granted access to the ++interface. Additionally, the @samp{menu entry editor} (@pxref{Menu entry ++editor}) is also safeguarded by the LUKS password, as modifying a boot entry is ++effectively the same as altering the @file{grub.cfg} file read from encrypted ++files. ++ ++It is worth mentioning that the built-in password support, as described in ++@samp{Authentication and Authorization in GRUB} (@pxref{Authentication and ++authorisation}), can also be used to protect the command-line interface from ++unauthorized access. However, it is not recommended to rely on this approach as ++it is an optional step. Setting it up requires additional manual intervention, ++which increases the risk of password leakage during the process. Moreover, the ++superuser list must be well maintained, and the password used cannot be ++synchronized with LUKS key rotation. + + @node Platform limitations + @chapter Platform limitations +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 49af8a9..9c456c2 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -1144,7 +1144,9 @@ grub_cryptodisk_scan_device_real (const char *name, + ret = grub_cryptodisk_insert (dev, name, source); + if (ret != GRUB_ERR_NONE) + goto error; +- ++#ifndef GRUB_UTIL ++ grub_cli_set_auth_needed (); ++#endif + goto cleanup; + } + grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk module can handle this device"); +@@ -1576,6 +1578,89 @@ luks_script_get (grub_size_t *sz) + return ret; + } + ++#ifdef GRUB_MACHINE_EFI ++grub_err_t ++grub_cryptodisk_challenge_password (void) ++{ ++ grub_cryptodisk_t cr_dev; ++ ++ for (cr_dev = cryptodisk_list; cr_dev != NULL; cr_dev = cr_dev->next) ++ { ++ grub_cryptodisk_dev_t cr; ++ grub_disk_t source = NULL; ++ grub_err_t ret = GRUB_ERR_NONE; ++ grub_cryptodisk_t dev = NULL; ++ char *part = NULL; ++ struct grub_cryptomount_args cargs = {0}; ++ ++ cargs.check_boot = 0; ++ cargs.search_uuid = cr_dev->uuid; ++ ++ source = grub_disk_open (cr_dev->source); ++ ++ if (source == NULL) ++ { ++ ret = grub_errno; ++ goto error_out; ++ } ++ ++ FOR_CRYPTODISK_DEVS (cr) ++ { ++ dev = cr->scan (source, &cargs); ++ if (grub_errno) ++ { ++ ret = grub_errno; ++ goto error_out; ++ } ++ if (dev == NULL) ++ continue; ++ break; ++ } ++ ++ if (dev == NULL) ++ { ++ ret = grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk module can handle this device"); ++ goto error_out; ++ } ++ ++ part = grub_partition_get_name (source->partition); ++ grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name, ++ source->partition != NULL ? "," : "", ++ part != NULL ? part : N_("UNKNOWN"), cr_dev->uuid); ++ grub_free (part); ++ ++ cargs.key_data = grub_malloc (GRUB_CRYPTODISK_MAX_PASSPHRASE); ++ if (cargs.key_data == NULL) ++ { ++ ret = grub_errno; ++ goto error_out; ++ } ++ ++ if (!grub_password_get ((char *) cargs.key_data, GRUB_CRYPTODISK_MAX_PASSPHRASE)) ++ { ++ ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "passphrase not supplied"); ++ goto error_out; ++ } ++ cargs.key_len = grub_strlen ((char *) cargs.key_data); ++ ret = cr->recover_key (source, dev, &cargs); ++ ++ error_out: ++ grub_disk_close (source); ++ if (dev != NULL) ++ cryptodisk_close (dev); ++ if (cargs.key_data) ++ { ++ grub_memset (cargs.key_data, 0, cargs.key_len); ++ grub_free (cargs.key_data); ++ } ++ ++ return ret; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++#endif /* GRUB_MACHINE_EFI */ ++ + struct grub_procfs_entry luks_script = + { + .name = "luks_script", +diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c +index e4d4bf6..0a4a8d8 100644 +--- a/grub-core/kern/main.c ++++ b/grub-core/kern/main.c +@@ -37,6 +37,7 @@ + #endif + + static bool cli_disabled = false; ++static bool cli_need_auth = false; + + grub_addr_t + grub_modules_get_end (void) +@@ -308,6 +309,17 @@ grub_is_cli_disabled (void) + return cli_disabled; + } + ++bool ++grub_is_cli_need_auth (void) ++{ ++ return cli_need_auth; ++} ++ ++void grub_cli_set_auth_needed (void) ++{ ++ cli_need_auth = true; ++} ++ + static void + check_is_cli_disabled (void) + { +diff --git a/grub-core/normal/auth.c b/grub-core/normal/auth.c +index 53f2d72..075aba4 100644 +--- a/grub-core/normal/auth.c ++++ b/grub-core/normal/auth.c +@@ -25,6 +25,10 @@ + #include + #include + ++#ifdef GRUB_MACHINE_EFI ++#include ++#endif ++ + struct grub_auth_user + { + struct grub_auth_user *next; +@@ -200,6 +204,32 @@ grub_username_get (char buf[], unsigned buf_size) + return (key != GRUB_TERM_ESC); + } + ++grub_err_t ++grub_auth_check_cli_access (void) ++{ ++ if (grub_is_cli_need_auth () == true) ++ { ++#ifdef GRUB_MACHINE_EFI ++ static bool authenticated = false; ++ ++ if (authenticated == false) ++ { ++ grub_err_t ret; ++ ++ ret = grub_cryptodisk_challenge_password (); ++ if (ret == GRUB_ERR_NONE) ++ authenticated = true; ++ return ret; ++ } ++ return GRUB_ERR_NONE; ++#else ++ return GRUB_ACCESS_DENIED; ++#endif ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ + grub_err_t + grub_auth_check_authentication (const char *userlist) + { +diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c +index bac7b8a..6f6e4a8 100644 +--- a/grub-core/normal/main.c ++++ b/grub-core/normal/main.c +@@ -556,9 +556,13 @@ grub_cmdline_run (int nested, int force_auth) + } + while (err && force_auth); + ++ if (err == GRUB_ERR_NONE) ++ err = grub_auth_check_cli_access (); ++ + if (err) + { + grub_print_error (); ++ grub_wait_after_message (); + grub_errno = GRUB_ERR_NONE; + return; + } +diff --git a/grub-core/normal/menu_entry.c b/grub-core/normal/menu_entry.c +index 50eef91..150a800 100644 +--- a/grub-core/normal/menu_entry.c ++++ b/grub-core/normal/menu_entry.c +@@ -1255,9 +1255,13 @@ grub_menu_entry_run (grub_menu_entry_t entry) + + err = grub_auth_check_authentication (NULL); + ++ if (err == GRUB_ERR_NONE) ++ err = grub_auth_check_cli_access (); ++ + if (err) + { + grub_print_error (); ++ grub_wait_after_message (); + grub_errno = GRUB_ERR_NONE; + return; + } +diff --git a/include/grub/auth.h b/include/grub/auth.h +index 7473344..21d5190 100644 +--- a/include/grub/auth.h ++++ b/include/grub/auth.h +@@ -33,5 +33,6 @@ grub_err_t grub_auth_unregister_authentication (const char *user); + grub_err_t grub_auth_authenticate (const char *user); + grub_err_t grub_auth_deauthenticate (const char *user); + grub_err_t grub_auth_check_authentication (const char *userlist); ++grub_err_t grub_auth_check_cli_access (void); + + #endif /* ! GRUB_AUTH_HEADER */ +diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h +index d94df68..d2572f8 100644 +--- a/include/grub/cryptodisk.h ++++ b/include/grub/cryptodisk.h +@@ -187,4 +187,7 @@ grub_util_get_geli_uuid (const char *dev); + grub_cryptodisk_t grub_cryptodisk_get_by_uuid (const char *uuid); + grub_cryptodisk_t grub_cryptodisk_get_by_source_disk (grub_disk_t disk); + ++#ifdef GRUB_MACHINE_EFI ++grub_err_t grub_cryptodisk_challenge_password (void); ++#endif + #endif +diff --git a/include/grub/misc.h b/include/grub/misc.h +index fae4910..77d9f56 100644 +--- a/include/grub/misc.h ++++ b/include/grub/misc.h +@@ -440,6 +440,8 @@ grub_uint64_t EXPORT_FUNC(grub_divmod64) (grub_uint64_t n, + grub_uint64_t *r); + + extern bool EXPORT_FUNC(grub_is_cli_disabled) (void); ++extern bool EXPORT_FUNC(grub_is_cli_need_auth) (void); ++extern void EXPORT_FUNC(grub_cli_set_auth_needed) (void); + + /* Must match softdiv group in gentpl.py. */ + #if !defined(GRUB_MACHINE_EMU) && (defined(__arm__) || defined(__ia64__) || \ diff --git a/0399-disk-loopback-Reference-tracking-for-the-loopback.patch b/0399-disk-loopback-Reference-tracking-for-the-loopback.patch new file mode 100644 index 0000000..f69a0b0 --- /dev/null +++ b/0399-disk-loopback-Reference-tracking-for-the-loopback.patch @@ -0,0 +1,108 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: B Horn +Date: Tue, 11 Feb 2025 15:22:28 -0600 +Subject: [PATCH] disk/loopback: Reference tracking for the loopback + +It was possible to delete a loopback while there were still references +to it. This led to an exploitable use-after-free. + +Fixed by implementing a reference counting in the grub_loopback struct. + +Reported-by: B Horn +Signed-off-by: B Horn +Reviewed-by: Daniel Kiper +--- + grub-core/disk/loopback.c | 17 +++++++++++++++++ + include/grub/err.h | 3 ++- + include/grub/loopback.h | 1 + + 3 files changed, 20 insertions(+), 1 deletion(-) + +diff --git a/grub-core/disk/loopback.c b/grub-core/disk/loopback.c +index 99f4792..93026c5 100644 +--- a/grub-core/disk/loopback.c ++++ b/grub-core/disk/loopback.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -56,6 +57,8 @@ delete_loopback (const char *name) + if (! dev) + return grub_error (GRUB_ERR_BAD_DEVICE, "device not found"); + ++ if (dev->refcnt > 0) ++ return grub_error (GRUB_ERR_STILL_REFERENCED, "device still referenced"); + /* Remove the device from the list. */ + *prev = dev->next; + +@@ -109,6 +112,7 @@ grub_cmd_loopback (grub_extcmd_context_t ctxt, int argc, char **args) + + newdev->file = file; + newdev->id = last_id++; ++ newdev->refcnt = 0; + + /* Add the new entry to the list. */ + newdev->next = loopback_list; +@@ -150,6 +154,9 @@ grub_loopback_open (const char *name, grub_disk_t disk) + if (! dev) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); + ++ if (grub_add (dev->refcnt, 1, &dev->refcnt)) ++ grub_fatal ("Reference count overflow"); ++ + /* Use the filesize for the disk size, round up to a complete sector. */ + if (dev->file->size != GRUB_FILE_SIZE_UNKNOWN) + disk->total_sectors = ((dev->file->size + GRUB_DISK_SECTOR_SIZE - 1) +@@ -167,6 +174,15 @@ grub_loopback_open (const char *name, grub_disk_t disk) + return 0; + } + ++static void ++grub_loopback_close (grub_disk_t disk) ++{ ++ struct grub_loopback *dev = disk->data; ++ ++ if (grub_sub (dev->refcnt, 1, &dev->refcnt)) ++ grub_fatal ("Reference count underflow"); ++} ++ + static grub_err_t + grub_loopback_read (grub_disk_t disk, grub_disk_addr_t sector, + grub_size_t size, char *buf) +@@ -209,6 +225,7 @@ static struct grub_disk_dev grub_loopback_dev = + .id = GRUB_DISK_DEVICE_LOOPBACK_ID, + .disk_iterate = grub_loopback_iterate, + .disk_open = grub_loopback_open, ++ .disk_close = grub_loopback_close, + .disk_read = grub_loopback_read, + .disk_write = grub_loopback_write, + .next = 0 +diff --git a/include/grub/err.h b/include/grub/err.h +index c0f90ef..4b903df 100644 +--- a/include/grub/err.h ++++ b/include/grub/err.h +@@ -72,7 +72,8 @@ typedef enum + GRUB_ERR_NET_PACKET_TOO_BIG, + GRUB_ERR_NET_NO_DOMAIN, + GRUB_ERR_EOF, +- GRUB_ERR_BAD_SIGNATURE ++ GRUB_ERR_BAD_SIGNATURE, ++ GRUB_ERR_STILL_REFERENCED + } + grub_err_t; + +diff --git a/include/grub/loopback.h b/include/grub/loopback.h +index 3b9a9e3..915ef65 100644 +--- a/include/grub/loopback.h ++++ b/include/grub/loopback.h +@@ -25,6 +25,7 @@ struct grub_loopback + grub_file_t file; + struct grub_loopback *next; + unsigned long id; ++ grub_uint64_t refcnt; + }; + + #endif /* ! GRUB_LOOPBACK_HEADER */ diff --git a/0400-kern-disk-Limit-recursion-depth.patch b/0400-kern-disk-Limit-recursion-depth.patch new file mode 100644 index 0000000..b7d1dac --- /dev/null +++ b/0400-kern-disk-Limit-recursion-depth.patch @@ -0,0 +1,120 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: B Horn +Date: Sun, 12 May 2024 04:09:24 +0100 +Subject: [PATCH] kern/disk: Limit recursion depth + +The grub_disk_read() may trigger other disk reads, e.g. via loopbacks. +This may lead to very deep recursion which can corrupt the heap. So, fix +the issue by limiting reads depth. + +Reported-by: B Horn +Signed-off-by: B Horn +Reviewed-by: Daniel Kiper +--- + grub-core/kern/disk.c | 27 ++++++++++++++++++++------- + include/grub/err.h | 3 ++- + 2 files changed, 22 insertions(+), 8 deletions(-) + +diff --git a/grub-core/kern/disk.c b/grub-core/kern/disk.c +index 05a28ab..60f6ad2 100644 +--- a/grub-core/kern/disk.c ++++ b/grub-core/kern/disk.c +@@ -28,6 +28,10 @@ + + #define GRUB_CACHE_TIMEOUT 2 + ++/* Disk reads may trigger other disk reads. So, limit recursion depth. */ ++#define MAX_READ_RECURSION_DEPTH 16 ++static unsigned int read_recursion_depth = 0; ++ + /* The last time the disk was used. */ + static grub_uint64_t grub_last_time = 0; + +@@ -417,6 +421,8 @@ grub_err_t + grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector, + grub_off_t offset, grub_size_t size, void *buf) + { ++ grub_err_t err = GRUB_ERR_NONE; ++ + /* First of all, check if the region is within the disk. */ + if (grub_disk_adjust_range (disk, §or, &offset, size) != GRUB_ERR_NONE) + { +@@ -427,12 +433,17 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector, + return grub_errno; + } + ++ if (++read_recursion_depth >= MAX_READ_RECURSION_DEPTH) ++ { ++ grub_error (GRUB_ERR_RECURSION_DEPTH, "grub_disk_read(): Maximum recursion depth exceeded"); ++ goto error; ++ } ++ + /* First read until first cache boundary. */ + if (offset || (sector & (GRUB_DISK_CACHE_SIZE - 1))) + { + grub_disk_addr_t start_sector; + grub_size_t pos; +- grub_err_t err; + grub_size_t len; + + start_sector = sector & ~((grub_disk_addr_t) GRUB_DISK_CACHE_SIZE - 1); +@@ -444,7 +455,7 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector, + err = grub_disk_read_small (disk, start_sector, + offset + pos, len, buf); + if (err) +- return err; ++ goto error; + buf = (char *) buf + len; + size -= len; + offset += len; +@@ -457,7 +468,6 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector, + { + char *data = NULL; + grub_disk_addr_t agglomerate; +- grub_err_t err; + + /* agglomerate read until we find a first cached entry. */ + for (agglomerate = 0; agglomerate +@@ -493,7 +503,7 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector, + - disk->log_sector_size), + buf); + if (err) +- return err; ++ goto error; + + for (i = 0; i < agglomerate; i ++) + grub_disk_cache_store (disk->dev->id, disk->id, +@@ -527,13 +537,16 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector, + /* And now read the last part. */ + if (size) + { +- grub_err_t err; + err = grub_disk_read_small (disk, sector, 0, size, buf); + if (err) +- return err; ++ goto error; + } + +- return grub_errno; ++ err = grub_errno; ++ ++ error: ++ read_recursion_depth--; ++ return err; + } + + grub_uint64_t +diff --git a/include/grub/err.h b/include/grub/err.h +index 4b903df..905a6df 100644 +--- a/include/grub/err.h ++++ b/include/grub/err.h +@@ -73,7 +73,8 @@ typedef enum + GRUB_ERR_NET_NO_DOMAIN, + GRUB_ERR_EOF, + GRUB_ERR_BAD_SIGNATURE, +- GRUB_ERR_STILL_REFERENCED ++ GRUB_ERR_STILL_REFERENCED, ++ GRUB_ERR_RECURSION_DEPTH + } + grub_err_t; + diff --git a/0401-kern-partition-Limit-recursion-in-part_iterate.patch b/0401-kern-partition-Limit-recursion-in-part_iterate.patch new file mode 100644 index 0000000..60b0255 --- /dev/null +++ b/0401-kern-partition-Limit-recursion-in-part_iterate.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: B Horn +Date: Sat, 16 Nov 2024 21:24:19 +0000 +Subject: [PATCH] kern/partition: Limit recursion in part_iterate() + +The part_iterate() is used by grub_partition_iterate() as a callback in +the partition iterate functions. However, part_iterate() may also call +the partition iterate functions which may lead to recursion. Fix potential +issue by limiting the recursion depth. + +Signed-off-by: B Horn +Reviewed-by: Daniel Kiper +--- + grub-core/kern/partition.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/grub-core/kern/partition.c b/grub-core/kern/partition.c +index 3068c4dca..f3f125e75 100644 +--- a/grub-core/kern/partition.c ++++ b/grub-core/kern/partition.c +@@ -28,6 +28,9 @@ + + grub_partition_map_t grub_partition_map_list; + ++#define MAX_RECURSION_DEPTH 32 ++static unsigned int recursion_depth = 0; ++ + /* + * Checks that disk->partition contains part. This function assumes that the + * start of part is relative to the start of disk->partition. Returns 1 if +@@ -208,7 +211,12 @@ part_iterate (grub_disk_t dsk, const grub_partition_t partition, void *data) + FOR_PARTITION_MAPS(partmap) + { + grub_err_t err; +- err = partmap->iterate (dsk, part_iterate, ctx); ++ recursion_depth++; ++ if (recursion_depth <= MAX_RECURSION_DEPTH) ++ err = partmap->iterate (dsk, part_iterate, ctx); ++ else ++ err = grub_error (GRUB_ERR_RECURSION_DEPTH, "maximum recursion depth exceeded"); ++ recursion_depth--; + if (err) + grub_errno = GRUB_ERR_NONE; + if (ctx->ret) diff --git a/0402-script-execute-Limit-the-recursion-depth.patch b/0402-script-execute-Limit-the-recursion-depth.patch new file mode 100644 index 0000000..dd3c033 --- /dev/null +++ b/0402-script-execute-Limit-the-recursion-depth.patch @@ -0,0 +1,55 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: B Horn +Date: Thu, 18 Apr 2024 19:04:13 +0100 +Subject: [PATCH] script/execute: Limit the recursion depth + +If unbounded recursion is allowed it becomes possible to collide the +stack with the heap. As UEFI firmware often lacks guard pages this +becomes an exploitable issue as it is possible in some cases to do +a controlled overwrite of a section of this heap region with +arbitrary data. + +Reported-by: B Horn +Signed-off-by: B Horn +Reviewed-by: Daniel Kiper +--- + grub-core/script/execute.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c +index 0c6dd9c52..c383eb87c 100644 +--- a/grub-core/script/execute.c ++++ b/grub-core/script/execute.c +@@ -36,10 +36,18 @@ + is sizeof (int) * 3, and one extra for a possible -ve sign. */ + #define ERRNO_DIGITS_MAX (sizeof (int) * 3 + 1) + ++/* ++ * A limit on recursion, to avoid colliding with the heap. UEFI defines a baseline ++ * stack size of 128 KiB. So, assuming at most 1-2 KiB per iteration this should ++ * keep us safe. ++ */ ++#define MAX_RECURSION_DEPTH 64 ++ + static unsigned long is_continue; + static unsigned long active_loops; + static unsigned long active_breaks; + static unsigned long function_return; ++static unsigned long recursion_depth; + + #define GRUB_SCRIPT_SCOPE_MALLOCED 1 + #define GRUB_SCRIPT_SCOPE_ARGS_MALLOCED 2 +@@ -850,7 +858,13 @@ grub_script_execute_cmd (struct grub_script_cmd *cmd) + if (cmd == 0) + return 0; + ++ recursion_depth++; ++ ++ if (recursion_depth >= MAX_RECURSION_DEPTH) ++ return grub_error (GRUB_ERR_RECURSION_DEPTH, N_("maximum recursion depth exceeded")); ++ + ret = cmd->exec (cmd); ++ recursion_depth--; + + grub_snprintf (errnobuf, sizeof (errnobuf), "%d", ret); + grub_env_set ("?", errnobuf); diff --git a/0403-net-Unregister-net_default_ip-and-net_default_mac-va.patch b/0403-net-Unregister-net_default_ip-and-net_default_mac-va.patch new file mode 100644 index 0000000..7c6ea2f --- /dev/null +++ b/0403-net-Unregister-net_default_ip-and-net_default_mac-va.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: B Horn +Date: Tue, 11 Feb 2025 15:27:10 -0600 +Subject: [PATCH] net: Unregister net_default_ip and net_default_mac variables + hooks on unload + +The net module is a dependency of normal. So, it shouldn't be possible +to unload the net. Though unregister variables hooks as a precaution. +It also gets in line with unregistering the other net module hooks. + +Signed-off-by: B Horn +Reviewed-by: Daniel Kiper +--- + grub-core/net/net.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/grub-core/net/net.c b/grub-core/net/net.c +index 1001c611d..fd78f09b0 100644 +--- a/grub-core/net/net.c ++++ b/grub-core/net/net.c +@@ -2166,6 +2166,8 @@ GRUB_MOD_FINI(net) + + grub_register_variable_hook ("net_default_server", 0, 0); + grub_register_variable_hook ("pxe_default_server", 0, 0); ++ grub_register_variable_hook ("net_default_ip", 0, 0); ++ grub_register_variable_hook ("net_default_mac", 0, 0); + + grub_bootp_fini (); + grub_dns_fini (); diff --git a/0404-net-Remove-variables-hooks-when-interface-is-unregis.patch b/0404-net-Remove-variables-hooks-when-interface-is-unregis.patch new file mode 100644 index 0000000..1cb4b2a --- /dev/null +++ b/0404-net-Remove-variables-hooks-when-interface-is-unregis.patch @@ -0,0 +1,84 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: B Horn +Date: Tue, 11 Feb 2025 15:42:44 -0600 +Subject: [PATCH] net: Remove variables hooks when interface is unregisted + +The grub_net_network_level_interface_unregister(), previously +implemented in a header, did not remove the variables hooks that +were registered in grub_net_network_level_interface_register(). +Fix this by implementing the same logic used to register the +variables and move the function into the grub-core/net/net.c. + +Signed-off-by: B Horn +Reviewed-by: Daniel Kiper +--- + grub-core/net/net.c | 33 +++++++++++++++++++++++++++++++++ + include/grub/net.h | 11 +---------- + 2 files changed, 34 insertions(+), 10 deletions(-) + +diff --git a/grub-core/net/net.c b/grub-core/net/net.c +index fd78f09b0..251286227 100644 +--- a/grub-core/net/net.c ++++ b/grub-core/net/net.c +@@ -1051,6 +1051,39 @@ grub_net_add_ipv6_local (struct grub_net_network_level_interface *inter, + return 0; + } + ++void ++grub_net_network_level_interface_unregister (struct grub_net_network_level_interface *inter) ++{ ++ char *name; ++ ++ { ++ char buf[GRUB_NET_MAX_STR_HWADDR_LEN]; ++ ++ grub_net_hwaddr_to_str (&inter->hwaddress, buf); ++ name = grub_xasprintf ("net_%s_mac", inter->name); ++ if (name != NULL) ++ grub_register_variable_hook (name, NULL, NULL); ++ grub_free (name); ++ } ++ ++ { ++ char buf[GRUB_NET_MAX_STR_ADDR_LEN]; ++ ++ grub_net_addr_to_str (&inter->address, buf); ++ name = grub_xasprintf ("net_%s_ip", inter->name); ++ if (name != NULL) ++ grub_register_variable_hook (name, NULL, NULL); ++ grub_free (name); ++ } ++ ++ inter->card->num_ifaces--; ++ *inter->prev = inter->next; ++ if (inter->next) ++ inter->next->prev = inter->prev; ++ inter->next = 0; ++ inter->prev = 0; ++} ++ + grub_err_t + grub_net_add_ipv4_local (struct grub_net_network_level_interface *inter, + int mask) +diff --git a/include/grub/net.h b/include/grub/net.h +index 9e4898cc6..43eba9216 100644 +--- a/include/grub/net.h ++++ b/include/grub/net.h +@@ -618,16 +618,7 @@ void grub_bootp_fini (void); + void grub_dns_init (void); + void grub_dns_fini (void); + +-static inline void +-grub_net_network_level_interface_unregister (struct grub_net_network_level_interface *inter) +-{ +- inter->card->num_ifaces--; +- *inter->prev = inter->next; +- if (inter->next) +- inter->next->prev = inter->prev; +- inter->next = 0; +- inter->prev = 0; +-} ++void grub_net_network_level_interface_unregister (struct grub_net_network_level_interface *inter); + + void + grub_net_tcp_retransmit (void); diff --git a/0405-net-Fix-OOB-write-in-grub_net_search_config_file.patch b/0405-net-Fix-OOB-write-in-grub_net_search_config_file.patch new file mode 100644 index 0000000..278ad4d --- /dev/null +++ b/0405-net-Fix-OOB-write-in-grub_net_search_config_file.patch @@ -0,0 +1,79 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: B Horn +Date: Tue, 11 Feb 2025 16:38:44 -0600 +Subject: [PATCH] net: Fix OOB write in grub_net_search_config_file() + +The function included a call to grub_strcpy() which copied data from an +environment variable to a buffer allocated in grub_cmd_normal(). The +grub_cmd_normal() didn't consider the length of the environment variable. +So, the copy operation could exceed the allocation and lead to an OOB +write. Fix the issue by replacing grub_strcpy() with grub_strlcpy() and +pass the underlying buffers size to the grub_net_search_config_file(). + +Fixes: CVE-2025-0624 + +Signed-off-by: B Horn +Reviewed-by: Daniel Kiper +--- + grub-core/net/net.c | 7 ++++--- + grub-core/normal/main.c | 2 +- + include/grub/net.h | 2 +- + 3 files changed, 6 insertions(+), 5 deletions(-) + +diff --git a/grub-core/net/net.c b/grub-core/net/net.c +index 251286227..6c0bd00b4 100644 +--- a/grub-core/net/net.c ++++ b/grub-core/net/net.c +@@ -1971,14 +1971,15 @@ grub_config_search_through (char *config, char *suffix, + } + + grub_err_t +-grub_net_search_config_file (char *config) ++grub_net_search_config_file (char *config, grub_size_t config_buf_len) + { +- grub_size_t config_len; ++ grub_size_t config_len, suffix_len; + char *suffix; + + config_len = grub_strlen (config); + config[config_len] = '-'; + suffix = config + config_len + 1; ++ suffix_len = config_buf_len - (config_len + 1); + + struct grub_net_network_level_interface *inf; + FOR_NET_NETWORK_LEVEL_INTERFACES (inf) +@@ -2004,7 +2005,7 @@ grub_net_search_config_file (char *config) + + if (client_uuid) + { +- grub_strcpy (suffix, client_uuid); ++ grub_strlcpy (suffix, client_uuid, suffix_len); + if (grub_config_search_through (config, suffix, 1, 0) == 0) + return GRUB_ERR_NONE; + } +diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c +index 6f6e4a813..49b947292 100644 +--- a/grub-core/normal/main.c ++++ b/grub-core/normal/main.c +@@ -360,7 +360,7 @@ grub_try_normal_prefix (const char *prefix) + return err; + + grub_snprintf (config, config_len, "%s/grub.cfg", prefix); +- err = grub_net_search_config_file (config); ++ err = grub_net_search_config_file (config, config_len); + } + + if (err != GRUB_ERR_NONE) +diff --git a/include/grub/net.h b/include/grub/net.h +index 43eba9216..1101b0397 100644 +--- a/include/grub/net.h ++++ b/include/grub/net.h +@@ -648,7 +648,7 @@ void + grub_net_remove_dns_server (const struct grub_net_network_level_address *s); + + grub_err_t +-grub_net_search_config_file (char *config); ++grub_net_search_config_file (char *config, grub_size_t config_buf_len); + + extern char *grub_net_default_server; + diff --git a/0406-net-tftp-Fix-stack-buffer-overflow-in-tftp_open.patch b/0406-net-tftp-Fix-stack-buffer-overflow-in-tftp_open.patch new file mode 100644 index 0000000..e7b8754 --- /dev/null +++ b/0406-net-tftp-Fix-stack-buffer-overflow-in-tftp_open.patch @@ -0,0 +1,115 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: B Horn +Date: Thu, 18 Apr 2024 17:32:34 +0100 +Subject: [PATCH] net/tftp: Fix stack buffer overflow in tftp_open() + +An overly long filename can be passed to tftp_open() which would cause +grub_normalize_filename() to write out of bounds. + +Fixed by adding an extra argument to grub_normalize_filename() for the +space available, making it act closer to a strlcpy(). As several fixed +strings are strcpy()'d after into the same buffer, their total length is +checked to see if they exceed the remaining space in the buffer. If so, +return an error. + +On the occasion simplify code a bit by removing unneeded rrqlen zeroing. + +Reported-by: B Horn +Signed-off-by: B Horn +Reviewed-by: Daniel Kiper +--- + grub-core/net/tftp.c | 38 ++++++++++++++++++++++++-------------- + 1 file changed, 24 insertions(+), 14 deletions(-) + +diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c +index a95766dcb..ecfcc13d9 100644 +--- a/grub-core/net/tftp.c ++++ b/grub-core/net/tftp.c +@@ -266,17 +266,19 @@ tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)), + * forward slashes to a single forward slash. + */ + static void +-grub_normalize_filename (char *normalized, const char *filename) ++grub_normalize_filename (char *normalized, const char *filename, int c) + { + char *dest = normalized; + const char *src = filename; + +- while (*src != '\0') ++ while (*src != '\0' && c > 0) + { + if (src[0] == '/' && src[1] == '/') + src++; +- else ++ else { ++ c--; + *dest++ = *src++; ++ } + } + *dest = '\0'; + } +@@ -287,7 +289,7 @@ tftp_open (struct grub_file *file, const char *filename) + struct tftphdr *tftph; + char *rrq; + int i; +- int rrqlen; ++ int rrqlen, rrqsize; + int hdrlen; + grub_uint8_t open_data[1500]; + struct grub_net_buff nb; +@@ -315,37 +317,45 @@ tftp_open (struct grub_file *file, const char *filename) + + tftph = (struct tftphdr *) nb.data; + +- rrq = (char *) tftph->u.rrq; +- rrqlen = 0; +- + tftph->opcode = grub_cpu_to_be16_compile_time (TFTP_RRQ); + ++ rrq = (char *) tftph->u.rrq; ++ rrqsize = sizeof (tftph->u.rrq); ++ + /* + * Copy and normalize the filename to work-around issues on some TFTP + * servers when file names are being matched for remapping. + */ +- grub_normalize_filename (rrq, filename); +- rrqlen += grub_strlen (rrq) + 1; ++ grub_normalize_filename (rrq, filename, rrqsize); ++ ++ rrqlen = grub_strlen (rrq) + 1; + rrq += grub_strlen (rrq) + 1; + +- grub_strcpy (rrq, "octet"); ++ /* Verify there is enough space for the remaining components. */ + rrqlen += grub_strlen ("octet") + 1; ++ rrqlen += grub_strlen ("blksize") + 1; ++ rrqlen += grub_strlen ("1024") + 1; ++ rrqlen += grub_strlen ("tsize") + 1; ++ rrqlen += grub_strlen ("0") + 1; ++ ++ if (rrqlen >= rrqsize) { ++ grub_free (data); ++ return grub_error (GRUB_ERR_BAD_FILENAME, N_("filename too long")); ++ } ++ ++ grub_strcpy (rrq, "octet"); + rrq += grub_strlen ("octet") + 1; + + grub_strcpy (rrq, "blksize"); +- rrqlen += grub_strlen ("blksize") + 1; + rrq += grub_strlen ("blksize") + 1; + + grub_strcpy (rrq, "1024"); +- rrqlen += grub_strlen ("1024") + 1; + rrq += grub_strlen ("1024") + 1; + + grub_strcpy (rrq, "tsize"); +- rrqlen += grub_strlen ("tsize") + 1; + rrq += grub_strlen ("tsize") + 1; + + grub_strcpy (rrq, "0"); +- rrqlen += grub_strlen ("0") + 1; + rrq += grub_strlen ("0") + 1; + hdrlen = sizeof (tftph->opcode) + rrqlen; + diff --git a/0407-video-readers-jpeg-Do-not-permit-duplicate-SOF0-mark.patch b/0407-video-readers-jpeg-Do-not-permit-duplicate-SOF0-mark.patch new file mode 100644 index 0000000..4c680f6 --- /dev/null +++ b/0407-video-readers-jpeg-Do-not-permit-duplicate-SOF0-mark.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 8 Mar 2024 22:47:20 +1100 +Subject: [PATCH] video/readers/jpeg: Do not permit duplicate SOF0 markers in + JPEG + +Otherwise a subsequent header could change the height and width +allowing future OOB writes. + +Fixes: CVE-2024-45774 + +Reported-by: Nils Langius +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/video/readers/jpeg.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c +index 2da04094b..c7aaac362 100644 +--- a/grub-core/video/readers/jpeg.c ++++ b/grub-core/video/readers/jpeg.c +@@ -332,6 +332,10 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data) + if (grub_errno != GRUB_ERR_NONE) + return grub_errno; + ++ if (data->image_height != 0 || data->image_width != 0) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: cannot have duplicate SOF0 markers"); ++ + if (grub_jpeg_get_byte (data) != 8) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: only 8-bit precision is supported"); diff --git a/0408-kern-dl-Fix-for-an-integer-overflow-in-grub_dl_ref.patch b/0408-kern-dl-Fix-for-an-integer-overflow-in-grub_dl_ref.patch new file mode 100644 index 0000000..c5bb3ef --- /dev/null +++ b/0408-kern-dl-Fix-for-an-integer-overflow-in-grub_dl_ref.patch @@ -0,0 +1,138 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: B Horn +Date: Tue, 11 Feb 2025 16:41:57 -0600 +Subject: [PATCH] kern/dl: Fix for an integer overflow in grub_dl_ref() + +It was possible to overflow the value of mod->ref_count, a signed +integer, by repeatedly invoking insmod on an already loaded module. +This led to a use-after-free. As once ref_count was overflowed it became +possible to unload the module while there was still references to it. + +This resolves the issue by using grub_add() to check if the ref_count +will overflow and then stops further increments. Further changes were +also made to grub_dl_unref() to check for the underflow condition and +the reference count was changed to an unsigned 64-bit integer. + +Reported-by: B Horn +Signed-off-by: B Horn +Reviewed-by: Daniel Kiper +--- + grub-core/commands/minicmd.c | 2 +- + grub-core/kern/dl.c | 17 ++++++++++++----- + include/grub/dl.h | 8 ++++---- + util/misc.c | 4 ++-- + 4 files changed, 19 insertions(+), 12 deletions(-) + +diff --git a/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c +index 2bd3ac76f..2001043cf 100644 +--- a/grub-core/commands/minicmd.c ++++ b/grub-core/commands/minicmd.c +@@ -167,7 +167,7 @@ grub_mini_cmd_lsmod (struct grub_command *cmd __attribute__ ((unused)), + { + grub_dl_dep_t dep; + +- grub_printf ("%s\t%d\t\t", mod->name, mod->ref_count); ++ grub_printf ("%s\t%" PRIuGRUB_UINT64_T "\t\t", mod->name, mod->ref_count); + for (dep = mod->dep; dep; dep = dep->next) + { + if (dep != mod->dep) +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index f3cdb9e0b..944e5600a 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + #include + + /* Platforms where modules are in a readonly area of memory. */ +@@ -604,7 +605,7 @@ grub_dl_resolve_dependencies (grub_dl_t mod, Elf_Ehdr *e) + return GRUB_ERR_NONE; + } + +-int ++grub_uint64_t + grub_dl_ref (grub_dl_t mod) + { + grub_dl_dep_t dep; +@@ -615,10 +616,13 @@ grub_dl_ref (grub_dl_t mod) + for (dep = mod->dep; dep; dep = dep->next) + grub_dl_ref (dep->mod); + +- return ++mod->ref_count; ++ if (grub_add (mod->ref_count, 1, &mod->ref_count)) ++ grub_fatal ("Module reference count overflow"); ++ ++ return mod->ref_count; + } + +-int ++grub_uint64_t + grub_dl_unref (grub_dl_t mod) + { + grub_dl_dep_t dep; +@@ -629,10 +633,13 @@ grub_dl_unref (grub_dl_t mod) + for (dep = mod->dep; dep; dep = dep->next) + grub_dl_unref (dep->mod); + +- return --mod->ref_count; ++ if (grub_sub (mod->ref_count, 1, &mod->ref_count)) ++ grub_fatal ("Module reference count underflow"); ++ ++ return mod->ref_count; + } + +-int ++grub_uint64_t + grub_dl_ref_count (grub_dl_t mod) + { + if (mod == NULL) +diff --git a/include/grub/dl.h b/include/grub/dl.h +index 6bc2560bf..fdf55d4ee 100644 +--- a/include/grub/dl.h ++++ b/include/grub/dl.h +@@ -177,7 +177,7 @@ typedef struct grub_dl_dep *grub_dl_dep_t; + struct grub_dl + { + char *name; +- int ref_count; ++ grub_uint64_t ref_count; + int persistent; + grub_dl_dep_t dep; + grub_dl_segment_t segment; +@@ -206,9 +206,9 @@ grub_dl_t EXPORT_FUNC(grub_dl_load) (const char *name); + grub_dl_t grub_dl_load_core (void *addr, grub_size_t size); + grub_dl_t EXPORT_FUNC(grub_dl_load_core_noinit) (void *addr, grub_size_t size); + int EXPORT_FUNC(grub_dl_unload) (grub_dl_t mod); +-extern int EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod); +-extern int EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod); +-extern int EXPORT_FUNC(grub_dl_ref_count) (grub_dl_t mod); ++extern grub_uint64_t EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod); ++extern grub_uint64_t EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod); ++extern grub_uint64_t EXPORT_FUNC(grub_dl_ref_count) (grub_dl_t mod); + + extern grub_dl_t EXPORT_VAR(grub_dl_head); + +diff --git a/util/misc.c b/util/misc.c +index d545212d9..0f928e5b4 100644 +--- a/util/misc.c ++++ b/util/misc.c +@@ -190,14 +190,14 @@ grub_xputs_real (const char *str) + + void (*grub_xputs) (const char *str) = grub_xputs_real; + +-int ++grub_uint64_t + grub_dl_ref (grub_dl_t mod) + { + (void) mod; + return 0; + } + +-int ++grub_uint64_t + grub_dl_unref (grub_dl_t mod) + { + (void) mod; diff --git a/0409-kern-dl-Check-for-the-SHF_INFO_LINK-flag-in-grub_dl_.patch b/0409-kern-dl-Check-for-the-SHF_INFO_LINK-flag-in-grub_dl_.patch new file mode 100644 index 0000000..2abd173 --- /dev/null +++ b/0409-kern-dl-Check-for-the-SHF_INFO_LINK-flag-in-grub_dl_.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: B Horn +Date: Tue, 11 Feb 2025 17:01:26 -0600 +Subject: [PATCH] kern/dl: Check for the SHF_INFO_LINK flag in + grub_dl_relocate_symbols() + +The grub_dl_relocate_symbols() iterates through the sections in +an ELF looking for relocation sections. According to the spec [1] +the SHF_INFO_LINK flag should be set if the sh_info field is meant +to be a section index. + +[1] https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html + +Reported-by: B Horn +Signed-off-by: B Horn +Reviewed-by: Daniel Kiper +--- + grub-core/kern/dl.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index 944e5600a..f2806f8cf 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -672,6 +672,9 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr) + grub_dl_segment_t seg; + grub_err_t err; + ++ if (!(s->sh_flags & SHF_INFO_LINK)) ++ continue; ++ + seg = grub_dl_find_segment(mod, s->sh_info); + if (!seg) + continue; diff --git a/0410-commands-extcmd-Missing-check-for-failed-allocation.patch b/0410-commands-extcmd-Missing-check-for-failed-allocation.patch new file mode 100644 index 0000000..44e8c91 --- /dev/null +++ b/0410-commands-extcmd-Missing-check-for-failed-allocation.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lidong Chen +Date: Fri, 22 Nov 2024 06:27:55 +0000 +Subject: [PATCH] commands/extcmd: Missing check for failed allocation + +The grub_extcmd_dispatcher() calls grub_arg_list_alloc() to allocate +a grub_arg_list struct but it does not verify the allocation was successful. +In case of failed allocation the NULL state pointer can be accessed in +parse_option() through grub_arg_parse() which may lead to a security issue. + +Fixes: CVE-2024-45775 + +Reported-by: Nils Langius +Signed-off-by: Lidong Chen +Reviewed-by: Daniel Kiper +Reviewed-by: Alec Brown +--- + grub-core/commands/extcmd.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/commands/extcmd.c b/grub-core/commands/extcmd.c +index 90a5ca24a..c236be13a 100644 +--- a/grub-core/commands/extcmd.c ++++ b/grub-core/commands/extcmd.c +@@ -49,6 +49,9 @@ grub_extcmd_dispatcher (struct grub_command *cmd, int argc, char **args, + } + + state = grub_arg_list_alloc (ext, argc, args); ++ if (state == NULL) ++ return grub_errno; ++ + if (grub_arg_parse (ext, argc, args, state, &new_args, &new_argc)) + { + context.state = state; diff --git a/0411-commands-ls-Fix-NULL-dereference.patch b/0411-commands-ls-Fix-NULL-dereference.patch new file mode 100644 index 0000000..6a11dad --- /dev/null +++ b/0411-commands-ls-Fix-NULL-dereference.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: B Horn +Date: Sun, 12 May 2024 11:08:23 +0100 +Subject: [PATCH] commands/ls: Fix NULL dereference + +The grub_strrchr() may return NULL when the dirname do not contain "/". +This can happen on broken filesystems. + +Reported-by: B Horn +Signed-off-by: B Horn +Reviewed-by: Daniel Kiper +--- + grub-core/commands/ls.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/grub-core/commands/ls.c b/grub-core/commands/ls.c +index 8e98c73cc..783c82713 100644 +--- a/grub-core/commands/ls.c ++++ b/grub-core/commands/ls.c +@@ -241,7 +241,11 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human) + + grub_file_close (file); + +- p = grub_strrchr (dirname, '/') + 1; ++ p = grub_strrchr (dirname, '/'); ++ if (p == NULL) ++ goto fail; ++ ++p; ++ + dirname = grub_strndup (dirname, p - dirname); + if (! dirname) + goto fail; diff --git a/0412-commands-pgp-Unregister-the-check_signatures-hooks-o.patch b/0412-commands-pgp-Unregister-the-check_signatures-hooks-o.patch new file mode 100644 index 0000000..d2961a9 --- /dev/null +++ b/0412-commands-pgp-Unregister-the-check_signatures-hooks-o.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: B Horn +Date: Fri, 1 Nov 2024 19:24:29 +0000 +Subject: [PATCH] commands/pgp: Unregister the "check_signatures" hooks on + module unload + +If the hooks are not removed they can be called after the module has +been unloaded leading to an use-after-free. + +Fixes: CVE-2025-0622 + +Reported-by: B Horn +Signed-off-by: B Horn +Reviewed-by: Daniel Kiper +--- + grub-core/commands/pgp.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c +index b81ac0ae4..4a6a5f9a0 100644 +--- a/grub-core/commands/pgp.c ++++ b/grub-core/commands/pgp.c +@@ -982,6 +982,8 @@ GRUB_MOD_INIT(pgp) + + GRUB_MOD_FINI(pgp) + { ++ grub_register_variable_hook ("check_signatures", NULL, NULL); ++ grub_env_unset ("check_signatures"); + grub_verifier_unregister (&grub_pubkey_verifier); + grub_unregister_extcmd (cmd); + grub_unregister_extcmd (cmd_trust); diff --git a/0413-normal-Remove-variables-hooks-on-module-unload.patch b/0413-normal-Remove-variables-hooks-on-module-unload.patch new file mode 100644 index 0000000..8528952 --- /dev/null +++ b/0413-normal-Remove-variables-hooks-on-module-unload.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: B Horn +Date: Fri, 1 Nov 2024 23:46:55 +0000 +Subject: [PATCH] normal: Remove variables hooks on module unload + +The normal module does not entirely cleanup after itself in +its GRUB_MOD_FINI() leaving a few variables hooks in place. +It is not possible to unload normal module now but fix the +issues for completeness. + +On the occasion replace 0s with NULLs for "pager" variable +hooks unregister. + +Fixes: CVE-2025-0622 + +Reported-by: B Horn +Signed-off-by: B Horn +Reviewed-by: Daniel Kiper +--- + grub-core/normal/main.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c +index 49b947292..c96b6609d 100644 +--- a/grub-core/normal/main.c ++++ b/grub-core/normal/main.c +@@ -689,7 +689,9 @@ GRUB_MOD_FINI(normal) + grub_xputs = grub_xputs_saved; + + grub_set_history (0); +- grub_register_variable_hook ("pager", 0, 0); ++ grub_register_variable_hook ("pager", NULL, NULL); ++ grub_register_variable_hook ("color_normal", NULL, NULL); ++ grub_register_variable_hook ("color_highlight", NULL, NULL); + grub_fs_autoload_hook = 0; + grub_unregister_command (cmd_clear); + } diff --git a/0414-gettext-Remove-variables-hooks-on-module-unload.patch b/0414-gettext-Remove-variables-hooks-on-module-unload.patch new file mode 100644 index 0000000..6942c88 --- /dev/null +++ b/0414-gettext-Remove-variables-hooks-on-module-unload.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: B Horn +Date: Fri, 1 Nov 2024 23:52:06 +0000 +Subject: [PATCH] gettext: Remove variables hooks on module unload + +The gettext module does not entirely cleanup after itself in +its GRUB_MOD_FINI() leaving a few variables hooks in place. +It is not possible to unload gettext module because normal +module depends on it. Though fix the issues for completeness. + +Fixes: CVE-2025-0622 + +Reported-by: B Horn +Signed-off-by: B Horn +Reviewed-by: Daniel Kiper +--- + grub-core/gettext/gettext.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/grub-core/gettext/gettext.c b/grub-core/gettext/gettext.c +index 7ec81ca0b..16169e81f 100644 +--- a/grub-core/gettext/gettext.c ++++ b/grub-core/gettext/gettext.c +@@ -542,6 +542,10 @@ GRUB_MOD_INIT (gettext) + + GRUB_MOD_FINI (gettext) + { ++ grub_register_variable_hook ("locale_dir", NULL, NULL); ++ grub_register_variable_hook ("secondary_locale_dir", NULL, NULL); ++ grub_register_variable_hook ("lang", NULL, NULL); ++ + grub_gettext_delete_list (&main_context); + grub_gettext_delete_list (&secondary_context); + diff --git a/0415-gettext-Integer-overflow-leads-to-heap-OOB-write-or-.patch b/0415-gettext-Integer-overflow-leads-to-heap-OOB-write-or-.patch new file mode 100644 index 0000000..40c557b --- /dev/null +++ b/0415-gettext-Integer-overflow-leads-to-heap-OOB-write-or-.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lidong Chen +Date: Fri, 22 Nov 2024 06:27:56 +0000 +Subject: [PATCH] gettext: Integer overflow leads to heap OOB write or read + +Calculation of ctx->grub_gettext_msg_list size in grub_mofile_open() may +overflow leading to subsequent OOB write or read. This patch fixes the +issue by replacing grub_zalloc() and explicit multiplication with +grub_calloc() which does the same thing in safe manner. + +Fixes: CVE-2024-45776 + +Reported-by: Nils Langius +Signed-off-by: Lidong Chen +Reviewed-by: Daniel Kiper +Reviewed-by: Alec Brown +--- + grub-core/gettext/gettext.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/grub-core/gettext/gettext.c b/grub-core/gettext/gettext.c +index 16169e81f..868524839 100644 +--- a/grub-core/gettext/gettext.c ++++ b/grub-core/gettext/gettext.c +@@ -323,8 +323,8 @@ grub_mofile_open (struct grub_gettext_context *ctx, + for (ctx->grub_gettext_max_log = 0; ctx->grub_gettext_max >> ctx->grub_gettext_max_log; + ctx->grub_gettext_max_log++); + +- ctx->grub_gettext_msg_list = grub_zalloc (ctx->grub_gettext_max +- * sizeof (ctx->grub_gettext_msg_list[0])); ++ ctx->grub_gettext_msg_list = grub_calloc (ctx->grub_gettext_max, ++ sizeof (ctx->grub_gettext_msg_list[0])); + if (!ctx->grub_gettext_msg_list) + { + grub_file_close (fd); diff --git a/0416-gettext-Integer-overflow-leads-to-heap-OOB-write.patch b/0416-gettext-Integer-overflow-leads-to-heap-OOB-write.patch new file mode 100644 index 0000000..879d168 --- /dev/null +++ b/0416-gettext-Integer-overflow-leads-to-heap-OOB-write.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lidong Chen +Date: Fri, 22 Nov 2024 06:27:57 +0000 +Subject: [PATCH] gettext: Integer overflow leads to heap OOB write + +The size calculation of the translation buffer in +grub_gettext_getstr_from_position() may overflow +to 0 leading to heap OOB write. This patch fixes +the issue by using grub_add() and checking for +an overflow. + +Fixes: CVE-2024-45777 + +Reported-by: Nils Langius +Signed-off-by: Lidong Chen +Reviewed-by: Daniel Kiper +Reviewed-by: Alec Brown +--- + grub-core/gettext/gettext.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/grub-core/gettext/gettext.c b/grub-core/gettext/gettext.c +index 868524839..0e51b5d28 100644 +--- a/grub-core/gettext/gettext.c ++++ b/grub-core/gettext/gettext.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -99,6 +100,7 @@ grub_gettext_getstr_from_position (struct grub_gettext_context *ctx, + char *translation; + struct string_descriptor desc; + grub_err_t err; ++ grub_size_t alloc_sz; + + internal_position = (off + position * sizeof (desc)); + +@@ -109,7 +111,10 @@ grub_gettext_getstr_from_position (struct grub_gettext_context *ctx, + length = grub_cpu_to_le32 (desc.length); + offset = grub_cpu_to_le32 (desc.offset); + +- translation = grub_malloc (length + 1); ++ if (grub_add (length, 1, &alloc_sz)) ++ return NULL; ++ ++ translation = grub_malloc (alloc_sz); + if (!translation) + return NULL; + diff --git a/0417-commands-read-Add-silent-mode-to-read-command-to-sup.patch b/0417-commands-read-Add-silent-mode-to-read-command-to-sup.patch new file mode 100644 index 0000000..8d77402 --- /dev/null +++ b/0417-commands-read-Add-silent-mode-to-read-command-to-sup.patch @@ -0,0 +1,106 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Sun, 21 Mar 2021 15:22:19 -0500 +Subject: [PATCH] commands/read: Add silent mode to read command to suppress + input echo + +This conforms to the behavior of the -s option of the Bash read command. + +docs/grub: Document the -s option for the read command. + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + docs/grub.texi | 5 +++-- + grub-core/commands/read.c | 28 ++++++++++++++++++---------- + 2 files changed, 21 insertions(+), 12 deletions(-) + +diff --git a/docs/grub.texi b/docs/grub.texi +index bbcd1c931..913c3bff3 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -5041,10 +5041,11 @@ and the system will reboot. + @node read + @subsection read + +-@deffn Command read [var] ++@deffn Command read [-s] [var] + Read a line of input from the user. If an environment variable @var{var} is + given, set that environment variable to the line of input that was read, +-with no terminating newline. ++with no terminating newline. If the parameter @option{-s} is used, enable ++silent mode where input is not printed to the terminal. + @end deffn + + +diff --git a/grub-core/commands/read.c b/grub-core/commands/read.c +index fe3e88b15..c2969ccda 100644 +--- a/grub-core/commands/read.c ++++ b/grub-core/commands/read.c +@@ -23,13 +23,19 @@ + #include + #include + #include +-#include ++#include + #include + + GRUB_MOD_LICENSE ("GPLv3+"); + ++static const struct grub_arg_option options[] = ++ { ++ {"silent", 's', 0, N_("Do not echo input"), 0, 0}, ++ {0, 0, 0, 0, 0, 0} ++ }; ++ + static char * +-grub_getline (void) ++grub_getline (int silent) + { + int i; + char *line; +@@ -48,7 +54,7 @@ grub_getline (void) + break; + + line[i] = c; +- if (grub_isprint (c)) ++ if (!silent && grub_isprint (c)) + grub_printf ("%c", c); + i++; + tmp = grub_realloc (line, 1 + i + sizeof('\0')); +@@ -65,9 +71,11 @@ grub_getline (void) + } + + static grub_err_t +-grub_cmd_read (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) ++grub_cmd_read (grub_extcmd_context_t ctxt, int argc, char **args) + { +- char *line = grub_getline (); ++ struct grub_arg_list *state = ctxt->state; ++ char *line = grub_getline (state[0].set); ++ + if (! line) + return grub_errno; + if (argc > 0) +@@ -77,16 +85,16 @@ grub_cmd_read (grub_command_t cmd __attribute__ ((unused)), int argc, char **arg + return 0; + } + +-static grub_command_t cmd; ++static grub_extcmd_t cmd; + + GRUB_MOD_INIT(read) + { +- cmd = grub_register_command ("read", grub_cmd_read, +- N_("[ENVVAR]"), +- N_("Set variable with user input.")); ++ cmd = grub_register_extcmd ("read", grub_cmd_read, 0, ++ N_("[-s] [ENVVAR]"), ++ N_("Set variable with user input."), options); + } + + GRUB_MOD_FINI(read) + { +- grub_unregister_command (cmd); ++ grub_unregister_extcmd (cmd); + } diff --git a/0418-commands-read-Fix-overflow-in-grub_getline.patch b/0418-commands-read-Fix-overflow-in-grub_getline.patch new file mode 100644 index 0000000..e1ab66b --- /dev/null +++ b/0418-commands-read-Fix-overflow-in-grub_getline.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Li Gen +Date: Thu, 25 Aug 2022 19:59:09 -0500 +Subject: [PATCH] commands/read: Fix overflow in grub_getline() + +Store returned value from grub_getkey() in int instead of char to +prevent throwing away the extended bits. This was a problem because, +for instance, the left arrow key press would return +(GRUB_TERM_EXTENDED | 0x4b), which would have the GRUB_TERM_EXTENDED +thrown away leaving 0x4b or 'K'. These extended keys should either +work as intended or do nothing. This change has them do nothing, +instead of inserting a key not pressed by the user. + +Signed-off-by: Li Gen +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + grub-core/commands/read.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/grub-core/commands/read.c b/grub-core/commands/read.c +index c2969ccda..597c90706 100644 +--- a/grub-core/commands/read.c ++++ b/grub-core/commands/read.c +@@ -40,7 +40,7 @@ grub_getline (int silent) + int i; + char *line; + char *tmp; +- char c; ++ int c; + + i = 0; + line = grub_malloc (1 + i + sizeof('\0')); +@@ -53,8 +53,11 @@ grub_getline (int silent) + if ((c == '\n') || (c == '\r')) + break; + +- line[i] = c; +- if (!silent && grub_isprint (c)) ++ if (!grub_isprint (c)) ++ continue; ++ ++ line[i] = (char) c; ++ if (!silent) + grub_printf ("%c", c); + i++; + tmp = grub_realloc (line, 1 + i + sizeof('\0')); diff --git a/0419-commands-read-Fix-an-integer-overflow-when-supplying.patch b/0419-commands-read-Fix-an-integer-overflow-when-supplying.patch new file mode 100644 index 0000000..33ea08d --- /dev/null +++ b/0419-commands-read-Fix-an-integer-overflow-when-supplying.patch @@ -0,0 +1,69 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jonathan Bar Or +Date: Thu, 23 Jan 2025 19:17:05 +0100 +Subject: [PATCH] commands/read: Fix an integer overflow when supplying more + than 2^31 characters + +The grub_getline() function currently has a signed integer variable "i" +that can be overflown when user supplies more than 2^31 characters. +It results in a memory corruption of the allocated line buffer as well +as supplying large negative values to grub_realloc(). + +Fixes: CVE-2025-0690 + +Reported-by: Jonathan Bar Or +Signed-off-by: Jonathan Bar Or +Reviewed-by: Daniel Kiper +--- + grub-core/commands/read.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/grub-core/commands/read.c b/grub-core/commands/read.c +index 597c90706..8d72e45c9 100644 +--- a/grub-core/commands/read.c ++++ b/grub-core/commands/read.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -37,13 +38,14 @@ static const struct grub_arg_option options[] = + static char * + grub_getline (int silent) + { +- int i; ++ grub_size_t i; + char *line; + char *tmp; + int c; ++ grub_size_t alloc_size; + + i = 0; +- line = grub_malloc (1 + i + sizeof('\0')); ++ line = grub_malloc (1 + sizeof('\0')); + if (! line) + return NULL; + +@@ -59,8 +61,17 @@ grub_getline (int silent) + line[i] = (char) c; + if (!silent) + grub_printf ("%c", c); +- i++; +- tmp = grub_realloc (line, 1 + i + sizeof('\0')); ++ if (grub_add (i, 1, &i)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); ++ return NULL; ++ } ++ if (grub_add (i, 1 + sizeof('\0'), &alloc_size)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); ++ return NULL; ++ } ++ tmp = grub_realloc (line, alloc_size); + if (! tmp) + { + grub_free (line); diff --git a/0420-commands-test-Stack-overflow-due-to-unlimited-recurs.patch b/0420-commands-test-Stack-overflow-due-to-unlimited-recurs.patch new file mode 100644 index 0000000..3dc101b --- /dev/null +++ b/0420-commands-test-Stack-overflow-due-to-unlimited-recurs.patch @@ -0,0 +1,83 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lidong Chen +Date: Mon, 16 Dec 2024 20:22:41 +0000 +Subject: [PATCH] commands/test: Stack overflow due to unlimited recursion + depth + +The test_parse() evaluates test expression recursively. Due to lack of +recursion depth check a specially crafted expression may cause a stack +overflow. The recursion is only triggered by the parentheses usage and +it can be unlimited. However, sensible expressions are unlikely to +contain more than a few parentheses. So, this patch limits the recursion +depth to 100, which should be sufficient. + +Reported-by: Nils Langius +Signed-off-by: Lidong Chen +Reviewed-by: Daniel Kiper +--- + grub-core/commands/test.c | 21 ++++++++++++++++++--- + 1 file changed, 18 insertions(+), 3 deletions(-) + +diff --git a/grub-core/commands/test.c b/grub-core/commands/test.c +index 62d3fb398..b585c3d70 100644 +--- a/grub-core/commands/test.c ++++ b/grub-core/commands/test.c +@@ -29,6 +29,9 @@ + + GRUB_MOD_LICENSE ("GPLv3+"); + ++/* Set a limit on recursion to avoid stack overflow. */ ++#define MAX_TEST_RECURSION_DEPTH 100 ++ + /* A simple implementation for signed numbers. */ + static int + grub_strtosl (char *arg, const char ** const end, int base) +@@ -150,7 +153,7 @@ get_fileinfo (char *path, struct test_parse_ctx *ctx) + + /* Parse a test expression starting from *argn. */ + static int +-test_parse (char **args, int *argn, int argc) ++test_parse (char **args, int *argn, int argc, int *depth) + { + struct test_parse_ctx ctx = { + .and = 1, +@@ -387,13 +390,24 @@ test_parse (char **args, int *argn, int argc) + if (grub_strcmp (args[*argn], ")") == 0) + { + (*argn)++; ++ if (*depth > 0) ++ (*depth)--; ++ + return ctx.or || ctx.and; + } + /* Recursively invoke if parenthesis. */ + if (grub_strcmp (args[*argn], "(") == 0) + { + (*argn)++; +- update_val (test_parse (args, argn, argc), &ctx); ++ ++ if (++(*depth) > MAX_TEST_RECURSION_DEPTH) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("max recursion depth exceeded")); ++ depth--; ++ return ctx.or || ctx.and; ++ } ++ ++ update_val (test_parse (args, argn, argc, depth), &ctx); + continue; + } + +@@ -428,11 +442,12 @@ grub_cmd_test (grub_command_t cmd __attribute__ ((unused)), + int argc, char **args) + { + int argn = 0; ++ int depth = 0; + + if (argc >= 1 && grub_strcmp (args[argc - 1], "]") == 0) + argc--; + +- return test_parse (args, &argn, argc) ? GRUB_ERR_NONE ++ return test_parse (args, &argn, argc, &depth) ? GRUB_ERR_NONE + : grub_error (GRUB_ERR_TEST_FAILURE, N_("false")); + } + diff --git a/0421-commands-minicmd-Block-the-dump-command-in-lockdown-.patch b/0421-commands-minicmd-Block-the-dump-command-in-lockdown-.patch new file mode 100644 index 0000000..a999146 --- /dev/null +++ b/0421-commands-minicmd-Block-the-dump-command-in-lockdown-.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: B Horn +Date: Thu, 18 Apr 2024 20:29:39 +0100 +Subject: [PATCH] commands/minicmd: Block the dump command in lockdown mode + +The dump enables a user to read memory which should not be possible +in lockdown mode. + +Fixes: CVE-2025-1118 + +Reported-by: B Horn +Reported-by: Jonathan Bar Or +Signed-off-by: B Horn +Reviewed-by: Daniel Kiper +--- + grub-core/commands/minicmd.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c +index 2001043cf..9efb7718c 100644 +--- a/grub-core/commands/minicmd.c ++++ b/grub-core/commands/minicmd.c +@@ -215,8 +215,8 @@ GRUB_MOD_INIT(minicmd) + grub_register_command ("help", grub_mini_cmd_help, + 0, N_("Show this message.")); + cmd_dump = +- grub_register_command ("dump", grub_mini_cmd_dump, +- N_("ADDR [SIZE]"), N_("Show memory contents.")); ++ grub_register_command_lockdown ("dump", grub_mini_cmd_dump, ++ N_("ADDR [SIZE]"), N_("Show memory contents.")); + cmd_rmmod = + grub_register_command ("rmmod", grub_mini_cmd_rmmod, + N_("MODULE"), N_("Remove a module.")); diff --git a/0422-commands-memrw-Disable-memory-reading-in-lockdown-mo.patch b/0422-commands-memrw-Disable-memory-reading-in-lockdown-mo.patch new file mode 100644 index 0000000..e787d6f --- /dev/null +++ b/0422-commands-memrw-Disable-memory-reading-in-lockdown-mo.patch @@ -0,0 +1,50 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: B Horn +Date: Tue, 11 Feb 2025 17:12:29 -0600 +Subject: [PATCH] commands/memrw: Disable memory reading in lockdown mode + +With the rest of module being blocked in lockdown mode it does not make +a lot of sense to leave memory reading enabled. This also goes in par +with disabling the dump command. + +Reported-by: B Horn +Signed-off-by: B Horn +Reviewed-by: Daniel Kiper +--- + grub-core/commands/memrw.c | 21 ++++++++++++--------- + 1 file changed, 12 insertions(+), 9 deletions(-) + +diff --git a/grub-core/commands/memrw.c b/grub-core/commands/memrw.c +index 39cf3a06d..9d8a54a4b 100644 +--- a/grub-core/commands/memrw.c ++++ b/grub-core/commands/memrw.c +@@ -126,17 +126,20 @@ GRUB_MOD_INIT(memrw) + return; + + cmd_read_byte = +- grub_register_extcmd ("read_byte", grub_cmd_read, 0, +- N_("ADDR"), N_("Read 8-bit value from ADDR."), +- options); ++ grub_register_extcmd_lockdown ("read_byte", grub_cmd_read, 0, ++ N_("ADDR"), ++ N_("Read 8-bit value from ADDR."), ++ options); + cmd_read_word = +- grub_register_extcmd ("read_word", grub_cmd_read, 0, +- N_("ADDR"), N_("Read 16-bit value from ADDR."), +- options); ++ grub_register_extcmd_lockdown ("read_word", grub_cmd_read, 0, ++ N_("ADDR"), ++ N_("Read 16-bit value from ADDR."), ++ options); + cmd_read_dword = +- grub_register_extcmd ("read_dword", grub_cmd_read, 0, +- N_("ADDR"), N_("Read 32-bit value from ADDR."), +- options); ++ grub_register_extcmd_lockdown ("read_dword", grub_cmd_read, 0, ++ N_("ADDR"), ++ N_("Read 32-bit value from ADDR."), ++ options); + cmd_write_byte = + grub_register_command_lockdown ("write_byte", grub_cmd_write, + N_("ADDR VALUE [MASK]"), diff --git a/0423-commands-hexdump-Disable-memory-reading-in-lockdown-.patch b/0423-commands-hexdump-Disable-memory-reading-in-lockdown-.patch new file mode 100644 index 0000000..ae523f8 --- /dev/null +++ b/0423-commands-hexdump-Disable-memory-reading-in-lockdown-.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: B Horn +Date: Fri, 19 Apr 2024 22:31:45 +0100 +Subject: [PATCH] commands/hexdump: Disable memory reading in lockdown mode + +Reported-by: B Horn +Signed-off-by: B Horn +Reviewed-by: Daniel Kiper +--- + grub-core/commands/hexdump.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/grub-core/commands/hexdump.c b/grub-core/commands/hexdump.c +index eaa12465b..d6f61d98a 100644 +--- a/grub-core/commands/hexdump.c ++++ b/grub-core/commands/hexdump.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -51,7 +52,11 @@ grub_cmd_hexdump (grub_extcmd_context_t ctxt, int argc, char **args) + length = (state[1].set) ? grub_strtoul (state[1].arg, 0, 0) : 256; + + if (!grub_strcmp (args[0], "(mem)")) +- hexdump (skip, (char *) (grub_addr_t) skip, length); ++ { ++ if (grub_is_lockdown() == GRUB_LOCKDOWN_ENABLED) ++ return grub_error (GRUB_ERR_ACCESS_DENIED, N_("memory reading is disabled in lockdown mode")); ++ hexdump (skip, (char *) (grub_addr_t) skip, length); ++ } + else if ((args[0][0] == '(') && (args[0][namelen - 1] == ')')) + { + grub_disk_t disk; diff --git a/0424-fs-bfs-Disable-under-lockdown.patch b/0424-fs-bfs-Disable-under-lockdown.patch new file mode 100644 index 0000000..8ba815b --- /dev/null +++ b/0424-fs-bfs-Disable-under-lockdown.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Sat, 23 Mar 2024 15:59:43 +1100 +Subject: [PATCH] fs/bfs: Disable under lockdown + +The BFS is not fuzz-clean. Don't allow it to be loaded under lockdown. +This will also disable the AFS. + +Fixes: CVE-2024-45778 +Fixes: CVE-2024-45779 + +Reported-by: Nils Langius +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/fs/bfs.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/grub-core/fs/bfs.c b/grub-core/fs/bfs.c +index 17705812d..760c6229a 100644 +--- a/grub-core/fs/bfs.c ++++ b/grub-core/fs/bfs.c +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -1104,8 +1105,11 @@ GRUB_MOD_INIT (bfs) + { + COMPILE_TIME_ASSERT (1 << LOG_EXTENT_SIZE == + sizeof (struct grub_bfs_extent)); +- grub_bfs_fs.mod = mod; +- grub_fs_register (&grub_bfs_fs); ++ if (!grub_is_lockdown ()) ++ { ++ grub_bfs_fs.mod = mod; ++ grub_fs_register (&grub_bfs_fs); ++ } + } + + #ifdef MODE_AFS +@@ -1114,5 +1118,6 @@ GRUB_MOD_FINI (afs) + GRUB_MOD_FINI (bfs) + #endif + { +- grub_fs_unregister (&grub_bfs_fs); ++ if (!grub_is_lockdown ()) ++ grub_fs_unregister (&grub_bfs_fs); + } diff --git a/0425-fs-Disable-many-filesystems-under-lockdown.patch b/0425-fs-Disable-many-filesystems-under-lockdown.patch new file mode 100644 index 0000000..8790913 --- /dev/null +++ b/0425-fs-Disable-many-filesystems-under-lockdown.patch @@ -0,0 +1,391 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Sat, 23 Mar 2024 16:20:45 +1100 +Subject: [PATCH] fs: Disable many filesystems under lockdown + +The idea is to permit the following: btrfs, cpio, exfat, ext, f2fs, fat, +hfsplus, iso9660, squash4, tar, xfs and zfs. + +The JFS, ReiserFS, romfs, UDF and UFS security vulnerabilities were +reported by Jonathan Bar Or . + +Fixes: CVE-2025-0677 +Fixes: CVE-2025-0684 +Fixes: CVE-2025-0685 +Fixes: CVE-2025-0686 +Fixes: CVE-2025-0689 + +Suggested-by: Daniel Axtens +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/fs/affs.c | 11 ++++++++--- + grub-core/fs/cbfs.c | 11 ++++++++--- + grub-core/fs/jfs.c | 11 ++++++++--- + grub-core/fs/minix.c | 11 ++++++++--- + grub-core/fs/nilfs2.c | 11 ++++++++--- + grub-core/fs/ntfs.c | 11 ++++++++--- + grub-core/fs/reiserfs.c | 11 ++++++++--- + grub-core/fs/romfs.c | 11 ++++++++--- + grub-core/fs/sfs.c | 11 ++++++++--- + grub-core/fs/udf.c | 11 ++++++++--- + grub-core/fs/ufs.c | 11 ++++++++--- + 11 files changed, 88 insertions(+), 33 deletions(-) + +diff --git a/grub-core/fs/affs.c b/grub-core/fs/affs.c +index b1c64e77d..0133528ea 100644 +--- a/grub-core/fs/affs.c ++++ b/grub-core/fs/affs.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -699,12 +700,16 @@ static struct grub_fs grub_affs_fs = + + GRUB_MOD_INIT(affs) + { +- grub_affs_fs.mod = mod; +- grub_fs_register (&grub_affs_fs); ++ if (!grub_is_lockdown ()) ++ { ++ grub_affs_fs.mod = mod; ++ grub_fs_register (&grub_affs_fs); ++ } + my_mod = mod; + } + + GRUB_MOD_FINI(affs) + { +- grub_fs_unregister (&grub_affs_fs); ++ if (!grub_is_lockdown ()) ++ grub_fs_unregister (&grub_affs_fs); + } +diff --git a/grub-core/fs/cbfs.c b/grub-core/fs/cbfs.c +index 3e527cbf2..90c07ddf8 100644 +--- a/grub-core/fs/cbfs.c ++++ b/grub-core/fs/cbfs.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -390,13 +391,17 @@ GRUB_MOD_INIT (cbfs) + #if (defined (__i386__) || defined (__x86_64__)) && !defined (GRUB_UTIL) && !defined (GRUB_MACHINE_EMU) && !defined (GRUB_MACHINE_XEN) + init_cbfsdisk (); + #endif +- grub_cbfs_fs.mod = mod; +- grub_fs_register (&grub_cbfs_fs); ++ if (!grub_is_lockdown ()) ++ { ++ grub_cbfs_fs.mod = mod; ++ grub_fs_register (&grub_cbfs_fs); ++ } + } + + GRUB_MOD_FINI (cbfs) + { +- grub_fs_unregister (&grub_cbfs_fs); ++ if (!grub_is_lockdown ()) ++ grub_fs_unregister (&grub_cbfs_fs); + #if (defined (__i386__) || defined (__x86_64__)) && !defined (GRUB_UTIL) && !defined (GRUB_MACHINE_EMU) && !defined (GRUB_MACHINE_XEN) + fini_cbfsdisk (); + #endif +diff --git a/grub-core/fs/jfs.c b/grub-core/fs/jfs.c +index b0283ac00..ab175c7f1 100644 +--- a/grub-core/fs/jfs.c ++++ b/grub-core/fs/jfs.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -1005,12 +1006,16 @@ static struct grub_fs grub_jfs_fs = + + GRUB_MOD_INIT(jfs) + { +- grub_jfs_fs.mod = mod; +- grub_fs_register (&grub_jfs_fs); ++ if (!grub_is_lockdown ()) ++ { ++ grub_jfs_fs.mod = mod; ++ grub_fs_register (&grub_jfs_fs); ++ } + my_mod = mod; + } + + GRUB_MOD_FINI(jfs) + { +- grub_fs_unregister (&grub_jfs_fs); ++ if (!grub_is_lockdown ()) ++ grub_fs_unregister (&grub_jfs_fs); + } +diff --git a/grub-core/fs/minix.c b/grub-core/fs/minix.c +index beb1a6378..fc7fa80d9 100644 +--- a/grub-core/fs/minix.c ++++ b/grub-core/fs/minix.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -732,8 +733,11 @@ GRUB_MOD_INIT(minix) + #endif + #endif + { +- grub_minix_fs.mod = mod; +- grub_fs_register (&grub_minix_fs); ++ if (!grub_is_lockdown ()) ++ { ++ grub_minix_fs.mod = mod; ++ grub_fs_register (&grub_minix_fs); ++ } + my_mod = mod; + } + +@@ -755,5 +759,6 @@ GRUB_MOD_FINI(minix) + #endif + #endif + { +- grub_fs_unregister (&grub_minix_fs); ++ if (!grub_is_lockdown ()) ++ grub_fs_unregister (&grub_minix_fs); + } +diff --git a/grub-core/fs/nilfs2.c b/grub-core/fs/nilfs2.c +index c44583ee8..dd10c08f3 100644 +--- a/grub-core/fs/nilfs2.c ++++ b/grub-core/fs/nilfs2.c +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -1231,12 +1232,16 @@ GRUB_MOD_INIT (nilfs2) + grub_nilfs2_dat_entry)); + COMPILE_TIME_ASSERT (1 << LOG_INODE_SIZE + == sizeof (struct grub_nilfs2_inode)); +- grub_nilfs2_fs.mod = mod; +- grub_fs_register (&grub_nilfs2_fs); ++ if (!grub_is_lockdown ()) ++ { ++ grub_nilfs2_fs.mod = mod; ++ grub_fs_register (&grub_nilfs2_fs); ++ } + my_mod = mod; + } + + GRUB_MOD_FINI (nilfs2) + { +- grub_fs_unregister (&grub_nilfs2_fs); ++ if (!grub_is_lockdown ()) ++ grub_fs_unregister (&grub_nilfs2_fs); + } +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index 03e3e5c6a..96f038c54 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -1537,12 +1538,16 @@ static struct grub_fs grub_ntfs_fs = + + GRUB_MOD_INIT (ntfs) + { +- grub_ntfs_fs.mod = mod; +- grub_fs_register (&grub_ntfs_fs); ++ if (!grub_is_lockdown ()) ++ { ++ grub_ntfs_fs.mod = mod; ++ grub_fs_register (&grub_ntfs_fs); ++ } + my_mod = mod; + } + + GRUB_MOD_FINI (ntfs) + { +- grub_fs_unregister (&grub_ntfs_fs); ++ if (!grub_is_lockdown ()) ++ grub_fs_unregister (&grub_ntfs_fs); + } +diff --git a/grub-core/fs/reiserfs.c b/grub-core/fs/reiserfs.c +index d9a8bf602..84aadfae9 100644 +--- a/grub-core/fs/reiserfs.c ++++ b/grub-core/fs/reiserfs.c +@@ -39,6 +39,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -1407,12 +1408,16 @@ static struct grub_fs grub_reiserfs_fs = + + GRUB_MOD_INIT(reiserfs) + { +- grub_reiserfs_fs.mod = mod; +- grub_fs_register (&grub_reiserfs_fs); ++ if (!grub_is_lockdown ()) ++ { ++ grub_reiserfs_fs.mod = mod; ++ grub_fs_register (&grub_reiserfs_fs); ++ } + my_mod = mod; + } + + GRUB_MOD_FINI(reiserfs) + { +- grub_fs_unregister (&grub_reiserfs_fs); ++ if (!grub_is_lockdown ()) ++ grub_fs_unregister (&grub_reiserfs_fs); + } +diff --git a/grub-core/fs/romfs.c b/grub-core/fs/romfs.c +index a43546d95..6ee469911 100644 +--- a/grub-core/fs/romfs.c ++++ b/grub-core/fs/romfs.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -475,11 +476,15 @@ static struct grub_fs grub_romfs_fs = + + GRUB_MOD_INIT(romfs) + { +- grub_romfs_fs.mod = mod; +- grub_fs_register (&grub_romfs_fs); ++ if (!grub_is_lockdown ()) ++ { ++ grub_romfs_fs.mod = mod; ++ grub_fs_register (&grub_romfs_fs); ++ } + } + + GRUB_MOD_FINI(romfs) + { +- grub_fs_unregister (&grub_romfs_fs); ++ if (!grub_is_lockdown ()) ++ grub_fs_unregister (&grub_romfs_fs); + } +diff --git a/grub-core/fs/sfs.c b/grub-core/fs/sfs.c +index f0d7cac43..88705b3a2 100644 +--- a/grub-core/fs/sfs.c ++++ b/grub-core/fs/sfs.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + #include + + GRUB_MOD_LICENSE ("GPLv3+"); +@@ -779,12 +780,16 @@ static struct grub_fs grub_sfs_fs = + + GRUB_MOD_INIT(sfs) + { +- grub_sfs_fs.mod = mod; +- grub_fs_register (&grub_sfs_fs); ++ if (!grub_is_lockdown ()) ++ { ++ grub_sfs_fs.mod = mod; ++ grub_fs_register (&grub_sfs_fs); ++ } + my_mod = mod; + } + + GRUB_MOD_FINI(sfs) + { +- grub_fs_unregister (&grub_sfs_fs); ++ if (!grub_is_lockdown ()) ++ grub_fs_unregister (&grub_sfs_fs); + } +diff --git a/grub-core/fs/udf.c b/grub-core/fs/udf.c +index 3d4b40263..c0c31ae9c 100644 +--- a/grub-core/fs/udf.c ++++ b/grub-core/fs/udf.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -1382,12 +1383,16 @@ static struct grub_fs grub_udf_fs = { + + GRUB_MOD_INIT (udf) + { +- grub_udf_fs.mod = mod; +- grub_fs_register (&grub_udf_fs); ++ if (!grub_is_lockdown ()) ++ { ++ grub_udf_fs.mod = mod; ++ grub_fs_register (&grub_udf_fs); ++ } + my_mod = mod; + } + + GRUB_MOD_FINI (udf) + { +- grub_fs_unregister (&grub_udf_fs); ++ if (!grub_is_lockdown ()) ++ grub_fs_unregister (&grub_udf_fs); + } +diff --git a/grub-core/fs/ufs.c b/grub-core/fs/ufs.c +index 7f72494cd..22b669b4c 100644 +--- a/grub-core/fs/ufs.c ++++ b/grub-core/fs/ufs.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -899,8 +900,11 @@ GRUB_MOD_INIT(ufs1) + #endif + #endif + { +- grub_ufs_fs.mod = mod; +- grub_fs_register (&grub_ufs_fs); ++ if (!grub_is_lockdown ()) ++ { ++ grub_ufs_fs.mod = mod; ++ grub_fs_register (&grub_ufs_fs); ++ } + my_mod = mod; + } + +@@ -914,6 +918,7 @@ GRUB_MOD_FINI(ufs1) + #endif + #endif + { +- grub_fs_unregister (&grub_ufs_fs); ++ if (!grub_is_lockdown ()) ++ grub_fs_unregister (&grub_ufs_fs); + } + diff --git a/0426-disk-plainmount-Support-plain-encryption-mode.patch b/0426-disk-plainmount-Support-plain-encryption-mode.patch new file mode 100644 index 0000000..839780b --- /dev/null +++ b/0426-disk-plainmount-Support-plain-encryption-mode.patch @@ -0,0 +1,603 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Maxim Fomin +Date: Wed, 28 Dec 2022 17:20:00 +0000 +Subject: [PATCH] disk/plainmount: Support plain encryption mode + +This patch adds support for plain encryption mode, plain dm-crypt, via +new module/command named "plainmount". + +Signed-off-by: Maxim Fomin +Reviewed-by: Daniel Kiper +Reviewed-by: Glenn Washburn +--- + docs/grub.texi | 80 ++++++++ + grub-core/Makefile.core.def | 5 + + grub-core/disk/plainmount.c | 458 ++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 543 insertions(+) + create mode 100644 grub-core/disk/plainmount.c + +diff --git a/docs/grub.texi b/docs/grub.texi +index 913c3bff3..50c37d6ff 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -4052,6 +4052,7 @@ you forget a command, you can run the command @command{help} + * parttool:: Modify partition table entries + * password:: Set a clear-text password + * password_pbkdf2:: Set a hashed password ++* plainmount:: Open device encrypted in plain mode + * play:: Play a tune + * probe:: Retrieve device info + * rdmsr:: Read values from model-specific registers +@@ -4344,6 +4345,14 @@ function is supported, as Argon2 is not yet supported. + + Also, note that, unlike filesystem UUIDs, UUIDs for encrypted devices must be + specified without dash separators. ++ ++Successfully decrypted disks are named as (cryptoX) and have increasing numeration ++suffix for each new decrypted disk. If the encrypted disk hosts some higher level ++of abstraction (like LVM2 or MDRAID) it will be created under a separate device ++namespace in addition to the cryptodisk namespace. ++ ++Support for plain encryption mode (plain dm-crypt) is provided via separate ++@command{@pxref{plainmount}} command. + @end deffn + + @node cutmem +@@ -4990,6 +4999,77 @@ to generate password hashes. @xref{Security}. + @end deffn + + ++@node plainmount ++@subsection plainmount ++ ++@deffn Command plainmount device @option{-c} cipher @option{-s} key size [@option{-h} hash] ++[@option{-S} sector size] [@option{-p} password] [@option{-u} uuid] ++[[@option{-d} keyfile] [@option{-O} keyfile offset]] ++ ++ ++Setup access to the encrypted device in plain mode. Offset of the encrypted ++data at the device is specified in terms of 512 byte sectors using the blocklist ++syntax and loopback device. The following example shows how to specify 1MiB ++offset: ++ ++@example ++loopback node (hd0,gpt1)2048+ ++plainmount node @var{...} ++@end example ++ ++The @command{plainmount} command can be used to open LUKS encrypted volume ++if its master key and parameters (key size, cipher, offset, etc) are known. ++ ++There are two ways to specify a password: a keyfile and a secret passphrase. ++The keyfile path parameter has higher priority than the secret passphrase ++parameter and is specified with the option @option{-d}. Password data obtained ++from keyfiles is not hashed and is used directly as a cipher key. An optional ++offset of password data in the keyfile can be specified with the option ++@option{-O} or directly with the option @option{-d} and GRUB blocklist syntax, ++if the keyfile data can be accessed from a device and is 512 byte aligned. ++The following example shows both methods to specify password data in the ++keyfile at offset 1MiB: ++ ++@example ++plainmount -d (hd0,gpt1)2048+ @var{...} ++plainmount -d (hd0,gpt1)+ -O 1048576 @var{...} ++@end example ++ ++If no keyfile is specified then the password is set to the string specified ++by option @option{-p} or is requested interactively from the console. In both ++cases the provided password is hashed with the algorithm specified by the ++option @option{-h}. This option is mandatory if no keyfile is specified, but ++it can be set to @samp{plain} which means that no hashing is done and such ++password is used directly as a key. ++ ++Cipher @option{-c} and keysize @option{-s} options specify the cipher algorithm ++and the key size respectively and are mandatory options. Cipher must be specified ++with the mode separated by a dash (for example, @samp{aes-xts-plain64}). Key size ++option @option{-s} is the key size of the cipher in bits, not to be confused with ++the offset of the key data in a keyfile specified with the @option{-O} option. It ++must not exceed 1024 bits, so a 32 byte key would be specified as 256 bits ++ ++The optional parameter @option{-S} specifies encrypted device sector size. It ++must be at least 512 bytes long (default value) and a power of 2. @footnote{Current ++implementation of cryptsetup supports only 512/1024/2048/4096 byte sectors}. ++Disk sector size is configured when creating the encrypted volume. Attempting ++to decrypt volumes with a different sector size than it was created with will ++not result in an error, but will decrypt to random bytes and thus prevent ++accessing the volume (in some cases the filesystem driver can detect the presence ++of a filesystem, but nevertheless will refuse to mount it). ++ ++By default new plainmount devices will be given a UUID starting with ++'109fea84-a6b7-34a8-4bd1-1c506305a401' where the last digits are incremented ++by one for each plainmounted device beyond the first up to 2^10 devices. ++ ++All encryption arguments (cipher, hash, key size, disk offset and disk sector ++size) must match the parameters used to create the volume. If any of them does ++not match the actual arguments used during the initial encryption, plainmount ++will create virtual device with the garbage data and GRUB will report unknown ++filesystem for such device. ++@end deffn ++ ++ + @node play + @subsection play + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 505c3b63d..b8e29c788 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -1239,6 +1239,11 @@ module = { + common = disk/cryptodisk.c; + }; + ++module = { ++ name = plainmount; ++ common = disk/plainmount.c; ++}; ++ + module = { + name = json; + common = lib/json/json.c; +diff --git a/grub-core/disk/plainmount.c b/grub-core/disk/plainmount.c +new file mode 100644 +index 000000000..47e64805f +--- /dev/null ++++ b/grub-core/disk/plainmount.c +@@ -0,0 +1,458 @@ ++/* ++ * 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 . ++ */ ++ ++/* plaimount.c - Open device encrypted in plain mode. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++#define PLAINMOUNT_DEFAULT_SECTOR_SIZE 512 ++#define PLAINMOUNT_DEFAULT_UUID "109fea84-a6b7-34a8-4bd1-1c506305a400" ++ ++ ++enum PLAINMOUNT_OPTION ++ { ++ OPTION_HASH, ++ OPTION_CIPHER, ++ OPTION_KEY_SIZE, ++ OPTION_SECTOR_SIZE, ++ OPTION_PASSWORD, ++ OPTION_KEYFILE, ++ OPTION_KEYFILE_OFFSET, ++ OPTION_UUID ++ }; ++ ++static const struct grub_arg_option options[] = ++ { ++ /* TRANSLATORS: It's still restricted to this module only. */ ++ {"hash", 'h', 0, N_("Password hash"), 0, ARG_TYPE_STRING}, ++ {"cipher", 'c', 0, N_("Password cipher"), 0, ARG_TYPE_STRING}, ++ {"key-size", 's', 0, N_("Key size (in bits)"), 0, ARG_TYPE_INT}, ++ {"sector-size", 'S', 0, N_("Device sector size"), 0, ARG_TYPE_INT}, ++ {"password", 'p', 0, N_("Password (key)"), 0, ARG_TYPE_STRING}, ++ {"keyfile", 'd', 0, N_("Keyfile path"), 0, ARG_TYPE_STRING}, ++ {"keyfile-offset", 'O', 0, N_("Keyfile offset"), 0, ARG_TYPE_INT}, ++ {"uuid", 'u', 0, N_("Set device UUID"), 0, ARG_TYPE_STRING}, ++ {0, 0, 0, 0, 0, 0} ++ }; ++ ++/* Cryptodisk setkey() function wrapper */ ++static grub_err_t ++plainmount_setkey (grub_cryptodisk_t dev, grub_uint8_t *key, ++ grub_size_t size) ++{ ++ gcry_err_code_t code = grub_cryptodisk_setkey (dev, key, size); ++ if (code != GPG_ERR_NO_ERROR) ++ { ++ grub_dprintf ("plainmount", "failed to set cipher key with code: %d\n", code); ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("cannot set specified key")); ++ } ++ return GRUB_ERR_NONE; ++} ++ ++/* Configure cryptodisk uuid */ ++static void plainmount_set_uuid (grub_cryptodisk_t dev, const char *user_uuid) ++{ ++ grub_size_t pos = 0; ++ ++ /* Size of user_uuid is checked in main func */ ++ if (user_uuid != NULL) ++ grub_strcpy (dev->uuid, user_uuid); ++ else ++ { ++ /* ++ * Set default UUID. Last digits start from 1 and are incremented for ++ * each new plainmount device by snprintf(). ++ */ ++ grub_snprintf (dev->uuid, sizeof (dev->uuid) - 1, "%36lx", dev->id + 1); ++ while (dev->uuid[++pos] == ' '); ++ grub_memcpy (dev->uuid, PLAINMOUNT_DEFAULT_UUID, pos); ++ } ++ COMPILE_TIME_ASSERT (sizeof (dev->uuid) >= sizeof (PLAINMOUNT_DEFAULT_UUID)); ++} ++ ++/* Configure cryptodevice sector size (-S option) */ ++static grub_err_t ++plainmount_configure_sectors (grub_cryptodisk_t dev, grub_disk_t disk, ++ grub_size_t sector_size) ++{ ++ dev->total_sectors = grub_disk_native_sectors (disk); ++ if (dev->total_sectors == GRUB_DISK_SIZE_UNKNOWN) ++ return grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot determine disk %s size"), ++ disk->name); ++ ++ /* Convert size to sectors */ ++ dev->log_sector_size = grub_log2ull (sector_size); ++ dev->total_sectors = grub_convert_sector (dev->total_sectors, ++ GRUB_DISK_SECTOR_BITS, ++ dev->log_sector_size); ++ if (dev->total_sectors == 0) ++ return grub_error (GRUB_ERR_BAD_DEVICE, ++ N_("cannot set specified sector size on disk %s"), ++ disk->name); ++ ++ grub_dprintf ("plainmount", "log_sector_size=%d, total_sectors=%" ++ PRIuGRUB_UINT64_T"\n", dev->log_sector_size, dev->total_sectors); ++ return GRUB_ERR_NONE; ++} ++ ++/* Hashes a password into a key and stores it with the cipher. */ ++static grub_err_t ++plainmount_configure_password (grub_cryptodisk_t dev, const char *hash, ++ grub_uint8_t *key_data, grub_size_t key_size, ++ grub_size_t password_size) ++{ ++ grub_uint8_t *derived_hash, *dh; ++ char *p; ++ unsigned int round, i, len, size; ++ grub_size_t alloc_size; ++ grub_err_t err = GRUB_ERR_NONE; ++ ++ /* Support none (plain) hash */ ++ if (grub_strcmp (hash, "plain") == 0) ++ { ++ dev->hash = NULL; ++ return err; ++ } ++ ++ /* Hash argument was checked at main func */ ++ dev->hash = grub_crypto_lookup_md_by_name (hash); ++ len = dev->hash->mdlen; ++ ++ alloc_size = grub_max (password_size, key_size); ++ /* ++ * Allocate buffer for the password and for an added prefix character ++ * for each hash round ('alloc_size' may not be a multiple of 'len'). ++ */ ++ p = grub_zalloc (alloc_size + (alloc_size / len) + 1); ++ derived_hash = grub_zalloc (GRUB_CRYPTODISK_MAX_KEYLEN * 2); ++ if (p == NULL || derived_hash == NULL) ++ { ++ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory"); ++ goto fail; ++ } ++ dh = derived_hash; ++ ++ /* ++ * Hash password. Adapted from cryptsetup. ++ * https://gitlab.com/cryptsetup/cryptsetup/-/blob/main/lib/crypt_plain.c ++ */ ++ for (round = 0, size = alloc_size; size; round++, dh += len, size -= len) ++ { ++ for (i = 0; i < round; i++) ++ p[i] = 'A'; ++ ++ grub_memcpy (p + i, (char*) key_data, password_size); ++ ++ if (len > size) ++ len = size; ++ ++ grub_crypto_hash (dev->hash, dh, p, password_size + round); ++ } ++ grub_memcpy (key_data, derived_hash, key_size); ++ ++ fail: ++ grub_free (p); ++ grub_free (derived_hash); ++ return err; ++} ++ ++/* Read key material from keyfile */ ++static grub_err_t ++plainmount_configure_keyfile (char *keyfile, grub_uint8_t *key_data, ++ grub_size_t key_size, grub_size_t keyfile_offset) ++{ ++ grub_file_t g_keyfile = grub_file_open (keyfile, GRUB_FILE_TYPE_NONE); ++ if (g_keyfile == NULL) ++ return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("cannot open keyfile %s"), ++ keyfile); ++ ++ if (grub_file_seek (g_keyfile, keyfile_offset) == (grub_off_t) - 1) ++ return grub_error (GRUB_ERR_FILE_READ_ERROR, ++ N_("cannot seek keyfile at offset %"PRIuGRUB_SIZE), ++ keyfile_offset); ++ ++ if (key_size > (g_keyfile->size - keyfile_offset)) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Specified key size (%" ++ PRIuGRUB_SIZE") is too small for keyfile size (%" ++ PRIuGRUB_UINT64_T") and offset (%"PRIuGRUB_SIZE")"), ++ key_size, g_keyfile->size, keyfile_offset); ++ ++ if (grub_file_read (g_keyfile, key_data, key_size) != (grub_ssize_t) key_size) ++ return grub_error (GRUB_ERR_FILE_READ_ERROR, N_("error reading key file")); ++ return GRUB_ERR_NONE; ++} ++ ++/* Plainmount command entry point */ ++static grub_err_t ++grub_cmd_plainmount (grub_extcmd_context_t ctxt, int argc, char **args) ++{ ++ struct grub_arg_list *state = ctxt->state; ++ grub_cryptodisk_t dev = NULL; ++ grub_disk_t disk = NULL; ++ const gcry_md_spec_t *gcry_hash; ++ char *diskname, *disklast = NULL, *cipher, *mode, *hash, *keyfile, *uuid; ++ grub_size_t len, key_size, sector_size, keyfile_offset = 0, password_size = 0; ++ grub_err_t err; ++ const char *p; ++ grub_uint8_t *key_data; ++ ++ if (argc < 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("device name required")); ++ ++ /* Check whether required arguments are specified */ ++ if (!state[OPTION_CIPHER].set || !state[OPTION_KEY_SIZE].set) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "cipher and key size must be set"); ++ if (!state[OPTION_HASH].set && !state[OPTION_KEYFILE].set) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "hash algorithm must be set"); ++ ++ /* Check hash */ ++ if (!state[OPTION_KEYFILE].set) ++ { ++ gcry_hash = grub_crypto_lookup_md_by_name (state[OPTION_HASH].arg); ++ if (!gcry_hash) ++ return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("couldn't load hash %s"), ++ state[OPTION_HASH].arg); ++ ++ if (gcry_hash->mdlen > GRUB_CRYPTODISK_MAX_KEYLEN) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("hash length %"PRIuGRUB_SIZE" exceeds maximum %d bits"), ++ gcry_hash->mdlen * GRUB_CHAR_BIT, ++ GRUB_CRYPTODISK_MAX_KEYLEN * GRUB_CHAR_BIT); ++ } ++ ++ /* Check cipher mode */ ++ if (!grub_strchr (state[OPTION_CIPHER].arg,'-')) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("invalid cipher mode, must be of format cipher-mode")); ++ ++ /* Check password size */ ++ if (state[OPTION_PASSWORD].set && grub_strlen (state[OPTION_PASSWORD].arg) > ++ GRUB_CRYPTODISK_MAX_PASSPHRASE) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("password exceeds maximium size")); ++ ++ /* Check uuid length */ ++ if (state[OPTION_UUID].set && grub_strlen (state[OPTION_UUID].arg) > ++ GRUB_CRYPTODISK_MAX_UUID_LENGTH - 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("specified UUID exceeds maximum size")); ++ if (state[OPTION_UUID].set && grub_strlen (state[OPTION_UUID].arg) == 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("specified UUID too short")); ++ ++ /* Parse plainmount arguments */ ++ grub_errno = GRUB_ERR_NONE; ++ keyfile_offset = state[OPTION_KEYFILE_OFFSET].set ? ++ grub_strtoull (state[OPTION_KEYFILE_OFFSET].arg, &p, 0) : 0; ++ if (state[OPTION_KEYFILE_OFFSET].set && ++ (state[OPTION_KEYFILE_OFFSET].arg[0] == '\0' || *p != '\0' || ++ grub_errno != GRUB_ERR_NONE)) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unrecognized keyfile offset")); ++ ++ sector_size = state[OPTION_SECTOR_SIZE].set ? ++ grub_strtoull (state[OPTION_SECTOR_SIZE].arg, &p, 0) : ++ PLAINMOUNT_DEFAULT_SECTOR_SIZE; ++ if (state[OPTION_SECTOR_SIZE].set && (state[OPTION_SECTOR_SIZE].arg[0] == '\0' || ++ *p != '\0' || grub_errno != GRUB_ERR_NONE)) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unrecognized sector size")); ++ ++ /* Check key size */ ++ key_size = grub_strtoull (state[OPTION_KEY_SIZE].arg, &p, 0); ++ if (state[OPTION_KEY_SIZE].arg[0] == '\0' || *p != '\0' || ++ grub_errno != GRUB_ERR_NONE) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unrecognized key size")); ++ if ((key_size % GRUB_CHAR_BIT) != 0) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("key size is not multiple of %d bits"), GRUB_CHAR_BIT); ++ key_size = key_size / GRUB_CHAR_BIT; ++ if (key_size > GRUB_CRYPTODISK_MAX_KEYLEN) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("key size %"PRIuGRUB_SIZE" exceeds maximum %d bits"), ++ key_size * GRUB_CHAR_BIT, ++ GRUB_CRYPTODISK_MAX_KEYLEN * GRUB_CHAR_BIT); ++ ++ /* Check disk sector size */ ++ if (sector_size < GRUB_DISK_SECTOR_SIZE) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("sector size -S must be at least %d"), ++ GRUB_DISK_SECTOR_SIZE); ++ if ((sector_size & (sector_size - 1)) != 0) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("sector size -S %"PRIuGRUB_SIZE" is not power of 2"), ++ sector_size); ++ ++ /* Allocate all stuff here */ ++ hash = state[OPTION_HASH].set ? grub_strdup (state[OPTION_HASH].arg) : NULL; ++ cipher = grub_strdup (state[OPTION_CIPHER].arg); ++ keyfile = state[OPTION_KEYFILE].set ? ++ grub_strdup (state[OPTION_KEYFILE].arg) : NULL; ++ dev = grub_zalloc (sizeof *dev); ++ key_data = grub_zalloc (GRUB_CRYPTODISK_MAX_PASSPHRASE); ++ uuid = state[OPTION_UUID].set ? grub_strdup (state[OPTION_UUID].arg) : NULL; ++ if ((state[OPTION_HASH].set && hash == NULL) || cipher == NULL || dev == NULL || ++ (state[OPTION_KEYFILE].set && keyfile == NULL) || key_data == NULL || ++ (state[OPTION_UUID].set && uuid == NULL)) ++ { ++ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory"); ++ goto fail; ++ } ++ ++ /* Copy user password from -p option */ ++ if (state[OPTION_PASSWORD].set) ++ { ++ /* ++ * Password from the '-p' option is limited to C-string. ++ * Arbitrary data keys are supported via keyfiles. ++ */ ++ password_size = grub_strlen (state[OPTION_PASSWORD].arg); ++ grub_strcpy ((char*) key_data, state[OPTION_PASSWORD].arg); ++ } ++ ++ /* Set cipher mode (tested above) */ ++ mode = grub_strchr (cipher,'-'); ++ *mode++ = '\0'; ++ ++ /* Check cipher */ ++ err = grub_cryptodisk_setcipher (dev, cipher, mode); ++ if (err != GRUB_ERR_NONE) ++ { ++ if (err == GRUB_ERR_FILE_NOT_FOUND) ++ err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid cipher %s"), cipher); ++ else if (err == GRUB_ERR_BAD_ARGUMENT) ++ err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid mode %s"), mode); ++ else ++ err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid cipher %s or mode %s"), ++ cipher, mode); ++ goto fail; ++ } ++ ++ /* Open SOURCE disk */ ++ diskname = args[0]; ++ len = grub_strlen (diskname); ++ if (len && diskname[0] == '(' && diskname[len - 1] == ')') ++ { ++ disklast = &diskname[len - 1]; ++ *disklast = '\0'; ++ diskname++; ++ } ++ disk = grub_disk_open (diskname); ++ if (disk == NULL) ++ { ++ if (disklast) ++ *disklast = ')'; ++ err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("cannot open disk %s"), diskname); ++ goto fail; ++ } ++ ++ /* Get password from console */ ++ if (!state[OPTION_KEYFILE].set && key_data[0] == '\0') ++ { ++ char *part = grub_partition_get_name (disk->partition); ++ grub_printf_ (N_("Enter passphrase for %s%s%s: "), disk->name, ++ disk->partition != NULL ? "," : "", ++ part != NULL ? part : N_("UNKNOWN")); ++ grub_free (part); ++ ++ if (!grub_password_get ((char*) key_data, GRUB_CRYPTODISK_MAX_PASSPHRASE - 1)) ++ { ++ err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("error reading password")); ++ goto fail; ++ } ++ /* ++ * Password from interactive console is limited to C-string. ++ * Arbitrary data keys are supported via keyfiles. ++ */ ++ password_size = grub_strlen ((char*) key_data); ++ } ++ ++ /* Warn if hash and keyfile are both provided */ ++ if (state[OPTION_KEYFILE].set && state[OPTION_HASH].arg) ++ grub_printf_ (N_("warning: hash is ignored if keyfile is specified\n")); ++ ++ /* Warn if -p option is specified with keyfile */ ++ if (state[OPTION_PASSWORD].set && state[OPTION_KEYFILE].set) ++ grub_printf_ (N_("warning: password specified with -p option " ++ "is ignored if keyfile is provided\n")); ++ ++ /* Warn of -O is provided without keyfile */ ++ if (state[OPTION_KEYFILE_OFFSET].set && !state[OPTION_KEYFILE].set) ++ grub_printf_ (N_("warning: keyfile offset option -O " ++ "specified without keyfile option -d\n")); ++ ++ grub_dprintf ("plainmount", "parameters: cipher=%s, hash=%s, key_size=%" ++ PRIuGRUB_SIZE ", keyfile=%s, keyfile offset=%" PRIuGRUB_SIZE "\n", ++ cipher, hash, key_size, keyfile, keyfile_offset); ++ ++ err = plainmount_configure_sectors (dev, disk, sector_size); ++ if (err != GRUB_ERR_NONE) ++ goto fail; ++ ++ /* Configure keyfile or password */ ++ if (state[OPTION_KEYFILE].set) ++ err = plainmount_configure_keyfile (keyfile, key_data, key_size, keyfile_offset); ++ else ++ err = plainmount_configure_password (dev, hash, key_data, key_size, password_size); ++ if (err != GRUB_ERR_NONE) ++ goto fail; ++ ++ err = plainmount_setkey (dev, key_data, key_size); ++ if (err != GRUB_ERR_NONE) ++ goto fail; ++ ++ err = grub_cryptodisk_insert (dev, diskname, disk); ++ if (err != GRUB_ERR_NONE) ++ goto fail; ++ ++ dev->modname = "plainmount"; ++ dev->source_disk = disk; ++ plainmount_set_uuid (dev, uuid); ++ ++ fail: ++ grub_free (hash); ++ grub_free (cipher); ++ grub_free (keyfile); ++ grub_free (key_data); ++ grub_free (uuid); ++ if (err != GRUB_ERR_NONE && disk != NULL) ++ grub_disk_close (disk); ++ if (err != GRUB_ERR_NONE) ++ grub_free (dev); ++ return err; ++} ++ ++static grub_extcmd_t cmd; ++GRUB_MOD_INIT (plainmount) ++{ ++ cmd = grub_register_extcmd ("plainmount", grub_cmd_plainmount, 0, ++ N_("-c cipher -s key-size [-h hash] [-S sector-size]" ++ " [-o offset] [-p password] [-u uuid] " ++ " [[-d keyfile] [-O keyfile offset]] "), ++ N_("Open partition encrypted in plain mode."), ++ options); ++} ++ ++GRUB_MOD_FINI (plainmount) ++{ ++ grub_unregister_extcmd (cmd); ++} diff --git a/0427-disk-Use-safe-math-macros-to-prevent-overflows.patch b/0427-disk-Use-safe-math-macros-to-prevent-overflows.patch new file mode 100644 index 0000000..cf0e1ea --- /dev/null +++ b/0427-disk-Use-safe-math-macros-to-prevent-overflows.patch @@ -0,0 +1,543 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Alec Brown +Date: Tue, 11 Feb 2025 17:59:04 -0600 +Subject: [PATCH] disk: Use safe math macros to prevent overflows + +Replace direct arithmetic operations with macros from include/grub/safemath.h +to prevent potential overflow issues when calculating the memory sizes. + +Signed-off-by: Alec Brown +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 36 ++++++++++++++++++------ + grub-core/disk/diskfilter.c | 9 ++++-- + grub-core/disk/ieee1275/obdisk.c | 43 ++++++++++++++++++++++++---- + grub-core/disk/ieee1275/ofdisk.c | 60 ++++++++++++++++++++++++++++++++++------ + grub-core/disk/ldm.c | 36 ++++++++++++++++++++---- + grub-core/disk/luks2.c | 7 ++++- + grub-core/disk/memdisk.c | 7 ++++- + grub-core/disk/plainmount.c | 9 ++++-- + 8 files changed, 172 insertions(+), 35 deletions(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 9c456c2..bd5eaf0 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + #ifdef GRUB_UTIL + #include +@@ -1475,7 +1476,7 @@ static char * + luks_script_get (grub_size_t *sz) + { + grub_cryptodisk_t i; +- grub_size_t size = 0; ++ grub_size_t size = 0, mul; + char *ptr, *ret; + + *sz = 0; +@@ -1484,10 +1485,6 @@ luks_script_get (grub_size_t *sz) + if (grub_strcmp (i->modname, "luks") == 0 || + grub_strcmp (i->modname, "luks2") == 0) + { +- size += grub_strlen (i->modname); +- size += sizeof ("_mount"); +- size += grub_strlen (i->uuid); +- size += grub_strlen (i->cipher->cipher->name); + /* + * Add space in the line for (in order) spaces, cipher mode, cipher IV + * mode, sector offset, sector size and the trailing newline. This is +@@ -1495,14 +1492,35 @@ luks_script_get (grub_size_t *sz) + * in an earlier version of this code that are unaccounted for. It is + * left in the calculations in case it is needed. At worst, its short- + * lived wasted space. ++ * ++ * 60 = 5 + 5 + 8 + 20 + 6 + 1 + 15 + */ +- size += 5 + 5 + 8 + 20 + 6 + 1 + 15; ++ if (grub_add (size, grub_strlen (i->modname), &size) || ++ grub_add (size, sizeof ("_mount") + 60, &size) || ++ grub_add (size, grub_strlen (i->uuid), &size) || ++ grub_add (size, grub_strlen (i->cipher->cipher->name), &size) || ++ grub_mul (i->keysize, 2, &mul) || ++ grub_add (size, mul, &size)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while obtaining size of luks script"); ++ return 0; ++ } + if (i->essiv_hash) +- size += grub_strlen (i->essiv_hash->name); +- size += i->keysize * 2; ++ { ++ if (grub_add (size, grub_strlen (i->essiv_hash->name), &size)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while obtaining size of luks script"); ++ return 0; ++ } ++ } + } ++ if (grub_add (size, 1, &size)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while obtaining size of luks script"); ++ return 0; ++ } + +- ret = grub_malloc (size + 1); ++ ret = grub_malloc (size); + if (!ret) + return 0; + +diff --git a/grub-core/disk/diskfilter.c b/grub-core/disk/diskfilter.c +index 7cdffe3..4c0b568 100644 +--- a/grub-core/disk/diskfilter.c ++++ b/grub-core/disk/diskfilter.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #ifdef GRUB_UTIL + #include + #include +@@ -1016,7 +1017,7 @@ grub_diskfilter_make_raid (grub_size_t uuidlen, char *uuid, int nmemb, + { + struct grub_diskfilter_vg *array; + int i; +- grub_size_t j; ++ grub_size_t j, sz; + grub_uint64_t totsize; + struct grub_diskfilter_pv *pv; + grub_err_t err; +@@ -1110,7 +1111,11 @@ grub_diskfilter_make_raid (grub_size_t uuidlen, char *uuid, int nmemb, + } + array->lvs->vg = array; + +- array->lvs->idname = grub_malloc (sizeof ("mduuid/") + 2 * uuidlen); ++ if (grub_mul (uuidlen, 2, &sz) || ++ grub_add (sz, sizeof ("mduuid/"), &sz)) ++ goto fail; ++ ++ array->lvs->idname = grub_malloc (sz); + if (!array->lvs->idname) + goto fail; + +diff --git a/grub-core/disk/ieee1275/obdisk.c b/grub-core/disk/ieee1275/obdisk.c +index ec413c3..8e4bbf1 100644 +--- a/grub-core/disk/ieee1275/obdisk.c ++++ b/grub-core/disk/ieee1275/obdisk.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -128,9 +129,17 @@ count_commas (const char *src) + static char * + decode_grub_devname (const char *name) + { +- char *devpath = grub_malloc (grub_strlen (name) + 1); ++ char *devpath; + char *p, c; ++ grub_size_t sz; + ++ if (grub_add (grub_strlen (name), 1, &sz)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining size of device name")); ++ return NULL; ++ } ++ ++ devpath = grub_malloc (sz); + if (devpath == NULL) + return NULL; + +@@ -156,12 +165,20 @@ static char * + encode_grub_devname (const char *path) + { + char *encoding, *optr; ++ grub_size_t sz; + + if (path == NULL) + return NULL; + +- encoding = grub_malloc (sizeof (IEEE1275_DEV) + count_commas (path) + +- grub_strlen (path) + 1); ++ if (grub_add (sizeof (IEEE1275_DEV) + 1, count_commas (path), &sz) || ++ grub_add (sz, grub_strlen (path), &sz)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining encoding size")); ++ grub_print_error (); ++ return NULL; ++ } ++ ++ encoding = grub_malloc (sz); + + if (encoding == NULL) + { +@@ -396,6 +413,14 @@ canonicalise_disk (const char *devname) + + real_unit_str_len = grub_strlen (op->name) + sizeof (IEEE1275_DISK_ALIAS) + + grub_strlen (real_unit_address); ++ if (grub_add (grub_strlen (op->name), sizeof (IEEE1275_DISK_ALIAS), &real_unit_str_len) || ++ grub_add (real_unit_str_len, grub_strlen (real_unit_address), &real_unit_str_len)) ++ { ++ grub_free (parent); ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining size of canonical name")); ++ grub_print_error (); ++ return NULL; ++ } + + real_canon = grub_malloc (real_unit_str_len); + +@@ -413,6 +438,7 @@ canonicalise_disk (const char *devname) + static struct disk_dev * + add_canon_disk (const char *cname) + { ++ grub_size_t sz; + struct disk_dev *dev; + + dev = grub_zalloc (sizeof (struct disk_dev)); +@@ -428,13 +454,18 @@ add_canon_disk (const char *cname) + * arguments and allows a client program to open + * the entire (raw) disk. Any disk label is ignored. + */ +- dev->raw_name = grub_malloc (grub_strlen (cname) + sizeof (":nolabel")); ++ if (grub_add (grub_strlen (cname), sizeof (":nolabel"), &sz)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while appending :nolabel to end of canonical name"); ++ goto failed; ++ } ++ ++ dev->raw_name = grub_malloc (sz); + + if (dev->raw_name == NULL) + goto failed; + +- grub_snprintf (dev->raw_name, grub_strlen (cname) + sizeof (":nolabel"), +- "%s:nolabel", cname); ++ grub_snprintf (dev->raw_name, sz, "%s:nolabel", cname); + } + + /* +diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c +index 5534684..2099963 100644 +--- a/grub-core/disk/ieee1275/ofdisk.c ++++ b/grub-core/disk/ieee1275/ofdisk.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + static char *last_devpath; + static grub_ieee1275_ihandle_t last_ihandle; +@@ -80,6 +81,7 @@ ofdisk_hash_add_real (char *devpath) + struct ofdisk_hash_ent **head = &ofdisk_hash[ofdisk_hash_fn(devpath)]; + const char *iptr; + char *optr; ++ grub_size_t sz; + + p = grub_zalloc (sizeof (*p)); + if (!p) +@@ -87,8 +89,14 @@ ofdisk_hash_add_real (char *devpath) + + p->devpath = devpath; + +- p->grub_devpath = grub_malloc (sizeof ("ieee1275/") +- + 2 * grub_strlen (p->devpath)); ++ if (grub_mul (grub_strlen (p->devpath), 2, &sz) || ++ grub_add (sz, sizeof ("ieee1275/"), &sz)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining size of device path")); ++ return NULL; ++ } ++ ++ p->grub_devpath = grub_malloc (sz); + + if (!p->grub_devpath) + { +@@ -98,7 +106,13 @@ ofdisk_hash_add_real (char *devpath) + + if (! grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_PARTITION_0)) + { +- p->open_path = grub_malloc (grub_strlen (p->devpath) + 3); ++ if (grub_add (grub_strlen (p->devpath), 3, &sz)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining size of an open path")); ++ return NULL; ++ } ++ ++ p->open_path = grub_malloc (sz); + if (!p->open_path) + { + grub_free (p->grub_devpath); +@@ -224,7 +238,7 @@ dev_iterate (const struct grub_ieee1275_devalias *alias) + args; + char *buf, *bufptr; + unsigned i; +- ++ grub_size_t sz; + + RETRY_IEEE1275_OFDISK_OPEN(alias->path, &ihandle) + if (! ihandle) +@@ -245,7 +259,14 @@ dev_iterate (const struct grub_ieee1275_devalias *alias) + return; + } + +- buf = grub_malloc (grub_strlen (alias->path) + 32); ++ if (grub_add (grub_strlen (alias->path), 32, &sz)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while creating buffer for vscsi"); ++ grub_ieee1275_close (ihandle); ++ return; ++ } ++ ++ buf = grub_malloc (sz); + if (!buf) + return; + bufptr = grub_stpcpy (buf, alias->path); +@@ -289,9 +310,15 @@ dev_iterate (const struct grub_ieee1275_devalias *alias) + grub_uint64_t *table; + grub_uint16_t table_size; + grub_ieee1275_ihandle_t ihandle; ++ grub_size_t sz; + +- buf = grub_malloc (grub_strlen (alias->path) + +- sizeof ("/disk@7766554433221100")); ++ if (grub_add (grub_strlen (alias->path), sizeof ("/disk@7766554433221100"), &sz)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while creating buffer for sas_ioa"); ++ return; ++ } ++ ++ buf = grub_malloc (sz); + if (!buf) + return; + bufptr = grub_stpcpy (buf, alias->path); +@@ -431,9 +458,17 @@ grub_ofdisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data, + static char * + compute_dev_path (const char *name) + { +- char *devpath = grub_malloc (grub_strlen (name) + 3); ++ char *devpath; + char *p, c; ++ grub_size_t sz; + ++ if (grub_add (grub_strlen (name), 3, &sz)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining size of device path")); ++ return NULL; ++ } ++ ++ devpath = grub_malloc (sz); + if (!devpath) + return NULL; + +@@ -660,6 +695,7 @@ insert_bootpath (void) + char *bootpath; + grub_ssize_t bootpath_size; + char *type; ++ grub_size_t sz; + + if (grub_ieee1275_get_property_length (grub_ieee1275_chosen, "bootpath", + &bootpath_size) +@@ -670,7 +706,13 @@ insert_bootpath (void) + return; + } + +- bootpath = (char *) grub_malloc ((grub_size_t) bootpath_size + 64); ++ if (grub_add (bootpath_size, 64, &sz)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining bootpath size")); ++ return; ++ } ++ ++ bootpath = (char *) grub_malloc (sz); + if (! bootpath) + { + grub_print_error (); +diff --git a/grub-core/disk/ldm.c b/grub-core/disk/ldm.c +index 4577a51..1726607 100644 +--- a/grub-core/disk/ldm.c ++++ b/grub-core/disk/ldm.c +@@ -220,6 +220,7 @@ make_vg (grub_disk_t disk, + struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE + / sizeof (struct grub_ldm_vblk)]; + unsigned i; ++ grub_size_t sz; + err = grub_disk_read (disk, cursec, 0, + sizeof(vblk), &vblk); + if (err) +@@ -251,7 +252,13 @@ make_vg (grub_disk_t disk, + grub_free (pv); + goto fail2; + } +- pv->internal_id = grub_malloc (ptr[0] + 2); ++ if (grub_add (ptr[0], 2, &sz)) ++ { ++ grub_free (pv); ++ goto fail2; ++ } ++ ++ pv->internal_id = grub_malloc (sz); + if (!pv->internal_id) + { + grub_free (pv); +@@ -276,7 +283,15 @@ make_vg (grub_disk_t disk, + goto fail2; + } + pv->id.uuidlen = *ptr; +- pv->id.uuid = grub_malloc (pv->id.uuidlen + 1); ++ ++ if (grub_add (pv->id.uuidlen, 1, &sz)) ++ { ++ grub_free (pv->internal_id); ++ grub_free (pv); ++ goto fail2; ++ } ++ ++ pv->id.uuid = grub_malloc (sz); + grub_memcpy (pv->id.uuid, ptr + 1, pv->id.uuidlen); + pv->id.uuid[pv->id.uuidlen] = 0; + +@@ -343,7 +358,13 @@ make_vg (grub_disk_t disk, + grub_free (lv); + goto fail2; + } +- lv->internal_id = grub_malloc ((grub_size_t) ptr[0] + 2); ++ if (grub_add (ptr[0], 2, &sz)) ++ { ++ grub_free (lv->segments); ++ grub_free (lv); ++ goto fail2; ++ } ++ lv->internal_id = grub_malloc (sz); + if (!lv->internal_id) + { + grub_free (lv); +@@ -455,6 +476,7 @@ make_vg (grub_disk_t disk, + struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE + / sizeof (struct grub_ldm_vblk)]; + unsigned i; ++ grub_size_t sz; + err = grub_disk_read (disk, cursec, 0, + sizeof(vblk), &vblk); + if (err) +@@ -489,7 +511,12 @@ make_vg (grub_disk_t disk, + { + goto fail2; + } +- comp->internal_id = grub_malloc ((grub_size_t) ptr[0] + 2); ++ if (grub_add (ptr[0], 2, &sz)) ++ { ++ grub_free (comp); ++ goto fail2; ++ } ++ comp->internal_id = grub_malloc (sz); + if (!comp->internal_id) + { + grub_free (comp); +@@ -639,7 +666,6 @@ make_vg (grub_disk_t disk, + if (lv->segments->node_alloc == lv->segments->node_count) + { + void *t; +- grub_size_t sz; + + if (grub_mul (lv->segments->node_alloc, 2, &lv->segments->node_alloc) || + grub_mul (lv->segments->node_alloc, sizeof (*lv->segments->nodes), &sz)) +diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c +index ac3ab09..50f0e69 100644 +--- a/grub-core/disk/luks2.c ++++ b/grub-core/disk/luks2.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -549,6 +550,7 @@ luks2_recover_key (grub_disk_t source, + gcry_err_code_t gcry_ret; + grub_json_t *json = NULL, keyslots; + grub_err_t ret; ++ grub_size_t sz; + + if (cargs->key_data == NULL || cargs->key_len == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no key data"); +@@ -557,7 +559,10 @@ luks2_recover_key (grub_disk_t source, + if (ret) + return ret; + +- json_header = grub_zalloc (grub_be_to_cpu64 (header.hdr_size) - sizeof (header)); ++ if (grub_sub (grub_be_to_cpu64 (header.hdr_size), sizeof (header), &sz)) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, "underflow detected while calculating json header size"); ++ ++ json_header = grub_zalloc (sz); + if (!json_header) + return GRUB_ERR_OUT_OF_MEMORY; + +diff --git a/grub-core/disk/memdisk.c b/grub-core/disk/memdisk.c +index 613779c..36de3bf 100644 +--- a/grub-core/disk/memdisk.c ++++ b/grub-core/disk/memdisk.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -96,7 +97,11 @@ GRUB_MOD_INIT(memdisk) + + grub_dprintf ("memdisk", "Found memdisk image at %p\n", memdisk_orig_addr); + +- memdisk_size = header->size - sizeof (struct grub_module_header); ++ if (grub_sub (header->size, sizeof (struct grub_module_header), &memdisk_size)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, "underflow detected while obtaining memdisk size"); ++ return; ++ } + memdisk_addr = grub_malloc (memdisk_size); + + grub_dprintf ("memdisk", "Copying memdisk image to dynamic memory\n"); +diff --git a/grub-core/disk/plainmount.c b/grub-core/disk/plainmount.c +index 47e6480..21ec407 100644 +--- a/grub-core/disk/plainmount.c ++++ b/grub-core/disk/plainmount.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -126,7 +127,7 @@ plainmount_configure_password (grub_cryptodisk_t dev, const char *hash, + grub_uint8_t *derived_hash, *dh; + char *p; + unsigned int round, i, len, size; +- grub_size_t alloc_size; ++ grub_size_t alloc_size, sz; + grub_err_t err = GRUB_ERR_NONE; + + /* Support none (plain) hash */ +@@ -145,7 +146,11 @@ plainmount_configure_password (grub_cryptodisk_t dev, const char *hash, + * Allocate buffer for the password and for an added prefix character + * for each hash round ('alloc_size' may not be a multiple of 'len'). + */ +- p = grub_zalloc (alloc_size + (alloc_size / len) + 1); ++ if (grub_add (alloc_size, (alloc_size / len), &sz) || ++ grub_add (sz, 1, &sz)) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while allocating size of password buffer")); ++ ++ p = grub_zalloc (sz); + derived_hash = grub_zalloc (GRUB_CRYPTODISK_MAX_KEYLEN * 2); + if (p == NULL || derived_hash == NULL) + { diff --git a/0428-disk-Prevent-overflows-when-allocating-memory-for-ar.patch b/0428-disk-Prevent-overflows-when-allocating-memory-for-ar.patch new file mode 100644 index 0000000..117e2b9 --- /dev/null +++ b/0428-disk-Prevent-overflows-when-allocating-memory-for-ar.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Alec Brown +Date: Wed, 12 Feb 2025 10:26:44 -0600 +Subject: [PATCH] disk: Prevent overflows when allocating memory for arrays + +Use grub_calloc() when allocating memory for arrays to ensure proper +overflow checks are in place. + +Signed-off-by: Alec Brown +Reviewed-by: Daniel Kiper +--- + grub-core/disk/lvm.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/grub-core/disk/lvm.c b/grub-core/disk/lvm.c +index 8257159b3..99f5e7cc6 100644 +--- a/grub-core/disk/lvm.c ++++ b/grub-core/disk/lvm.c +@@ -671,8 +671,7 @@ grub_lvm_detect (grub_disk_t disk, + goto lvs_segment_fail; + } + +- seg->nodes = grub_zalloc (sizeof (seg->nodes[0]) +- * seg->node_count); ++ seg->nodes = grub_calloc (seg->node_count, sizeof (seg->nodes[0])); + + p = grub_strstr (p, "mirrors = ["); + if (p == NULL) +@@ -760,8 +759,7 @@ grub_lvm_detect (grub_disk_t disk, + } + } + +- seg->nodes = grub_zalloc (sizeof (seg->nodes[0]) +- * seg->node_count); ++ seg->nodes = grub_calloc (seg->node_count, sizeof (seg->nodes[0])); + + p = grub_strstr (p, "raids = ["); + if (p == NULL) diff --git a/0429-disk-Check-if-returned-pointer-for-allocated-memory-.patch b/0429-disk-Check-if-returned-pointer-for-allocated-memory-.patch new file mode 100644 index 0000000..2031f21 --- /dev/null +++ b/0429-disk-Check-if-returned-pointer-for-allocated-memory-.patch @@ -0,0 +1,152 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Alec Brown +Date: Wed, 22 Jan 2025 02:55:11 +0000 +Subject: [PATCH] disk: Check if returned pointer for allocated memory is NULL + +When using grub_malloc(), grub_zalloc() or grub_calloc(), these functions can +fail if we are out of memory. After allocating memory we should check if these +functions returned NULL and handle this error if they did. + +On the occasion make a NULL check in ATA code more obvious. + +Signed-off-by: Alec Brown +Reviewed-by: Daniel Kiper +--- + grub-core/disk/ata.c | 4 ++-- + grub-core/disk/ieee1275/obdisk.c | 6 ++++++ + grub-core/disk/ldm.c | 6 ++++++ + grub-core/disk/lvm.c | 14 ++++++++++++++ + grub-core/disk/memdisk.c | 2 ++ + 5 files changed, 30 insertions(+), 2 deletions(-) + +diff --git a/grub-core/disk/ata.c b/grub-core/disk/ata.c +index 3620a282e..8bc3ab7f3 100644 +--- a/grub-core/disk/ata.c ++++ b/grub-core/disk/ata.c +@@ -112,10 +112,10 @@ grub_ata_identify (struct grub_ata *dev) + return grub_atapi_identify (dev); + + info64 = grub_malloc (GRUB_DISK_SECTOR_SIZE); ++ if (info64 == NULL) ++ return grub_errno; + info32 = (grub_uint32_t *) info64; + info16 = (grub_uint16_t *) info64; +- if (! info16) +- return grub_errno; + + grub_memset (&parms, 0, sizeof (parms)); + parms.buffer = info16; +diff --git a/grub-core/disk/ieee1275/obdisk.c b/grub-core/disk/ieee1275/obdisk.c +index 8e4bbf11c..c72086072 100644 +--- a/grub-core/disk/ieee1275/obdisk.c ++++ b/grub-core/disk/ieee1275/obdisk.c +@@ -423,6 +423,12 @@ canonicalise_disk (const char *devname) + } + + real_canon = grub_malloc (real_unit_str_len); ++ if (real_canon == NULL) ++ { ++ grub_free (parent); ++ grub_print_error (); ++ return NULL; ++ } + + grub_snprintf (real_canon, real_unit_str_len, "%s/disk@%s", + op->name, real_unit_address); +diff --git a/grub-core/disk/ldm.c b/grub-core/disk/ldm.c +index 172660710..246eee3d6 100644 +--- a/grub-core/disk/ldm.c ++++ b/grub-core/disk/ldm.c +@@ -292,6 +292,12 @@ make_vg (grub_disk_t disk, + } + + pv->id.uuid = grub_malloc (sz); ++ if (pv->id.uuid == NULL) ++ { ++ grub_free (pv->internal_id); ++ grub_free (pv); ++ goto fail2; ++ } + grub_memcpy (pv->id.uuid, ptr + 1, pv->id.uuidlen); + pv->id.uuid[pv->id.uuidlen] = 0; + +diff --git a/grub-core/disk/lvm.c b/grub-core/disk/lvm.c +index 99f5e7cc6..4ddb81526 100644 +--- a/grub-core/disk/lvm.c ++++ b/grub-core/disk/lvm.c +@@ -370,6 +370,8 @@ grub_lvm_detect (grub_disk_t disk, + break; + + pv = grub_zalloc (sizeof (*pv)); ++ if (pv == NULL) ++ goto fail4; + q = p; + while (*q != ' ' && q < mda_end) + q++; +@@ -379,6 +381,8 @@ grub_lvm_detect (grub_disk_t disk, + + s = q - p; + pv->name = grub_malloc (s + 1); ++ if (pv->name == NULL) ++ goto pvs_fail_noname; + grub_memcpy (pv->name, p, s); + pv->name[s] = '\0'; + +@@ -451,6 +455,8 @@ grub_lvm_detect (grub_disk_t disk, + break; + + lv = grub_zalloc (sizeof (*lv)); ++ if (lv == NULL) ++ goto fail4; + + q = p; + while (*q != ' ' && q < mda_end) +@@ -545,6 +551,8 @@ grub_lvm_detect (grub_disk_t disk, + goto lvs_fail; + } + lv->segments = grub_calloc (lv->segment_count, sizeof (*seg)); ++ if (lv->segments == NULL) ++ goto lvs_fail; + seg = lv->segments; + + for (i = 0; i < lv->segment_count; i++) +@@ -612,6 +620,8 @@ grub_lvm_detect (grub_disk_t disk, + + seg->nodes = grub_calloc (seg->node_count, + sizeof (*stripe)); ++ if (seg->nodes == NULL) ++ goto lvs_segment_fail; + stripe = seg->nodes; + + p = grub_strstr (p, "stripes = ["); +@@ -672,6 +682,8 @@ grub_lvm_detect (grub_disk_t disk, + } + + seg->nodes = grub_calloc (seg->node_count, sizeof (seg->nodes[0])); ++ if (seg->nodes == NULL) ++ goto lvs_segment_fail; + + p = grub_strstr (p, "mirrors = ["); + if (p == NULL) +@@ -760,6 +772,8 @@ grub_lvm_detect (grub_disk_t disk, + } + + seg->nodes = grub_calloc (seg->node_count, sizeof (seg->nodes[0])); ++ if (seg->nodes == NULL) ++ goto lvs_segment_fail; + + p = grub_strstr (p, "raids = ["); + if (p == NULL) +diff --git a/grub-core/disk/memdisk.c b/grub-core/disk/memdisk.c +index 36de3bfab..2d7afaea3 100644 +--- a/grub-core/disk/memdisk.c ++++ b/grub-core/disk/memdisk.c +@@ -103,6 +103,8 @@ GRUB_MOD_INIT(memdisk) + return; + } + memdisk_addr = grub_malloc (memdisk_size); ++ if (memdisk_addr == NULL) ++ return; + + grub_dprintf ("memdisk", "Copying memdisk image to dynamic memory\n"); + grub_memmove (memdisk_addr, memdisk_orig_addr, memdisk_size); diff --git a/0430-disk-ieee1275-ofdisk-Call-grub_ieee1275_close-when-g.patch b/0430-disk-ieee1275-ofdisk-Call-grub_ieee1275_close-when-g.patch new file mode 100644 index 0000000..abfbf71 --- /dev/null +++ b/0430-disk-ieee1275-ofdisk-Call-grub_ieee1275_close-when-g.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Alec Brown +Date: Wed, 22 Jan 2025 02:55:12 +0000 +Subject: [PATCH] disk/ieee1275/ofdisk: Call grub_ieee1275_close() when + grub_malloc() fails + +In the dev_iterate() function a handle is opened but isn't closed when +grub_malloc() returns NULL. We should fix this by closing it on error. + +Signed-off-by: Alec Brown +Reviewed-by: Daniel Kiper +--- + grub-core/disk/ieee1275/ofdisk.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c +index 209996390..abb5082cd 100644 +--- a/grub-core/disk/ieee1275/ofdisk.c ++++ b/grub-core/disk/ieee1275/ofdisk.c +@@ -268,7 +268,10 @@ dev_iterate (const struct grub_ieee1275_devalias *alias) + + buf = grub_malloc (sz); + if (!buf) +- return; ++ { ++ grub_ieee1275_close (ihandle); ++ return; ++ } + bufptr = grub_stpcpy (buf, alias->path); + + for (i = 0; i < args.nentries; i++) diff --git a/0431-fs-Use-safe-math-macros-to-prevent-overflows.patch b/0431-fs-Use-safe-math-macros-to-prevent-overflows.patch new file mode 100644 index 0000000..8e55184 --- /dev/null +++ b/0431-fs-Use-safe-math-macros-to-prevent-overflows.patch @@ -0,0 +1,353 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lidong Chen +Date: Wed, 12 Feb 2025 10:33:31 -0600 +Subject: [PATCH] fs: Use safe math macros to prevent overflows + +Replace direct arithmetic operations with macros from include/grub/safemath.h +to prevent potential overflow issues when calculating the memory sizes. + +Signed-off-by: Lidong Chen +Reviewed-by: Daniel Kiper +--- + grub-core/fs/archelp.c | 9 ++++++++- + grub-core/fs/btrfs.c | 34 ++++++++++++++++++++++++++++------ + grub-core/fs/cpio_common.c | 16 ++++++++++++++-- + grub-core/fs/f2fs.c | 17 +++++++++++++++-- + grub-core/fs/ntfscomp.c | 9 ++++++++- + grub-core/fs/squash4.c | 12 +++++++++--- + grub-core/fs/xfs.c | 17 +++++++++++++++-- + 7 files changed, 97 insertions(+), 17 deletions(-) + +diff --git a/grub-core/fs/archelp.c b/grub-core/fs/archelp.c +index 0cf544f6f..6491f74f9 100644 +--- a/grub-core/fs/archelp.c ++++ b/grub-core/fs/archelp.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -68,6 +69,7 @@ handle_symlink (struct grub_archelp_data *data, + char *rest; + char *linktarget; + grub_size_t linktarget_len; ++ grub_size_t sz; + + *restart = 0; + +@@ -98,7 +100,12 @@ handle_symlink (struct grub_archelp_data *data, + if (linktarget[0] == '\0') + return GRUB_ERR_NONE; + linktarget_len = grub_strlen (linktarget); +- target = grub_malloc (linktarget_len + grub_strlen (*name) + 2); ++ ++ if (grub_add (linktarget_len, grub_strlen (*name), &sz) || ++ grub_add (sz, 2, &sz)) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("link target length overflow")); ++ ++ target = grub_malloc (sz); + if (!target) + return grub_errno; + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index 3ed37a4db..0d45f09d3 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -1999,6 +1999,7 @@ find_path (struct grub_btrfs_data *data, + char *origpath = NULL; + unsigned symlinks_max = 32; + const char *relpath = grub_env_get ("btrfs_relative_path"); ++ grub_size_t sz; + + follow_default = 0; + origpath = grub_strdup (path); +@@ -2125,9 +2126,15 @@ find_path (struct grub_btrfs_data *data, + struct grub_btrfs_dir_item *cdirel; + if (elemsize > allocated) + { +- allocated = 2 * elemsize; ++ if (grub_mul (2, elemsize, &allocated) || ++ grub_add (allocated, 1, &sz)) ++ { ++ grub_free (path_alloc); ++ grub_free (origpath); ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("directory item size overflow")); ++ } + grub_free (direl); +- direl = grub_malloc (allocated + 1); ++ direl = grub_malloc (sz); + if (!direl) + { + grub_free (path_alloc); +@@ -2191,8 +2198,16 @@ find_path (struct grub_btrfs_data *data, + grub_free (origpath); + return err; + } +- tmp = grub_malloc (grub_le_to_cpu64 (inode.size) +- + grub_strlen (path) + 1); ++ ++ if (grub_add (grub_le_to_cpu64 (inode.size), grub_strlen (path), &sz) || ++ grub_add (sz, 1, &sz)) ++ { ++ grub_free (direl); ++ grub_free (path_alloc); ++ grub_free (origpath); ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("buffer size overflow")); ++ } ++ tmp = grub_malloc (sz); + if (!tmp) + { + grub_free (direl); +@@ -2334,6 +2349,7 @@ grub_btrfs_dir (grub_device_t device, const char *path, + grub_uint8_t type; + char *new_path = NULL; + grub_size_t est_size = 0; ++ grub_size_t sz; + + if (!data) + return grub_errno; +@@ -2383,9 +2399,15 @@ grub_btrfs_dir (grub_device_t device, const char *path, + } + if (elemsize > allocated) + { +- allocated = 2 * elemsize; ++ if (grub_mul (2, elemsize, &allocated) || ++ grub_add (allocated, 1, &sz)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("directory element size overflow")); ++ r = -grub_errno; ++ break; ++ } + grub_free (direl); +- direl = grub_malloc (allocated + 1); ++ direl = grub_malloc (sz); + if (!direl) + { + r = -grub_errno; +diff --git a/grub-core/fs/cpio_common.c b/grub-core/fs/cpio_common.c +index 4e885d623..ce49aa0b1 100644 +--- a/grub-core/fs/cpio_common.c ++++ b/grub-core/fs/cpio_common.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -48,6 +49,7 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name, + struct head hd; + grub_size_t namesize; + grub_uint32_t modeval; ++ grub_size_t sz; + + data->hofs = data->next_hofs; + +@@ -76,7 +78,10 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name, + + *mode = modeval; + +- *name = grub_malloc (namesize + 1); ++ if (grub_add (namesize, 1, &sz)) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("file name size overflow")); ++ ++ *name = grub_malloc (sz); + if (*name == NULL) + return grub_errno; + +@@ -110,10 +115,17 @@ grub_cpio_get_link_target (struct grub_archelp_data *data) + { + char *ret; + grub_err_t err; ++ grub_size_t sz; + + if (data->size == 0) + return grub_strdup (""); +- ret = grub_malloc (data->size + 1); ++ ++ if (grub_add (data->size, 1, &sz)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("target data size overflow")); ++ return NULL; ++ } ++ ret = grub_malloc (sz); + if (!ret) + return NULL; + +diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c +index e5dcbc470..a3182a3e5 100644 +--- a/grub-core/fs/f2fs.c ++++ b/grub-core/fs/f2fs.c +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -958,6 +959,7 @@ grub_f2fs_read_symlink (grub_fshelp_node_t node) + char *symlink; + struct grub_fshelp_node *diro = node; + grub_uint64_t filesize; ++ grub_size_t sz; + + if (!diro->inode_read) + { +@@ -968,7 +970,12 @@ grub_f2fs_read_symlink (grub_fshelp_node_t node) + + filesize = grub_f2fs_file_size(&diro->inode.i); + +- symlink = grub_malloc (filesize + 1); ++ if (grub_add (filesize, 1, &sz)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("symlink size overflow")); ++ return 0; ++ } ++ symlink = grub_malloc (sz); + if (!symlink) + return 0; + +@@ -997,6 +1004,7 @@ grub_f2fs_check_dentries (struct grub_f2fs_dir_iter_ctx *ctx) + enum FILE_TYPE ftype; + int name_len; + int ret; ++ int sz; + + if (grub_f2fs_test_bit_le (i, ctx->bitmap) == 0) + { +@@ -1010,7 +1018,12 @@ grub_f2fs_check_dentries (struct grub_f2fs_dir_iter_ctx *ctx) + if (name_len >= F2FS_NAME_LEN) + return 0; + +- filename = grub_malloc (name_len + 1); ++ if (grub_add (name_len, 1, &sz)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("directory entry name length overflow")); ++ return 0; ++ } ++ filename = grub_malloc (sz); + if (!filename) + return 0; + +diff --git a/grub-core/fs/ntfscomp.c b/grub-core/fs/ntfscomp.c +index 3cd97d337..4bf95c85d 100644 +--- a/grub-core/fs/ntfscomp.c ++++ b/grub-core/fs/ntfscomp.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -310,6 +311,7 @@ ntfscomp (grub_uint8_t *dest, grub_disk_addr_t ofs, + { + grub_err_t ret; + grub_disk_addr_t vcn; ++ int log_sz; + + if (ctx->attr->sbuf) + { +@@ -349,7 +351,12 @@ ntfscomp (grub_uint8_t *dest, grub_disk_addr_t ofs, + } + + ctx->comp.comp_head = ctx->comp.comp_tail = 0; +- ctx->comp.cbuf = grub_malloc (1 << (ctx->comp.log_spc + GRUB_NTFS_BLK_SHR)); ++ if (grub_add (ctx->comp.log_spc, GRUB_NTFS_BLK_SHR, &log_sz)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("compression buffer size overflow")); ++ return 0; ++ } ++ ctx->comp.cbuf = grub_malloc (1 << log_sz); + if (!ctx->comp.cbuf) + return 0; + +diff --git a/grub-core/fs/squash4.c b/grub-core/fs/squash4.c +index ccfa3eea5..0ee9bb2e8 100644 +--- a/grub-core/fs/squash4.c ++++ b/grub-core/fs/squash4.c +@@ -460,11 +460,11 @@ grub_squash_read_symlink (grub_fshelp_node_t node) + { + char *ret; + grub_err_t err; +- grub_size_t sz; ++ grub_uint32_t sz; + + if (grub_add (grub_le_to_cpu32 (node->ino.symlink.namelen), 1, &sz)) + { +- grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("symlink name length overflow")); + return NULL; + } + +@@ -577,6 +577,7 @@ grub_squash_iterate_dir (grub_fshelp_node_t dir, + struct grub_squash_dirent di; + struct grub_squash_inode ino; + grub_size_t sz; ++ grub_uint16_t nlen; + + err = read_chunk (dir->data, &di, sizeof (di), + grub_le_to_cpu64 (dir->data->sb.diroffset) +@@ -592,7 +593,12 @@ grub_squash_iterate_dir (grub_fshelp_node_t dir, + if (err) + return 0; + +- buf = grub_malloc (grub_le_to_cpu16 (di.namelen) + 2); ++ if (grub_add (grub_le_to_cpu16 (di.namelen), 2, &nlen)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("name length overflow")); ++ return 0; ++ } ++ buf = grub_malloc (nlen); + if (!buf) + return 0; + err = read_chunk (dir->data, buf, +diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c +index 7b0ea577e..ff6fe3d83 100644 +--- a/grub-core/fs/xfs.c ++++ b/grub-core/fs/xfs.c +@@ -676,6 +676,7 @@ static char * + grub_xfs_read_symlink (grub_fshelp_node_t node) + { + grub_ssize_t size = grub_be_to_cpu64 (node->inode.size); ++ grub_size_t sz; + + if (size < 0) + { +@@ -697,7 +698,12 @@ grub_xfs_read_symlink (grub_fshelp_node_t node) + if (node->data->hascrc) + off = 56; + +- symlink = grub_malloc (size + 1); ++ if (grub_add (size, 1, &sz)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("symlink size overflow")); ++ return 0; ++ } ++ symlink = grub_malloc (sz); + if (!symlink) + return 0; + +@@ -747,8 +753,15 @@ static int iterate_dir_call_hook (grub_uint64_t ino, const char *filename, + { + struct grub_fshelp_node *fdiro; + grub_err_t err; ++ grub_size_t sz; + +- fdiro = grub_malloc (grub_xfs_fshelp_size(ctx->diro->data) + 1); ++ if (grub_add (grub_xfs_fshelp_size(ctx->diro->data), 1, &sz)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("directory data size overflow")); ++ grub_print_error (); ++ return 0; ++ } ++ fdiro = grub_malloc (sz); + if (!fdiro) + { + grub_print_error (); diff --git a/0432-fs-Prevent-overflows-when-allocating-memory-for-arra.patch b/0432-fs-Prevent-overflows-when-allocating-memory-for-arra.patch new file mode 100644 index 0000000..d9ffaf1 --- /dev/null +++ b/0432-fs-Prevent-overflows-when-allocating-memory-for-arra.patch @@ -0,0 +1,82 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lidong Chen +Date: Tue, 21 Jan 2025 19:02:37 +0000 +Subject: [PATCH] fs: Prevent overflows when allocating memory for arrays + +Use grub_calloc() when allocating memory for arrays to ensure proper +overflow checks are in place. + +The HFS+ and squash4 security vulnerabilities were reported by +Jonathan Bar Or . + +Fixes: CVE-2025-0678 +Fixes: CVE-2025-1125 + +Signed-off-by: Lidong Chen +Reviewed-by: Daniel Kiper +--- + grub-core/fs/btrfs.c | 4 ++-- + grub-core/fs/hfspluscomp.c | 9 +++++++-- + grub-core/fs/squash4.c | 8 ++++---- + 3 files changed, 13 insertions(+), 8 deletions(-) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index 0d45f09d3..4a4a8f243 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -1409,8 +1409,8 @@ grub_btrfs_mount (grub_device_t dev) + } + + data->n_devices_allocated = 16; +- data->devices_attached = grub_malloc (sizeof (data->devices_attached[0]) +- * data->n_devices_allocated); ++ data->devices_attached = grub_calloc (data->n_devices_allocated, ++ sizeof (data->devices_attached[0])); + if (!data->devices_attached) + { + grub_free (data); +diff --git a/grub-core/fs/hfspluscomp.c b/grub-core/fs/hfspluscomp.c +index d76f3f137..4965ef19a 100644 +--- a/grub-core/fs/hfspluscomp.c ++++ b/grub-core/fs/hfspluscomp.c +@@ -244,14 +244,19 @@ hfsplus_open_compressed_real (struct grub_hfsplus_file *node) + return 0; + } + node->compress_index_size = grub_le_to_cpu32 (index_size); +- node->compress_index = grub_malloc (node->compress_index_size +- * sizeof (node->compress_index[0])); ++ node->compress_index = grub_calloc (node->compress_index_size, ++ sizeof (node->compress_index[0])); + if (!node->compress_index) + { + node->compressed = 0; + grub_free (attr_node); + return grub_errno; + } ++ ++ /* ++ * The node->compress_index_size * sizeof (node->compress_index[0]) is safe here ++ * due to relevant checks done in grub_calloc() above. ++ */ + if (grub_hfsplus_read_file (node, 0, 0, + 0x104 + sizeof (index_size), + node->compress_index_size +diff --git a/grub-core/fs/squash4.c b/grub-core/fs/squash4.c +index 0ee9bb2e8..5239cdd5c 100644 +--- a/grub-core/fs/squash4.c ++++ b/grub-core/fs/squash4.c +@@ -810,10 +810,10 @@ direct_read (struct grub_squash_data *data, + break; + } + total_blocks = ((total_size + data->blksz - 1) >> data->log2_blksz); +- ino->block_sizes = grub_malloc (total_blocks +- * sizeof (ino->block_sizes[0])); +- ino->cumulated_block_sizes = grub_malloc (total_blocks +- * sizeof (ino->cumulated_block_sizes[0])); ++ ino->block_sizes = grub_calloc (total_blocks, ++ sizeof (ino->block_sizes[0])); ++ ino->cumulated_block_sizes = grub_calloc (total_blocks, ++ sizeof (ino->cumulated_block_sizes[0])); + if (!ino->block_sizes || !ino->cumulated_block_sizes) + { + grub_free (ino->block_sizes); diff --git a/0433-fs-Prevent-overflows-when-assigning-returned-values-.patch b/0433-fs-Prevent-overflows-when-assigning-returned-values-.patch new file mode 100644 index 0000000..7ad1c12 --- /dev/null +++ b/0433-fs-Prevent-overflows-when-assigning-returned-values-.patch @@ -0,0 +1,105 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lidong Chen +Date: Tue, 21 Jan 2025 19:02:38 +0000 +Subject: [PATCH] fs: Prevent overflows when assigning returned values from + read_number() + +The direct assignment of the unsigned long long value returned by +read_number() can potentially lead to an overflow on a 32-bit systems. +The fix replaces the direct assignments with calls to grub_cast() +which detects the overflows and safely assigns the values if no +overflow is detected. + +Signed-off-by: Lidong Chen +Reviewed-by: Daniel Kiper +--- + grub-core/fs/cpio_common.c | 18 ++++++++++++++---- + grub-core/fs/tar.c | 23 ++++++++++++++++------- + 2 files changed, 30 insertions(+), 11 deletions(-) + +diff --git a/grub-core/fs/cpio_common.c b/grub-core/fs/cpio_common.c +index ce49aa0b1..e6c51a6af 100644 +--- a/grub-core/fs/cpio_common.c ++++ b/grub-core/fs/cpio_common.c +@@ -62,11 +62,21 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name, + #endif + ) + return grub_error (GRUB_ERR_BAD_FS, "invalid cpio archive"); +- data->size = read_number (hd.filesize, ARRAY_SIZE (hd.filesize)); ++ ++ if (grub_cast (read_number (hd.filesize, ARRAY_SIZE (hd.filesize)), &data->size)) ++ return grub_error (GRUB_ERR_BAD_FS, N_("data size overflow")); ++ + if (mtime) +- *mtime = read_number (hd.mtime, ARRAY_SIZE (hd.mtime)); +- modeval = read_number (hd.mode, ARRAY_SIZE (hd.mode)); +- namesize = read_number (hd.namesize, ARRAY_SIZE (hd.namesize)); ++ { ++ if (grub_cast (read_number (hd.mtime, ARRAY_SIZE (hd.mtime)), mtime)) ++ return grub_error (GRUB_ERR_BAD_FS, N_("mtime overflow")); ++ } ++ ++ if (grub_cast (read_number (hd.mode, ARRAY_SIZE (hd.mode)), &modeval)) ++ return grub_error (GRUB_ERR_BAD_FS, N_("mode overflow")); ++ ++ if (grub_cast (read_number (hd.namesize, ARRAY_SIZE (hd.namesize)), &namesize)) ++ return grub_error (GRUB_ERR_BAD_FS, N_("namesize overflow")); + + /* Don't allow negative numbers. */ + if (namesize >= 0x80000000) +diff --git a/grub-core/fs/tar.c b/grub-core/fs/tar.c +index fd2ec1f74..1eaa5349f 100644 +--- a/grub-core/fs/tar.c ++++ b/grub-core/fs/tar.c +@@ -99,9 +99,10 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name, + if (hd.typeflag == 'L') + { + grub_err_t err; +- grub_size_t namesize = read_number (hd.size, sizeof (hd.size)); ++ grub_size_t namesize; + +- if (grub_add (namesize, 1, &sz)) ++ if (grub_cast (read_number (hd.size, sizeof (hd.size)), &namesize) || ++ grub_add (namesize, 1, &sz)) + return grub_error (GRUB_ERR_BAD_FS, N_("name size overflow")); + + *name = grub_malloc (sz); +@@ -123,9 +124,10 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name, + if (hd.typeflag == 'K') + { + grub_err_t err; +- grub_size_t linksize = read_number (hd.size, sizeof (hd.size)); ++ grub_size_t linksize; + +- if (grub_add (linksize, 1, &sz)) ++ if (grub_cast (read_number (hd.size, sizeof (hd.size)), &linksize) || ++ grub_add (linksize, 1, &sz)) + return grub_error (GRUB_ERR_BAD_FS, N_("link size overflow")); + + if (data->linkname_alloc < sz) +@@ -174,15 +176,22 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name, + (*name)[extra_size + sizeof (hd.name)] = 0; + } + +- data->size = read_number (hd.size, sizeof (hd.size)); ++ if (grub_cast (read_number (hd.size, sizeof (hd.size)), &data->size)) ++ return grub_error (GRUB_ERR_BAD_FS, N_("data size overflow")); ++ + data->dofs = data->hofs + GRUB_DISK_SECTOR_SIZE; + data->next_hofs = data->dofs + ((data->size + GRUB_DISK_SECTOR_SIZE - 1) & + ~(GRUB_DISK_SECTOR_SIZE - 1)); + if (mtime) +- *mtime = read_number (hd.mtime, sizeof (hd.mtime)); ++ { ++ if (grub_cast (read_number (hd.mtime, sizeof (hd.mtime)), mtime)) ++ return grub_error (GRUB_ERR_BAD_FS, N_("mtime overflow")); ++ } + if (mode) + { +- *mode = read_number (hd.mode, sizeof (hd.mode)); ++ if (grub_cast (read_number (hd.mode, sizeof (hd.mode)), mode)) ++ return grub_error (GRUB_ERR_BAD_FS, N_("mode overflow")); ++ + switch (hd.typeflag) + { + /* Hardlink. */ diff --git a/0434-fs-zfs-Use-safe-math-macros-to-prevent-overflows.patch b/0434-fs-zfs-Use-safe-math-macros-to-prevent-overflows.patch new file mode 100644 index 0000000..89b530f --- /dev/null +++ b/0434-fs-zfs-Use-safe-math-macros-to-prevent-overflows.patch @@ -0,0 +1,138 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lidong Chen +Date: Wed, 22 Jan 2025 07:17:02 +0000 +Subject: [PATCH] fs/zfs: Use safe math macros to prevent overflows + +Replace direct arithmetic operations with macros from include/grub/safemath.h +to prevent potential overflow issues when calculating the memory sizes. + +Signed-off-by: Lidong Chen +Reviewed-by: Daniel Kiper +--- + grub-core/fs/zfs/zfs.c | 50 ++++++++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 44 insertions(+), 6 deletions(-) + +diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c +index cbbd86730..b52d293f2 100644 +--- a/grub-core/fs/zfs/zfs.c ++++ b/grub-core/fs/zfs/zfs.c +@@ -2383,6 +2383,7 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap, + zap_dnode->endian) << DNODE_SHIFT); + grub_err_t err; + grub_zfs_endian_t endian; ++ grub_size_t sz; + + if (zap_verify (zap, zap_dnode->endian)) + return 0; +@@ -2444,8 +2445,14 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap, + if (le->le_type != ZAP_CHUNK_ENTRY) + continue; + +- buf = grub_malloc (grub_zfs_to_cpu16 (le->le_name_length, endian) +- * name_elem_length + 1); ++ if (grub_mul (grub_zfs_to_cpu16 (le->le_name_length, endian), name_elem_length, &sz) || ++ grub_add (sz, 1, &sz)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("buffer size overflow")); ++ grub_free (l); ++ return grub_errno; ++ } ++ buf = grub_malloc (sz); + if (zap_leaf_array_get (l, endian, blksft, + grub_zfs_to_cpu16 (le->le_name_chunk, + endian), +@@ -2866,6 +2873,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + && ((grub_zfs_to_cpu64(((znode_phys_t *) DN_BONUS (&dnode_path->dn.dn))->zp_mode, dnode_path->dn.endian) >> 12) & 0xf) == 0xa) + { + char *sym_value; ++ grub_size_t sz; + grub_size_t sym_sz; + int free_symval = 0; + char *oldpath = path, *oldpathbuf = path_buf; +@@ -2917,7 +2925,18 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + break; + free_symval = 1; + } +- path = path_buf = grub_malloc (sym_sz + grub_strlen (oldpath) + 1); ++ ++ if (grub_add (sym_sz, grub_strlen (oldpath), &sz) || ++ grub_add (sz, 1, &sz)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("path buffer size overflow")); ++ grub_free (oldpathbuf); ++ if (free_symval) ++ grub_free (sym_value); ++ err = grub_errno; ++ break; ++ } ++ path = path_buf = grub_malloc (sz); + if (!path_buf) + { + grub_free (oldpathbuf); +@@ -2951,6 +2970,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) + { +@@ -2984,7 +3004,15 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + + SA_SIZE_OFFSET), + dnode_path->dn.endian); + char *oldpath = path, *oldpathbuf = path_buf; +- path = path_buf = grub_malloc (sym_sz + grub_strlen (oldpath) + 1); ++ if (grub_add (sym_sz, grub_strlen (oldpath), &sz) || ++ grub_add (sz, 1, &sz)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("path buffer size overflow")); ++ grub_free (oldpathbuf); ++ err = grub_errno; ++ break; ++ } ++ path = path_buf = grub_malloc (sz); + if (!path_buf) + { + grub_free (oldpathbuf); +@@ -3553,6 +3581,7 @@ grub_zfs_nvlist_lookup_nvlist_array (const char *nvlist, const char *name, + unsigned i; + grub_size_t nelm; + int elemsize = 0; ++ int sz; + + found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST_ARRAY, &nvpair, + &size, &nelm); +@@ -3587,7 +3616,12 @@ grub_zfs_nvlist_lookup_nvlist_array (const char *nvlist, const char *name, + return 0; + } + +- ret = grub_zalloc (elemsize + sizeof (grub_uint32_t)); ++ if (grub_add (elemsize, sizeof (grub_uint32_t), &sz)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("elemsize overflow")); ++ return 0; ++ } ++ ret = grub_zalloc (sz); + if (!ret) + return 0; + grub_memcpy (ret, nvlist, sizeof (grub_uint32_t)); +@@ -4166,6 +4200,7 @@ iterate_zap_snap (const char *name, grub_uint64_t val, + struct grub_dirhook_info info; + char *name2; + int ret; ++ grub_size_t sz; + + dnode_end_t mdn; + +@@ -4186,7 +4221,10 @@ iterate_zap_snap (const char *name, grub_uint64_t val, + return 0; + } + +- name2 = grub_malloc (grub_strlen (name) + 2); ++ if (grub_add (grub_strlen (name), 2, &sz)) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("name length overflow")); ++ ++ name2 = grub_malloc (sz); + name2[0] = '@'; + grub_memcpy (name2 + 1, name, grub_strlen (name) + 1); + ret = ctx->hook (name2, &info, ctx->hook_data); diff --git a/0435-fs-zfs-Prevent-overflows-when-allocating-memory-for-.patch b/0435-fs-zfs-Prevent-overflows-when-allocating-memory-for-.patch new file mode 100644 index 0000000..083467f --- /dev/null +++ b/0435-fs-zfs-Prevent-overflows-when-allocating-memory-for-.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lidong Chen +Date: Wed, 22 Jan 2025 07:17:03 +0000 +Subject: [PATCH] fs/zfs: Prevent overflows when allocating memory for arrays + +Use grub_calloc() when allocating memory for arrays to ensure proper +overflow checks are in place. + +Signed-off-by: Lidong Chen +Reviewed-by: Daniel Kiper +--- + grub-core/fs/zfs/zfs.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c +index b52d293f2..913046ba9 100644 +--- a/grub-core/fs/zfs/zfs.c ++++ b/grub-core/fs/zfs/zfs.c +@@ -721,8 +721,8 @@ fill_vdev_info_real (struct grub_zfs_data *data, + { + fill->n_children = nelm; + +- fill->children = grub_zalloc (fill->n_children +- * sizeof (fill->children[0])); ++ fill->children = grub_calloc (fill->n_children, ++ sizeof (fill->children[0])); + } + + for (i = 0; i < nelm; i++) +@@ -3697,8 +3697,8 @@ zfs_mount (grub_device_t dev) + #endif + + data->n_devices_allocated = 16; +- data->devices_attached = grub_malloc (sizeof (data->devices_attached[0]) +- * data->n_devices_allocated); ++ data->devices_attached = grub_calloc (data->n_devices_allocated, ++ sizeof (data->devices_attached[0])); + data->n_devices_attached = 0; + err = scan_disk (dev, data, 1, &inserted); + if (err) diff --git a/0436-fs-zfs-Check-if-returned-pointer-for-allocated-memor.patch b/0436-fs-zfs-Check-if-returned-pointer-for-allocated-memor.patch new file mode 100644 index 0000000..5f09e89 --- /dev/null +++ b/0436-fs-zfs-Check-if-returned-pointer-for-allocated-memor.patch @@ -0,0 +1,88 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lidong Chen +Date: Wed, 22 Jan 2025 07:17:01 +0000 +Subject: [PATCH] fs/zfs: Check if returned pointer for allocated memory is + NULL + +When using grub_malloc() or grub_zalloc(), these functions can fail if +we are out of memory. After allocating memory we should check if these +functions returned NULL and handle this error if they did. + +Signed-off-by: Lidong Chen +Reviewed-by: Daniel Kiper +--- + grub-core/fs/zfs/zfs.c | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c +index 913046ba9..9123b5682 100644 +--- a/grub-core/fs/zfs/zfs.c ++++ b/grub-core/fs/zfs/zfs.c +@@ -612,6 +612,8 @@ zfs_fetch_nvlist (struct grub_zfs_device_desc *diskdesc, char **nvlist) + return grub_error (GRUB_ERR_BUG, "member drive unknown"); + + *nvlist = grub_malloc (VDEV_PHYS_SIZE); ++ if (!*nvlist) ++ return grub_errno; + + /* Read in the vdev name-value pair list (112K). */ + err = grub_disk_read (diskdesc->dev->disk, diskdesc->vdev_phys_sector, 0, +@@ -723,6 +725,11 @@ fill_vdev_info_real (struct grub_zfs_data *data, + + fill->children = grub_calloc (fill->n_children, + sizeof (fill->children[0])); ++ if (!fill->children) ++ { ++ grub_free (type); ++ return grub_errno; ++ } + } + + for (i = 0; i < nelm; i++) +@@ -2453,6 +2460,11 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap, + return grub_errno; + } + buf = grub_malloc (sz); ++ if (!buf) ++ { ++ grub_free (l); ++ return grub_errno; ++ } + if (zap_leaf_array_get (l, endian, blksft, + grub_zfs_to_cpu16 (le->le_name_chunk, + endian), +@@ -2468,6 +2480,12 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap, + val_length = ((int) le->le_value_length + * (int) le->le_int_size); + val = grub_malloc (grub_zfs_to_cpu16 (val_length, endian)); ++ if (!val) ++ { ++ grub_free (l); ++ grub_free (buf); ++ return grub_errno; ++ } + if (zap_leaf_array_get (l, endian, blksft, + grub_zfs_to_cpu16 (le->le_value_chunk, + endian), +@@ -3699,6 +3717,11 @@ zfs_mount (grub_device_t dev) + data->n_devices_allocated = 16; + data->devices_attached = grub_calloc (data->n_devices_allocated, + sizeof (data->devices_attached[0])); ++ if (!data->devices_attached) ++ { ++ grub_free (data); ++ return NULL; ++ } + data->n_devices_attached = 0; + err = scan_disk (dev, data, 1, &inserted); + if (err) +@@ -4225,6 +4248,9 @@ iterate_zap_snap (const char *name, grub_uint64_t val, + return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("name length overflow")); + + name2 = grub_malloc (sz); ++ if (!name2) ++ return grub_errno; ++ + name2[0] = '@'; + grub_memcpy (name2 + 1, name, grub_strlen (name) + 1); + ret = ctx->hook (name2, &info, ctx->hook_data); diff --git a/0437-fs-zfs-Add-missing-NULL-check-after-grub_strdup-call.patch b/0437-fs-zfs-Add-missing-NULL-check-after-grub_strdup-call.patch new file mode 100644 index 0000000..8641851 --- /dev/null +++ b/0437-fs-zfs-Add-missing-NULL-check-after-grub_strdup-call.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lidong Chen +Date: Wed, 22 Jan 2025 07:17:04 +0000 +Subject: [PATCH] fs/zfs: Add missing NULL check after grub_strdup() call + +Signed-off-by: Lidong Chen +Reviewed-by: Daniel Kiper +--- + grub-core/fs/zfs/zfs.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c +index 9123b5682..da014b123 100644 +--- a/grub-core/fs/zfs/zfs.c ++++ b/grub-core/fs/zfs/zfs.c +@@ -3297,6 +3297,8 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol, + filename = 0; + snapname = 0; + fsname = grub_strdup (fullpath); ++ if (!fsname) ++ return grub_errno; + } + else + { diff --git a/0438-net-Use-safe-math-macros-to-prevent-overflows.patch b/0438-net-Use-safe-math-macros-to-prevent-overflows.patch new file mode 100644 index 0000000..1aa8866 --- /dev/null +++ b/0438-net-Use-safe-math-macros-to-prevent-overflows.patch @@ -0,0 +1,240 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lidong Chen +Date: Wed, 12 Feb 2025 10:38:17 -0600 +Subject: [PATCH] net: Use safe math macros to prevent overflows + +Replace direct arithmetic operations with macros from include/grub/safemath.h +to prevent potential overflow issues when calculating the memory sizes. + +Signed-off-by: Lidong Chen +Signed-off-by: Alec Brown +Reviewed-by: Daniel Kiper +--- + grub-core/net/bootp.c | 16 +++++++++++-- + grub-core/net/dns.c | 9 ++++++- + grub-core/net/drivers/ieee1275/ofnet.c | 20 ++++++++++++++-- + grub-core/net/net.c | 44 +++++++++++++++++++++++++++------- + 4 files changed, 76 insertions(+), 13 deletions(-) + +diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c +index 7baf3540c..f00d4a9ad 100644 +--- a/grub-core/net/bootp.c ++++ b/grub-core/net/bootp.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + static int + dissect_url (const char *url, char **proto, char **host, char **path) +@@ -1476,6 +1477,7 @@ grub_cmd_dhcpopt (struct grub_command *cmd __attribute__ ((unused)), + unsigned num; + const grub_uint8_t *ptr; + grub_uint8_t taglength; ++ grub_uint8_t len; + + if (argc < 4) + return grub_error (GRUB_ERR_BAD_ARGUMENT, +@@ -1517,7 +1519,12 @@ grub_cmd_dhcpopt (struct grub_command *cmd __attribute__ ((unused)), + if (grub_strcmp (args[3], "string") == 0) + { + grub_err_t err = GRUB_ERR_NONE; +- char *val = grub_malloc (taglength + 1); ++ char *val; ++ ++ if (grub_add (taglength, 1, &len)) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("tag length overflow")); ++ ++ val = grub_malloc (len); + if (!val) + return grub_errno; + grub_memcpy (val, ptr, taglength); +@@ -1550,7 +1557,12 @@ grub_cmd_dhcpopt (struct grub_command *cmd __attribute__ ((unused)), + if (grub_strcmp (args[3], "hex") == 0) + { + grub_err_t err = GRUB_ERR_NONE; +- char *val = grub_malloc (2 * taglength + 1); ++ char *val; ++ ++ if (grub_mul (taglength, 2, &len) || grub_add (len, 1, &len)) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("tag length overflow")); ++ ++ val = grub_malloc (len); + int i; + if (!val) + return grub_errno; +diff --git a/grub-core/net/dns.c b/grub-core/net/dns.c +index 17961a9f1..64b48a31c 100644 +--- a/grub-core/net/dns.c ++++ b/grub-core/net/dns.c +@@ -224,10 +224,17 @@ get_name (const grub_uint8_t *name_at, const grub_uint8_t *head, + { + int length; + char *ret; ++ int len; + + if (!check_name_real (name_at, head, tail, NULL, &length, NULL)) + return NULL; +- ret = grub_malloc (length + 1); ++ ++ if (grub_add (length, 1, &len)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("name length overflow")); ++ return NULL; ++ } ++ ret = grub_malloc (len); + if (!ret) + return NULL; + if (!check_name_real (name_at, head, tail, NULL, NULL, ret)) +diff --git a/grub-core/net/drivers/ieee1275/ofnet.c b/grub-core/net/drivers/ieee1275/ofnet.c +index bcb3f9ea0..650114806 100644 +--- a/grub-core/net/drivers/ieee1275/ofnet.c ++++ b/grub-core/net/drivers/ieee1275/ofnet.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -404,6 +405,7 @@ search_net_devices (struct grub_ieee1275_devalias *alias) + grub_uint8_t *pprop; + char *shortname; + char need_suffix = 1; ++ grub_size_t sz; + + if (grub_strcmp (alias->type, "network") != 0) + return 0; +@@ -461,9 +463,23 @@ search_net_devices (struct grub_ieee1275_devalias *alias) + } + + if (need_suffix) +- ofdata->path = grub_malloc (grub_strlen (alias->path) + sizeof (SUFFIX)); ++ { ++ if (grub_add (grub_strlen (alias->path), sizeof (SUFFIX), &sz)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obatining size of ofdata path")); ++ grub_print_error (); ++ return 0; ++ } ++ } + else +- ofdata->path = grub_malloc (grub_strlen (alias->path) + 1); ++ { ++ if (grub_add (grub_strlen (alias->path), 1, &sz)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obatining size of ofdata path")); ++ grub_print_error (); ++ return 0; ++ } ++ } + if (!ofdata->path) + { + grub_print_error (); +diff --git a/grub-core/net/net.c b/grub-core/net/net.c +index 6c0bd00b4..9826328ca 100644 +--- a/grub-core/net/net.c ++++ b/grub-core/net/net.c +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + #ifdef GRUB_MACHINE_EFI + #include + #endif +@@ -211,6 +212,7 @@ grub_net_ipv6_get_slaac (struct grub_net_card *card, + { + struct grub_net_slaac_mac_list *slaac; + char *ptr; ++ grub_size_t sz; + + for (slaac = card->slaac_list; slaac; slaac = slaac->next) + if (grub_net_hwaddr_cmp (&slaac->address, hwaddr) == 0) +@@ -220,9 +222,16 @@ grub_net_ipv6_get_slaac (struct grub_net_card *card, + if (!slaac) + return NULL; + +- slaac->name = grub_malloc (grub_strlen (card->name) +- + GRUB_NET_MAX_STR_HWADDR_LEN +- + sizeof (":slaac")); ++ if (grub_add (grub_strlen (card->name), ++ (GRUB_NET_MAX_STR_HWADDR_LEN + sizeof (":slaac")), &sz)) ++ { ++ grub_free (slaac); ++ grub_error (GRUB_ERR_OUT_OF_RANGE, ++ "overflow detected while obtaining size of slaac name"); ++ return NULL; ++ } ++ ++ slaac->name = grub_malloc (sz); + ptr = grub_stpcpy (slaac->name, card->name); + if (grub_net_hwaddr_cmp (&card->default_address, hwaddr) != 0) + { +@@ -293,6 +302,7 @@ grub_net_ipv6_get_link_local (struct grub_net_card *card, + char *name; + char *ptr; + grub_net_network_level_address_t addr; ++ grub_size_t sz; + + addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; + addr.ipv6[0] = grub_cpu_to_be64_compile_time (0xfe80ULL << 48); +@@ -306,9 +316,14 @@ grub_net_ipv6_get_link_local (struct grub_net_card *card, + return inf; + } + +- name = grub_malloc (grub_strlen (card->name) +- + GRUB_NET_MAX_STR_HWADDR_LEN +- + sizeof (":link")); ++ if (grub_add (grub_strlen (card->name), ++ (GRUB_NET_MAX_STR_HWADDR_LEN + sizeof (":link")), &sz)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, ++ "overflow detected while obtaining size of link name"); ++ return NULL; ++ } ++ name = grub_malloc (sz); + if (!name) + return NULL; + +@@ -1461,8 +1476,15 @@ grub_net_open_real (const char *name) + if (grub_strchr (port_start + 1, ':')) + { + int iplen = grub_strlen (server); ++ grub_size_t sz; ++ + /* bracket bare ipv6 addrs */ +- host = grub_malloc (iplen + 3); ++ if (grub_add (iplen, 3, &sz)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining length of host")); ++ return NULL; ++ } ++ host = grub_malloc (sz); + if(!host) + { + return NULL; +@@ -1722,6 +1744,7 @@ grub_env_set_net_property (const char *intername, const char *suffix, + { + char *varname, *varvalue; + char *ptr; ++ grub_size_t sz; + + varname = grub_xasprintf ("net_%s_%s", intername, suffix); + if (!varname) +@@ -1729,7 +1752,12 @@ grub_env_set_net_property (const char *intername, const char *suffix, + for (ptr = varname; *ptr; ptr++) + if (*ptr == ':') + *ptr = '_'; +- varvalue = grub_malloc (len + 1); ++ if (grub_add (len, 1, &sz)) ++ { ++ grub_free (varname); ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while obtaining the size of an env variable"); ++ } ++ varvalue = grub_malloc (sz); + if (!varvalue) + { + grub_free (varname); diff --git a/0439-net-Prevent-overflows-when-allocating-memory-for-arr.patch b/0439-net-Prevent-overflows-when-allocating-memory-for-arr.patch new file mode 100644 index 0000000..dda1e79 --- /dev/null +++ b/0439-net-Prevent-overflows-when-allocating-memory-for-arr.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lidong Chen +Date: Wed, 22 Jan 2025 18:04:43 +0000 +Subject: [PATCH] net: Prevent overflows when allocating memory for arrays + +Use grub_calloc() when allocating memory for arrays to ensure proper +overflow checks are in place. + +Signed-off-by: Lidong Chen +Reviewed-by: Daniel Kiper +--- + grub-core/net/dns.c | 4 ++-- + grub-core/net/net.c | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/grub-core/net/dns.c b/grub-core/net/dns.c +index 64b48a31c..aafd92902 100644 +--- a/grub-core/net/dns.c ++++ b/grub-core/net/dns.c +@@ -494,8 +494,8 @@ grub_net_dns_lookup (const char *name, + && grub_get_time_ms () < dns_cache[h].limit_time) + { + grub_dprintf ("dns", "retrieved from cache\n"); +- *addresses = grub_malloc (dns_cache[h].naddresses +- * sizeof ((*addresses)[0])); ++ *addresses = grub_calloc (dns_cache[h].naddresses, ++ sizeof ((*addresses)[0])); + if (!*addresses) + return grub_errno; + *naddresses = dns_cache[h].naddresses; +diff --git a/grub-core/net/net.c b/grub-core/net/net.c +index 9826328ca..a17392abb 100644 +--- a/grub-core/net/net.c ++++ b/grub-core/net/net.c +@@ -91,8 +91,8 @@ grub_net_link_layer_add_address (struct grub_net_card *card, + /* Add sender to cache table. */ + if (card->link_layer_table == NULL) + { +- card->link_layer_table = grub_zalloc (LINK_LAYER_CACHE_SIZE +- * sizeof (card->link_layer_table[0])); ++ card->link_layer_table = grub_calloc (LINK_LAYER_CACHE_SIZE, ++ sizeof (card->link_layer_table[0])); + if (card->link_layer_table == NULL) + return; + } diff --git a/0440-net-Check-if-returned-pointer-for-allocated-memory-i.patch b/0440-net-Check-if-returned-pointer-for-allocated-memory-i.patch new file mode 100644 index 0000000..83283a9 --- /dev/null +++ b/0440-net-Check-if-returned-pointer-for-allocated-memory-i.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Alec Brown +Date: Wed, 22 Jan 2025 18:04:44 +0000 +Subject: [PATCH] net: Check if returned pointer for allocated memory is NULL + +When using grub_malloc(), the function can fail if we are out of memory. +After allocating memory we should check if this function returned NULL +and handle this error if it did. + +Signed-off-by: Alec Brown +Reviewed-by: Daniel Kiper +--- + grub-core/net/net.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/grub-core/net/net.c b/grub-core/net/net.c +index a17392abb..4bfe03d53 100644 +--- a/grub-core/net/net.c ++++ b/grub-core/net/net.c +@@ -232,6 +232,11 @@ grub_net_ipv6_get_slaac (struct grub_net_card *card, + } + + slaac->name = grub_malloc (sz); ++ if (slaac->name == NULL) ++ { ++ grub_free (slaac); ++ return NULL; ++ } + ptr = grub_stpcpy (slaac->name, card->name); + if (grub_net_hwaddr_cmp (&card->default_address, hwaddr) != 0) + { diff --git a/0441-fs-sfs-Check-if-allocated-memory-is-NULL.patch b/0441-fs-sfs-Check-if-allocated-memory-is-NULL.patch new file mode 100644 index 0000000..57d2960 --- /dev/null +++ b/0441-fs-sfs-Check-if-allocated-memory-is-NULL.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Alec Brown +Date: Tue, 28 Jan 2025 05:15:50 +0000 +Subject: [PATCH] fs/sfs: Check if allocated memory is NULL + +When using grub_zalloc(), if we are out of memory, this function can fail. +After allocating memory, we should check if grub_zalloc() returns NULL. +If so, we should handle this error. + +Fixes: CID 473856 + +Signed-off-by: Alec Brown +Reviewed-by: Ross Philipson +Reviewed-by: Daniel Kiper +--- + grub-core/fs/sfs.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/fs/sfs.c b/grub-core/fs/sfs.c +index 88705b3a2..bad4ae8d1 100644 +--- a/grub-core/fs/sfs.c ++++ b/grub-core/fs/sfs.c +@@ -429,6 +429,9 @@ grub_sfs_mount (grub_disk_t disk) + - 24 /* offsetof (struct grub_sfs_objc, objects) */ + - 25); /* offsetof (struct grub_sfs_obj, filename) */ + data->label = grub_zalloc (max_len + 1); ++ if (data->label == NULL) ++ goto fail; ++ + grub_strncpy (data->label, (char *) rootobjc->objects[0].filename, max_len); + + grub_free (rootobjc_data); diff --git a/0442-script-execute-Fix-potential-underflow-and-NULL-dere.patch b/0442-script-execute-Fix-potential-underflow-and-NULL-dere.patch new file mode 100644 index 0000000..3f2a53c --- /dev/null +++ b/0442-script-execute-Fix-potential-underflow-and-NULL-dere.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lidong Chen +Date: Wed, 29 Jan 2025 06:48:37 +0000 +Subject: [PATCH] script/execute: Fix potential underflow and NULL dereference + +The result is initialized to 0 in grub_script_arglist_to_argv(). +If the for loop condition is not met both result.args and result.argc +remain 0 causing result.argc - 1 to underflow and/or result.args NULL +dereference. Fix the issues by adding relevant checks. + +Fixes: CID 473880 + +Signed-off-by: Lidong Chen +Reviewed-by: Daniel Kiper +--- + grub-core/script/execute.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c +index c383eb87c..89fdaa101 100644 +--- a/grub-core/script/execute.c ++++ b/grub-core/script/execute.c +@@ -794,6 +794,9 @@ cleanup: + } + } + ++ if (result.args == NULL || result.argc == 0) ++ goto fail; ++ + if (! result.args[result.argc - 1]) + result.argc--; + diff --git a/0443-osdep-unix-getroot-Fix-potential-underflow.patch b/0443-osdep-unix-getroot-Fix-potential-underflow.patch new file mode 100644 index 0000000..d1321a8 --- /dev/null +++ b/0443-osdep-unix-getroot-Fix-potential-underflow.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lidong Chen +Date: Wed, 29 Jan 2025 06:48:38 +0000 +Subject: [PATCH] osdep/unix/getroot: Fix potential underflow + +The entry_len is initialized in grub_find_root_devices_from_mountinfo() +to 0 before the while loop iterates through /proc/self/mountinfo. If the +file is empty or contains only invalid entries entry_len remains +0 causing entry_len - 1 in the subsequent for loop initialization +to underflow. To prevent this add a check to ensure entry_len > 0 before +entering the for loop. + +Fixes: CID 473877 + +Signed-off-by: Lidong Chen +Reviewed-by: Daniel Kiper +Reviewed-by: Ross Philipson +--- + grub-core/osdep/linux/getroot.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c +index f0c503f43..893527a95 100644 +--- a/grub-core/osdep/linux/getroot.c ++++ b/grub-core/osdep/linux/getroot.c +@@ -599,6 +599,9 @@ again: + } + } + ++ if (!entry_len) ++ goto out; ++ + /* Now scan visible mounts for the ones we're interested in. */ + for (i = entry_len - 1; i >= 0; i--) + { diff --git a/0444-misc-Ensure-consistent-overflow-error-messages.patch b/0444-misc-Ensure-consistent-overflow-error-messages.patch new file mode 100644 index 0000000..76a6386 --- /dev/null +++ b/0444-misc-Ensure-consistent-overflow-error-messages.patch @@ -0,0 +1,55 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lidong Chen +Date: Tue, 21 Jan 2025 19:02:39 +0000 +Subject: [PATCH] misc: Ensure consistent overflow error messages + +Update the overflow error messages to make them consistent +across the GRUB code. + +Signed-off-by: Lidong Chen +Reviewed-by: Daniel Kiper +--- + grub-core/fs/ntfs.c | 2 +- + grub-core/fs/ntfscomp.c | 2 +- + grub-core/video/readers/png.c | 2 +- + 3 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index 96f038c54..7ebcaf063 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -574,7 +574,7 @@ retry: + goto retry; + } + } +- return grub_error (GRUB_ERR_BAD_FS, "run list overflown"); ++ return grub_error (GRUB_ERR_BAD_FS, "run list overflow"); + } + ctx->curr_vcn = ctx->next_vcn; + ctx->next_vcn += read_run_data (run, c1, 0); /* length of current VCN */ +diff --git a/grub-core/fs/ntfscomp.c b/grub-core/fs/ntfscomp.c +index 4bf95c85d..88594702e 100644 +--- a/grub-core/fs/ntfscomp.c ++++ b/grub-core/fs/ntfscomp.c +@@ -30,7 +30,7 @@ static grub_err_t + decomp_nextvcn (struct grub_ntfs_comp *cc) + { + if (cc->comp_head >= cc->comp_tail) +- return grub_error (GRUB_ERR_BAD_FS, "compression block overflown"); ++ return grub_error (GRUB_ERR_BAD_FS, "compression block overflow"); + if (grub_disk_read + (cc->disk, + (cc->comp_table[cc->comp_head].next_lcn - +diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c +index 7f2ba7849..3ff215dd6 100644 +--- a/grub-core/video/readers/png.c ++++ b/grub-core/video/readers/png.c +@@ -622,7 +622,7 @@ static grub_err_t + grub_png_output_byte (struct grub_png_data *data, grub_uint8_t n) + { + if (--data->raw_bytes < 0) +- return grub_error (GRUB_ERR_BAD_FILE_TYPE, "image size overflown"); ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "image size overflow"); + + if (data->cur_column == 0) + { diff --git a/0445-bus-usb-ehci-Define-GRUB_EHCI_TOGGLE-as-grub_uint32_.patch b/0445-bus-usb-ehci-Define-GRUB_EHCI_TOGGLE-as-grub_uint32_.patch new file mode 100644 index 0000000..c919216 --- /dev/null +++ b/0445-bus-usb-ehci-Define-GRUB_EHCI_TOGGLE-as-grub_uint32_.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Alec Brown +Date: Tue, 4 Feb 2025 15:11:10 +0000 +Subject: [PATCH] bus/usb/ehci: Define GRUB_EHCI_TOGGLE as grub_uint32_t + +The Coverity indicates that GRUB_EHCI_TOGGLE is an int that contains +a negative value and we are using it for the variable token which is +grub_uint32_t. To remedy this we can cast the definition to grub_uint32_t. + +Fixes: CID 473851 + +Signed-off-by: Alec Brown +Reviewed-by: Daniel Kiper +--- + grub-core/bus/usb/ehci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/bus/usb/ehci.c b/grub-core/bus/usb/ehci.c +index d966fc210..d1e8a01ca 100644 +--- a/grub-core/bus/usb/ehci.c ++++ b/grub-core/bus/usb/ehci.c +@@ -218,7 +218,7 @@ enum + + #define GRUB_EHCI_TERMINATE (1<<0) + +-#define GRUB_EHCI_TOGGLE (1<<31) ++#define GRUB_EHCI_TOGGLE ((grub_uint32_t) 1<<31) + + enum + { diff --git a/0446-normal-menu-Use-safe-math-to-avoid-an-integer-overfl.patch b/0446-normal-menu-Use-safe-math-to-avoid-an-integer-overfl.patch new file mode 100644 index 0000000..56fe75c --- /dev/null +++ b/0446-normal-menu-Use-safe-math-to-avoid-an-integer-overfl.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Alec Brown +Date: Tue, 4 Feb 2025 15:11:11 +0000 +Subject: [PATCH] normal/menu: Use safe math to avoid an integer overflow + +The Coverity indicates that the variable current_entry might overflow. +To prevent this use safe math when adding GRUB_MENU_PAGE_SIZE to current_entry. + +On the occasion fix limiting condition which was broken. + +Fixes: CID 473853 + +Signed-off-by: Alec Brown +Reviewed-by: Daniel Kiper +--- + grub-core/normal/menu.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c +index c8516a5a0..9a6033109 100644 +--- a/grub-core/normal/menu.c ++++ b/grub-core/normal/menu.c +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + + /* Time to delay after displaying an error message about a default/fallback + entry failing to boot. */ +@@ -784,9 +785,7 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot, int *notify_boot) + + case GRUB_TERM_CTRL | 'c': + case GRUB_TERM_KEY_NPAGE: +- if (current_entry + GRUB_MENU_PAGE_SIZE < menu->size) +- current_entry += GRUB_MENU_PAGE_SIZE; +- else ++ if (grub_add (current_entry, GRUB_MENU_PAGE_SIZE, ¤t_entry) || current_entry >= menu->size) + current_entry = menu->size - 1; + menu_set_chosen_entry (current_entry); + break; diff --git a/0447-kern-partition-Add-sanity-check-after-grub_strtoul-c.patch b/0447-kern-partition-Add-sanity-check-after-grub_strtoul-c.patch new file mode 100644 index 0000000..20b221f --- /dev/null +++ b/0447-kern-partition-Add-sanity-check-after-grub_strtoul-c.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lidong Chen +Date: Thu, 6 Feb 2025 18:16:56 +0000 +Subject: [PATCH] kern/partition: Add sanity check after grub_strtoul() call + +The current code incorrectly assumes that both the input and the values +returned by grub_strtoul() are always valid which can lead to potential +errors. This fix ensures proper validation to prevent any unintended issues. + +Fixes: CID 473843 + +Signed-off-by: Lidong Chen +Reviewed-by: Daniel Kiper +--- + grub-core/kern/partition.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/grub-core/kern/partition.c b/grub-core/kern/partition.c +index f3f125e75..144a7b6a6 100644 +--- a/grub-core/kern/partition.c ++++ b/grub-core/kern/partition.c +@@ -125,14 +125,22 @@ grub_partition_probe (struct grub_disk *disk, const char *str) + for (ptr = str; *ptr;) + { + grub_partition_map_t partmap; +- int num; ++ unsigned long num; + const char *partname, *partname_end; + + partname = ptr; + while (*ptr && grub_isalpha (*ptr)) + ptr++; + partname_end = ptr; +- num = grub_strtoul (ptr, &ptr, 0) - 1; ++ ++ num = grub_strtoul (ptr, &ptr, 0); ++ if (*ptr != '\0' || num == 0 || num > GRUB_INT_MAX) ++ { ++ grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid partition number")); ++ return 0; ++ } ++ ++ num -= 1; + + curpart = 0; + /* Use the first partition map type found. */ diff --git a/0448-kern-misc-Add-sanity-check-after-grub_strtoul-call.patch b/0448-kern-misc-Add-sanity-check-after-grub_strtoul-call.patch new file mode 100644 index 0000000..84f708d --- /dev/null +++ b/0448-kern-misc-Add-sanity-check-after-grub_strtoul-call.patch @@ -0,0 +1,57 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lidong Chen +Date: Thu, 6 Feb 2025 18:16:57 +0000 +Subject: [PATCH] kern/misc: Add sanity check after grub_strtoul() call + +When the format string, fmt0, includes a positional argument +grub_strtoul() or grub_strtoull() is called to extract the argument +position. However, the returned argument position isn't fully validated. +If the format is something like "%0$x" then these functions return +0 which leads to an underflow in the calculation of the args index, curn. +The fix is to add a check to ensure the extracted argument position is +greater than 0 before computing curn. Additionally, replace one +grub_strtoull() with grub_strtoul() and change curn type to make code +more correct. + +Fixes: CID 473841 + +Signed-off-by: Lidong Chen +Reviewed-by: Daniel Kiper +--- + grub-core/kern/misc.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c +index 50af9ee1b..da2f6e551 100644 +--- a/grub-core/kern/misc.c ++++ b/grub-core/kern/misc.c +@@ -858,7 +858,7 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args, + while ((c = *fmt++) != 0) + { + int longfmt = 0; +- grub_size_t curn; ++ unsigned long curn; + const char *p; + + if (c != '%') +@@ -876,7 +876,10 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args, + + if (*fmt == '$') + { +- curn = grub_strtoull (p, 0, 10) - 1; ++ curn = grub_strtoul (p, 0, 10); ++ if (curn == 0) ++ continue; ++ curn--; + fmt++; + } + +@@ -1035,6 +1038,8 @@ grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt0, + + if (*fmt == '$') + { ++ if (format1 == 0) ++ continue; + curn = format1 - 1; + fmt++; + format1 = 0; diff --git a/0449-loader-i386-linux-Cast-left-shift-to-grub_uint32_t.patch b/0449-loader-i386-linux-Cast-left-shift-to-grub_uint32_t.patch new file mode 100644 index 0000000..f93be9e --- /dev/null +++ b/0449-loader-i386-linux-Cast-left-shift-to-grub_uint32_t.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Alec Brown +Date: Wed, 12 Feb 2025 10:56:13 -0600 +Subject: [PATCH] loader/i386/linux: Cast left shift to grub_uint32_t + +The Coverity complains that we might overflow into a negative value when +setting linux_params.kernel_alignment to (1 << align). We can remedy +this by casting it to grub_uint32_t. + +Fixes: CID 473876 + +Signed-off-by: Alec Brown +Reviewed-by: Daniel Kiper +--- + grub-core/loader/i386/linux.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c +index 3c1ff6476..9d4c57619 100644 +--- a/grub-core/loader/i386/linux.c ++++ b/grub-core/loader/i386/linux.c +@@ -811,7 +811,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W, GRUB_MEM_ATTR_X); + + linux_params.code32_start = prot_mode_target + lh.code32_start - GRUB_LINUX_BZIMAGE_ADDR; +- linux_params.kernel_alignment = (1 << align); ++ linux_params.kernel_alignment = ((grub_uint32_t)1 << align); + linux_params.ps_mouse = linux_params.padding11 = 0; + linux_params.type_of_loader = GRUB_LINUX_BOOT_LOADER_TYPE; + diff --git a/0450-loader-i386-bsd-Use-safe-math-to-avoid-underflow.patch b/0450-loader-i386-bsd-Use-safe-math-to-avoid-underflow.patch new file mode 100644 index 0000000..a404600 --- /dev/null +++ b/0450-loader-i386-bsd-Use-safe-math-to-avoid-underflow.patch @@ -0,0 +1,56 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Alec Brown +Date: Wed, 5 Feb 2025 22:04:08 +0000 +Subject: [PATCH] loader/i386/bsd: Use safe math to avoid underflow + +The operation kern_end - kern_start may underflow when we input it into +grub_relocator_alloc_chunk_addr() call. To avoid this we can use safe +math for this subtraction. + +Fixes: CID 73845 + +Signed-off-by: Alec Brown +Reviewed-by: Daniel Kiper +--- + grub-core/loader/i386/bsd.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c +index 54befc266..939628f9e 100644 +--- a/grub-core/loader/i386/bsd.c ++++ b/grub-core/loader/i386/bsd.c +@@ -1341,6 +1341,7 @@ static grub_err_t + grub_bsd_load_elf (grub_elf_t elf, const char *filename) + { + grub_err_t err; ++ grub_size_t sz; + + kern_end = 0; + kern_start = ~0; +@@ -1371,8 +1372,11 @@ grub_bsd_load_elf (grub_elf_t elf, const char *filename) + + if (grub_errno) + return grub_errno; +- err = grub_relocator_alloc_chunk_addr (relocator, &ch, +- kern_start, kern_end - kern_start); ++ ++ if (grub_sub (kern_end, kern_start, &sz)) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, "underflow detected while determining size of kernel for relocator"); ++ ++ err = grub_relocator_alloc_chunk_addr (relocator, &ch, kern_start, sz); + if (err) + return err; + +@@ -1432,8 +1436,10 @@ grub_bsd_load_elf (grub_elf_t elf, const char *filename) + { + grub_relocator_chunk_t ch; + +- err = grub_relocator_alloc_chunk_addr (relocator, &ch, kern_start, +- kern_end - kern_start); ++ if (grub_sub (kern_end, kern_start, &sz)) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, "underflow detected while determining size of kernel for relocator"); ++ ++ err = grub_relocator_alloc_chunk_addr (relocator, &ch, kern_start, sz); + if (err) + return err; + kern_chunk_src = get_virtual_current_address (ch); diff --git a/0451-types-Make-bool-generally-available.patch b/0451-types-Make-bool-generally-available.patch new file mode 100644 index 0000000..62253cf --- /dev/null +++ b/0451-types-Make-bool-generally-available.patch @@ -0,0 +1,78 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Fri, 4 Nov 2022 12:13:34 -0400 +Subject: [PATCH] types: Make bool generally available + +Add an include on stdbool.h, making the bool type generally available +within the GRUB without needing to add a file-specific include every +time it would be used. + +Signed-off-by: Robbie Harwood +Reviewed-by: Daniel Kiper +--- + grub-core/commands/parttool.c | 2 +- + grub-core/parttool/msdospart.c | 4 ++-- + include/grub/parttool.h | 2 +- + include/grub/types.h | 1 + + 4 files changed, 5 insertions(+), 4 deletions(-) + +diff --git a/grub-core/commands/parttool.c b/grub-core/commands/parttool.c +index 051e31320..ff45c65e6 100644 +--- a/grub-core/commands/parttool.c ++++ b/grub-core/commands/parttool.c +@@ -315,7 +315,7 @@ grub_cmd_parttool (grub_command_t cmd __attribute__ ((unused)), + switch (curarg->type) + { + case GRUB_PARTTOOL_ARG_BOOL: +- pargs[curarg - ptool->args].bool ++ pargs[curarg - ptool->args].b + = (args[j][grub_strlen (curarg->name)] != '-'); + break; + +diff --git a/grub-core/parttool/msdospart.c b/grub-core/parttool/msdospart.c +index 3918caa06..3a7699e45 100644 +--- a/grub-core/parttool/msdospart.c ++++ b/grub-core/parttool/msdospart.c +@@ -61,7 +61,7 @@ static grub_err_t grub_pcpart_boot (const grub_device_t dev, + return grub_errno; + } + +- if (args[0].set && args[0].bool) ++ if (args[0].set && args[0].b) + { + for (i = 0; i < 4; i++) + mbr.entries[i].flag = 0x0; +@@ -116,7 +116,7 @@ static grub_err_t grub_pcpart_type (const grub_device_t dev, + + if (args[1].set) + { +- if (args[1].bool) ++ if (args[1].b) + type |= GRUB_PC_PARTITION_TYPE_HIDDEN_FLAG; + else + type &= ~GRUB_PC_PARTITION_TYPE_HIDDEN_FLAG; +diff --git a/include/grub/parttool.h b/include/grub/parttool.h +index 4e8f8d5e5..4799a22c5 100644 +--- a/include/grub/parttool.h ++++ b/include/grub/parttool.h +@@ -32,7 +32,7 @@ struct grub_parttool_args + int set; + union + { +- int bool; ++ int b; + char *str; + }; + }; +diff --git a/include/grub/types.h b/include/grub/types.h +index ba446d990..c00842ab0 100644 +--- a/include/grub/types.h ++++ b/include/grub/types.h +@@ -20,6 +20,7 @@ + #define GRUB_TYPES_HEADER 1 + + #include ++#include + #ifndef GRUB_UTIL + #include + #endif diff --git a/0452-include-grub-types.h-Add-PRI-GRUB_OFFSET-and-PRI-GRU.patch b/0452-include-grub-types.h-Add-PRI-GRUB_OFFSET-and-PRI-GRU.patch new file mode 100644 index 0000000..4ec6e6e --- /dev/null +++ b/0452-include-grub-types.h-Add-PRI-GRUB_OFFSET-and-PRI-GRU.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Wed, 28 Jun 2023 02:38:23 -0500 +Subject: [PATCH] include/grub/types.h: Add PRI*GRUB_OFFSET and + PRI*GRUB_DISK_ADDR + +These are currently always the same as PRI*GRUB_UINT64_T, but they may +not be in the future. + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + include/grub/types.h | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/include/grub/types.h b/include/grub/types.h +index c00842a..1587ff4 100644 +--- a/include/grub/types.h ++++ b/include/grub/types.h +@@ -181,10 +181,13 @@ typedef grub_uint64_t grub_properly_aligned_t; + #define GRUB_PROPERLY_ALIGNED_ARRAY(name, size) grub_properly_aligned_t name[((size) + sizeof (grub_properly_aligned_t) - 1) / sizeof (grub_properly_aligned_t)] + + /* The type for representing a file offset. */ +-typedef grub_uint64_t grub_off_t; ++typedef grub_uint64_t grub_off_t; ++#define PRIxGRUB_OFFSET PRIxGRUB_UINT64_T ++#define PRIuGRUB_OFFSET PRIuGRUB_UINT64_T + + /* The type for representing a disk block address. */ +-typedef grub_uint64_t grub_disk_addr_t; ++typedef grub_uint64_t grub_disk_addr_t; ++#define PRIxGRUB_DISK_ADDR PRIxGRUB_UINT64_T + + /* Byte-orders. */ + static inline grub_uint16_t grub_swap_bytes16(grub_uint16_t _x) diff --git a/0453-fs-xfs-Fix-issues-found-while-fuzzing-the-XFS-filesy.patch b/0453-fs-xfs-Fix-issues-found-while-fuzzing-the-XFS-filesy.patch new file mode 100644 index 0000000..c704ede --- /dev/null +++ b/0453-fs-xfs-Fix-issues-found-while-fuzzing-the-XFS-filesy.patch @@ -0,0 +1,106 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Fri, 2 Jun 2023 18:08:44 +0000 +Subject: [PATCH] fs/xfs: Fix issues found while fuzzing the XFS filesystem + +While performing fuzz testing with XFS filesystem images with ASAN +enabled, several issues were found where the memory accesses are made +beyond the data that is allocated into the struct grub_xfs_data +structure's data field. + +The existing structure didn't store the size of the memory allocated into +the buffer in the data field and had no way to check it. To resolve these +issues, the data size is stored to enable checks into the data buffer. + +With these checks in place, the fuzzing corpus no longer cause any crashes. + +Signed-off-by: Darren Kenny +Signed-off-by: Robbie Harwood +Signed-off-by: Marta Lewandowska +Signed-off-by: Lidong Chen +Reviewed-by: Daniel Kiper +--- + grub-core/fs/xfs.c | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c +index ff6fe3d..cc50feb 100644 +--- a/grub-core/fs/xfs.c ++++ b/grub-core/fs/xfs.c +@@ -239,6 +239,7 @@ struct grub_fshelp_node + + struct grub_xfs_data + { ++ grub_size_t data_size; + struct grub_xfs_sblock sblock; + grub_disk_t disk; + int pos; +@@ -621,8 +622,20 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) + } + else if (node->inode.format == XFS_INODE_FORMAT_EXT) + { ++ grub_addr_t exts_end = 0; ++ grub_addr_t data_end = 0; ++ + nrec = grub_be_to_cpu32 (node->inode.nextents); + exts = (struct grub_xfs_extent *) grub_xfs_inode_data(&node->inode); ++ ++ if (grub_mul (sizeof (struct grub_xfs_extent), nrec, &exts_end) || ++ grub_add ((grub_addr_t) node->data, exts_end, &exts_end) || ++ grub_add ((grub_addr_t) node->data, node->data->data_size, &data_end) || ++ exts_end > data_end) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "invalid number of XFS extents"); ++ return 0; ++ } + } + else + { +@@ -825,6 +838,9 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + grub_uint8_t *inopos = grub_xfs_inline_de_inopos(dir->data, de); + grub_uint8_t c; + ++ if ((inopos + (smallino ? 4 : 8)) > (grub_uint8_t *) dir + grub_xfs_fshelp_size (dir->data)) ++ return grub_error (GRUB_ERR_BAD_FS, "not a correct XFS inode"); ++ + /* inopos might be unaligned. */ + if (smallino) + ino = (((grub_uint32_t) inopos[0]) << 24) +@@ -851,6 +867,10 @@ 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; + } +@@ -916,6 +936,9 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + } + + filename = (char *)(direntry + 1); ++ if (filename + direntry->len - 1 > (char *) tail) ++ return grub_error (GRUB_ERR_BAD_FS, "invalid XFS directory entry"); ++ + /* The byte after the filename is for the filetype, padding, or + tag, which is not used by GRUB. So it can be overwritten. */ + filename[direntry->len] = '\0'; +@@ -960,6 +983,8 @@ grub_xfs_mount (grub_disk_t disk) + if (!data) + return 0; + ++ data->data_size = sizeof (struct grub_xfs_data); ++ + grub_dprintf("xfs", "Reading sb\n"); + /* Read the superblock. */ + if (grub_disk_read (disk, 0, 0, +@@ -981,6 +1006,7 @@ grub_xfs_mount (grub_disk_t disk) + if (! data) + goto fail; + ++ data->data_size = sz; + data->diropen.data = data; + data->diropen.ino = grub_be_to_cpu64(data->sblock.rootino); + data->diropen.inode_read = 1; diff --git a/grub.patches b/grub.patches index 99351a8..c25acf8 100644 --- a/grub.patches +++ b/grub.patches @@ -352,3 +352,102 @@ Patch0351: 0351-arm64-Use-proper-memory-type-for-kernel-allocation.patch Patch0352: 0352-cmd-search-Fix-a-possible-NULL-ptr-dereference.patch Patch0353: 0353-10_linux.in-escape-semicolon-and-ampersand-on-BLS-up.patch Patch0354: 0354-kern-ieee1275-init-Add-IEEE-1275-Radix-support-for-K.patch +Patch0355: 0355-misc-Implement-grub_strlcpy.patch +Patch0356: 0356-fs-ufs-Fix-a-heap-OOB-write.patch +Patch0357: 0357-fs-hfs-Fix-stack-OOB-write-with-grub_strcpy.patch +Patch0358: 0358-fs-tar-Initialize-name-in-grub_cpio_find_file.patch +Patch0359: 0359-fs-tar-Integer-overflow-leads-to-heap-OOB-write.patch +Patch0360: 0360-fs-f2fs-Set-a-grub_errno-if-mount-fails.patch +Patch0361: 0361-fs-hfsplus-Set-a-grub_errno-if-mount-fails.patch +Patch0362: 0362-fs-iso9660-Set-a-grub_errno-if-mount-fails.patch +Patch0363: 0363-fs-iso9660-Fix-invalid-free.patch +Patch0364: 0364-fs-jfs-Fix-OOB-read-in-jfs_getent.patch +Patch0365: 0365-fs-jfs-Fix-OOB-read-caused-by-invalid-dir-slot-index.patch +Patch0366: 0366-fs-jfs-Use-full-40-bits-offset-and-address-for-a-dat.patch +Patch0367: 0367-fs-jfs-Inconsistent-signed-unsigned-types-usage-in-r.patch +Patch0368: 0368-fs-ext2-Fix-out-of-bounds-read-for-inline-extents.patch +Patch0369: 0369-fs-ntfs-Fix-out-of-bounds-read.patch +Patch0370: 0370-fs-ntfs-Track-the-end-of-the-MFT-attribute-buffer.patch +Patch0371: 0371-fs-ntfs-Use-a-helper-function-to-access-attributes.patch +Patch0372: 0372-fs-ntfs-Implement-attribute-verification.patch +Patch0373: 0373-fs-xfs-Fix-out-of-bounds-read.patch +Patch0374: 0374-fs-xfs-Ensuring-failing-to-mount-sets-a-grub_errno.patch +Patch0375: 0375-kern-file-Ensure-file-data-is-set.patch +Patch0376: 0376-kern-file-Implement-filesystem-reference-counting.patch +Patch0377: 0377-cli_lock-Add-build-option-to-block-command-line-inte.patch +Patch0378: 0378-cryptodisk-Refactor-to-discard-have_it-global.patch +Patch0379: 0379-cryptodisk-Return-failure-in-cryptomount-when-no-cry.patch +Patch0380: 0380-cryptodisk-Improve-error-messaging-in-cryptomount-in.patch +Patch0381: 0381-cryptodisk-Improve-cryptomount-u-error-message.patch +Patch0382: 0382-cryptodisk-Add-infrastructure-to-pass-data-from-cryp.patch +Patch0383: 0383-cryptodisk-Refactor-password-input-out-of-crypto-dev.patch +Patch0384: 0384-luks2-Add-debug-message-to-align-with-luks-and-geli-.patch +Patch0385: 0385-cryptodisk-Move-global-variables-into-grub_cryptomou.patch +Patch0386: 0386-cryptodisk-Improve-handling-of-partition-name-in-cry.patch +Patch0387: 0387-cryptodisk-Fix-Coverity-use-after-free-bug.patch +Patch0388: 0388-disk-cryptodisk-Add-options-to-cryptomount-to-suppor.patch +Patch0389: 0389-disk-cryptodisk-Use-enum-constants-as-indexes-into-c.patch +Patch0390: 0390-cryptodisk-Add-support-for-using-detached-header-fil.patch +Patch0391: 0391-disk-cryptodisk-Support-encrypted-volumes-using-deta.patch +Patch0392: 0392-disk-cryptodisk-Allows-UUIDs-to-be-compared-in-a-das.patch +Patch0393: 0393-disk-cryptodisk-Fix-unintentional-integer-overflow.patch +Patch0394: 0394-disk-cryptodisk-When-cheatmounting-use-the-sector-in.patch +Patch0395: 0395-disk-cryptodisk-Fix-missing-change-when-updating-to-.patch +Patch0396: 0396-disk-cryptodisk-Optimize-luks_script_get.patch +Patch0397: 0397-disk-cryptodisk-Add-support-for-LUKS2-in-proc-luks_s.patch +Patch0398: 0398-disk-cryptodisk-Require-authentication-after-TPM-unl.patch +Patch0399: 0399-disk-loopback-Reference-tracking-for-the-loopback.patch +Patch0400: 0400-kern-disk-Limit-recursion-depth.patch +Patch0401: 0401-kern-partition-Limit-recursion-in-part_iterate.patch +Patch0402: 0402-script-execute-Limit-the-recursion-depth.patch +Patch0403: 0403-net-Unregister-net_default_ip-and-net_default_mac-va.patch +Patch0404: 0404-net-Remove-variables-hooks-when-interface-is-unregis.patch +Patch0405: 0405-net-Fix-OOB-write-in-grub_net_search_config_file.patch +Patch0406: 0406-net-tftp-Fix-stack-buffer-overflow-in-tftp_open.patch +Patch0407: 0407-video-readers-jpeg-Do-not-permit-duplicate-SOF0-mark.patch +Patch0408: 0408-kern-dl-Fix-for-an-integer-overflow-in-grub_dl_ref.patch +Patch0409: 0409-kern-dl-Check-for-the-SHF_INFO_LINK-flag-in-grub_dl_.patch +Patch0410: 0410-commands-extcmd-Missing-check-for-failed-allocation.patch +Patch0411: 0411-commands-ls-Fix-NULL-dereference.patch +Patch0412: 0412-commands-pgp-Unregister-the-check_signatures-hooks-o.patch +Patch0413: 0413-normal-Remove-variables-hooks-on-module-unload.patch +Patch0414: 0414-gettext-Remove-variables-hooks-on-module-unload.patch +Patch0415: 0415-gettext-Integer-overflow-leads-to-heap-OOB-write-or-.patch +Patch0416: 0416-gettext-Integer-overflow-leads-to-heap-OOB-write.patch +Patch0417: 0417-commands-read-Add-silent-mode-to-read-command-to-sup.patch +Patch0418: 0418-commands-read-Fix-overflow-in-grub_getline.patch +Patch0419: 0419-commands-read-Fix-an-integer-overflow-when-supplying.patch +Patch0420: 0420-commands-test-Stack-overflow-due-to-unlimited-recurs.patch +Patch0421: 0421-commands-minicmd-Block-the-dump-command-in-lockdown-.patch +Patch0422: 0422-commands-memrw-Disable-memory-reading-in-lockdown-mo.patch +Patch0423: 0423-commands-hexdump-Disable-memory-reading-in-lockdown-.patch +Patch0424: 0424-fs-bfs-Disable-under-lockdown.patch +Patch0425: 0425-fs-Disable-many-filesystems-under-lockdown.patch +Patch0426: 0426-disk-plainmount-Support-plain-encryption-mode.patch +Patch0427: 0427-disk-Use-safe-math-macros-to-prevent-overflows.patch +Patch0428: 0428-disk-Prevent-overflows-when-allocating-memory-for-ar.patch +Patch0429: 0429-disk-Check-if-returned-pointer-for-allocated-memory-.patch +Patch0430: 0430-disk-ieee1275-ofdisk-Call-grub_ieee1275_close-when-g.patch +Patch0431: 0431-fs-Use-safe-math-macros-to-prevent-overflows.patch +Patch0432: 0432-fs-Prevent-overflows-when-allocating-memory-for-arra.patch +Patch0433: 0433-fs-Prevent-overflows-when-assigning-returned-values-.patch +Patch0434: 0434-fs-zfs-Use-safe-math-macros-to-prevent-overflows.patch +Patch0435: 0435-fs-zfs-Prevent-overflows-when-allocating-memory-for-.patch +Patch0436: 0436-fs-zfs-Check-if-returned-pointer-for-allocated-memor.patch +Patch0437: 0437-fs-zfs-Add-missing-NULL-check-after-grub_strdup-call.patch +Patch0438: 0438-net-Use-safe-math-macros-to-prevent-overflows.patch +Patch0439: 0439-net-Prevent-overflows-when-allocating-memory-for-arr.patch +Patch0440: 0440-net-Check-if-returned-pointer-for-allocated-memory-i.patch +Patch0441: 0441-fs-sfs-Check-if-allocated-memory-is-NULL.patch +Patch0442: 0442-script-execute-Fix-potential-underflow-and-NULL-dere.patch +Patch0443: 0443-osdep-unix-getroot-Fix-potential-underflow.patch +Patch0444: 0444-misc-Ensure-consistent-overflow-error-messages.patch +Patch0445: 0445-bus-usb-ehci-Define-GRUB_EHCI_TOGGLE-as-grub_uint32_.patch +Patch0446: 0446-normal-menu-Use-safe-math-to-avoid-an-integer-overfl.patch +Patch0447: 0447-kern-partition-Add-sanity-check-after-grub_strtoul-c.patch +Patch0448: 0448-kern-misc-Add-sanity-check-after-grub_strtoul-call.patch +Patch0449: 0449-loader-i386-linux-Cast-left-shift-to-grub_uint32_t.patch +Patch0450: 0450-loader-i386-bsd-Use-safe-math-to-avoid-underflow.patch +Patch0451: 0451-types-Make-bool-generally-available.patch +Patch0452: 0452-include-grub-types.h-Add-PRI-GRUB_OFFSET-and-PRI-GRU.patch +Patch0453: 0453-fs-xfs-Fix-issues-found-while-fuzzing-the-XFS-filesy.patch diff --git a/grub2.spec b/grub2.spec index 42943a2..b6d2d56 100644 --- a/grub2.spec +++ b/grub2.spec @@ -16,7 +16,7 @@ Name: grub2 Epoch: 1 Version: 2.06 -Release: 95%{?dist} +Release: 96%{?dist} Summary: Bootloader with support for Linux, Multiboot and more License: GPLv3+ URL: http://www.gnu.org/software/grub/ @@ -547,6 +547,28 @@ mv ${EFI_HOME}/grub.cfg.stb ${EFI_HOME}/grub.cfg %endif %changelog +* Wed Feb 12 2025 Nicolas Frayer - 2.06-96 +- Fixes for several CVEs +- Resolves: CVE-2024-45779 CVE-2024-45778 CVE-2025-1118 +- Resolves: CVE-2025-0677 CVE-2024-45782 CVE-2025-0690 +- Resolves: CVE-2024-45783 CVE-2025-0624 CVE-2024-45776 +- Resolves: CVE-2025-0622 CVE-2024-45774 CVE-2024-45775 +- Resolves: CVE-2024-45781 CVE-2024-45780 +- Resolves: #RHEL-79700 +- Resolves: #RHEL-79341 +- Resolves: #RHEL-79875 +- Resolves: #RHEL-79849 +- Resolves: #RHEL-79707 +- Resolves: #RHEL-79857 +- Resolves: #RHEL-79709 +- Resolves: #RHEL-79846 +- Resolves: #RHEL-75737 +- Resolves: #RHEL-79713 +- Resolves: #RHEL-73785 +- Resolves: #RHEL-73787 +- Resolves: #RHEL-79704 +- Resolves: #RHEL-79702 + * Mon Jan 13 2025 Nicolas Frayer - 2.06-95 - kern/ieee1275/init: Add IEEE 1275 Radix support for KVM on Power - Resolves: #RHEL-52761