From 28b4487267ce1809fccc2c5e78869af71ea1184a Mon Sep 17 00:00:00 2001 From: James Le Cuirot Date: Thu, 12 Feb 2026 18:26:23 +0000 Subject: [PATCH] sys-boot/grub: Refresh the 2.12 patches against Fedora 44 Signed-off-by: James Le Cuirot --- .../coreos/config/env/sys-boot/grub | 4 +- .../sys-boot/grub/grub-2.12-00-redhat.patch | 9891 +++++++++++++++-- .../grub-2.12-01-execute-return-code.patch | 112 - 3 files changed, 9054 insertions(+), 953 deletions(-) delete mode 100644 sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-boot/grub/grub-2.12-01-execute-return-code.patch diff --git a/sdk_container/src/third_party/coreos-overlay/coreos/config/env/sys-boot/grub b/sdk_container/src/third_party/coreos-overlay/coreos/config/env/sys-boot/grub index 932b56a943..a546912347 100644 --- a/sdk_container/src/third_party/coreos-overlay/coreos/config/env/sys-boot/grub +++ b/sdk_container/src/third_party/coreos-overlay/coreos/config/env/sys-boot/grub @@ -1,7 +1,7 @@ # Bump the flatcar version stated here every time we or Red Hat change patches # that modify parts of GRUB that are installed to the boot partition. Reset the # version back to 1 when the upstream GRUB version changes. -FLATCAR_VERSION=flatcar3 +FLATCAR_VERSION=flatcar4 # Gentoo's patches conflict with Red Hat's patches, and none of Gentoo's patches # affect Flatcar, so skip them all. @@ -43,7 +43,7 @@ cros_post_src_install_sbat() { insinto /usr/share/grub newins - sbat.csv <<-EOF sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md - grub,4,Free Software Foundation,grub,${PV},https://www.gnu.org/software/grub/ + grub,5,Free Software Foundation,grub,${PV},https://www.gnu.org/software/grub/ grub.flatcar,1,Flatcar,grub2,${PV}-${FLATCAR_VERSION},https://github.com/flatcar/Flatcar EOF } diff --git a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-boot/grub/grub-2.12-00-redhat.patch b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-boot/grub/grub-2.12-00-redhat.patch index b2b633fafa..d07f902f26 100644 --- a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-boot/grub/grub-2.12-00-redhat.patch +++ b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-boot/grub/grub-2.12-00-redhat.patch @@ -324,7 +324,7 @@ index 9b1d39971..39f4e5472 100644 # define GRUB_STACK_PROTECTOR_INIT @GRUB_STACK_PROTECTOR_INIT@ diff --git a/configure.ac b/configure.ac -index cd667a2eb..4788f3d6a 100644 +index cd667a2eb..a6a6957fb 100644 --- a/configure.ac +++ b/configure.ac @@ -70,6 +70,7 @@ grub_TRANSFORM([grub-install]) @@ -413,7 +413,29 @@ index cd667a2eb..4788f3d6a 100644 AC_CACHE_CHECK([for options to get soft-float], grub_cv_target_cc_soft_float, [ grub_cv_target_cc_soft_float=no if test "x$target_cpu" = xarm64; then -@@ -1321,6 +1359,26 @@ if test "x$target_cpu" = xarm; then +@@ -1275,7 +1313,7 @@ AC_SUBST(TARGET_LDFLAGS_OLDMAGIC) + + LDFLAGS="$TARGET_LDFLAGS" + +-if test "$target_cpu" = x86_64 || test "$target_cpu" = sparc64 || test "$target_cpu" = riscv64 ; then ++if test "$target_cpu" = x86_64 || test "$target_cpu" = sparc64 ; then + # Use large model to support 4G memory + AC_CACHE_CHECK([whether option -mcmodel=large works], grub_cv_cc_mcmodel, [ + CFLAGS="$TARGET_CFLAGS -mcmodel=large" +@@ -1285,9 +1323,11 @@ if test "$target_cpu" = x86_64 || test "$target_cpu" = sparc64 || test "$target_ + ]) + if test "x$grub_cv_cc_mcmodel" = xyes; then + TARGET_CFLAGS="$TARGET_CFLAGS -mcmodel=large" +- elif test "$target_cpu" = sparc64 || test "$target_cpu" = riscv64; then ++ elif test "$target_cpu" = sparc64; then + TARGET_CFLAGS="$TARGET_CFLAGS -mcmodel=medany" + fi ++elif test "$target_cpu" = riscv64 ; then ++ TARGET_CFLAGS="$TARGET_CFLAGS -mcmodel=medany" + fi + + if test "$target_cpu"-"$platform" = x86_64-efi; then +@@ -1321,6 +1361,26 @@ if test "x$target_cpu" = xarm; then done ]) @@ -440,7 +462,7 @@ index cd667a2eb..4788f3d6a 100644 if test x"$grub_cv_target_cc_mno_movt" != xno ; then # A trick so that clang doesn't see it on link stage TARGET_CPPFLAGS="$TARGET_CPPFLAGS $grub_cv_target_cc_mno_movt" -@@ -1527,7 +1585,15 @@ grub_PROG_TARGET_CC +@@ -1527,7 +1587,15 @@ grub_PROG_TARGET_CC if test "x$TARGET_APPLE_LINKER" != x1 ; then grub_PROG_OBJCOPY_ABSOLUTE fi @@ -456,7 +478,7 @@ index cd667a2eb..4788f3d6a 100644 if test "x$target_cpu" = xi386; then if test "$platform" != emu && test "x$TARGET_APPLE_LINKER" != x1 ; then if test ! -z "$TARGET_IMG_LDSCRIPT"; then -@@ -1620,6 +1686,17 @@ else +@@ -1620,6 +1688,17 @@ else fi AC_SUBST([BOOT_TIME_STATS]) @@ -474,7 +496,7 @@ index cd667a2eb..4788f3d6a 100644 AC_ARG_ENABLE([grub-emu-sdl2], [AS_HELP_STRING([--enable-grub-emu-sdl2], [build and install the `grub-emu' debugging utility with SDL2 support (default=guessed)])]) -@@ -1847,7 +1924,7 @@ if test "x$with_dejavufont" = x; then +@@ -1847,7 +1926,7 @@ if test "x$with_dejavufont" = x; then # search in well-known directories if test x"$starfield_excuse" = x; then for ext in pcf pcf.gz bdf bdf.gz ttf ttf.gz; do @@ -483,7 +505,7 @@ index cd667a2eb..4788f3d6a 100644 if test -f "$dir/DejaVuSans.$ext"; then DJVU_FONT_SOURCE="$dir/DejaVuSans.$ext" break 2 -@@ -2081,6 +2158,17 @@ if test x"$enable_werror" != xno ; then +@@ -2081,6 +2160,17 @@ if test x"$enable_werror" != xno ; then fi fi @@ -501,7 +523,7 @@ index cd667a2eb..4788f3d6a 100644 TARGET_CPP="$TARGET_CC -E" TARGET_CCAS=$TARGET_CC -@@ -2090,6 +2178,41 @@ HOST_CPPFLAGS="$HOST_CPPFLAGS -I\$(top_builddir)/include" +@@ -2090,6 +2180,41 @@ HOST_CPPFLAGS="$HOST_CPPFLAGS -I\$(top_builddir)/include" TARGET_CPPFLAGS="$TARGET_CPPFLAGS -I\$(top_srcdir)/include" TARGET_CPPFLAGS="$TARGET_CPPFLAGS -I\$(top_builddir)/include" @@ -543,7 +565,7 @@ index cd667a2eb..4788f3d6a 100644 GRUB_TARGET_CPU="${target_cpu}" GRUB_PLATFORM="${platform}" -@@ -2184,6 +2307,7 @@ AM_CONDITIONAL([COND_APPLE_LINKER], [test x$TARGET_APPLE_LINKER = x1]) +@@ -2184,6 +2309,7 @@ AM_CONDITIONAL([COND_APPLE_LINKER], [test x$TARGET_APPLE_LINKER = x1]) AM_CONDITIONAL([COND_ENABLE_EFIEMU], [test x$enable_efiemu = xyes]) AM_CONDITIONAL([COND_ENABLE_CACHE_STATS], [test x$DISK_CACHE_STATS = x1]) AM_CONDITIONAL([COND_ENABLE_BOOT_TIME_STATS], [test x$BOOT_TIME_STATS = x1]) @@ -551,7 +573,7 @@ index cd667a2eb..4788f3d6a 100644 AM_CONDITIONAL([COND_HAVE_CXX], [test x$HAVE_CXX = xyes]) -@@ -2285,6 +2409,12 @@ else +@@ -2285,6 +2411,12 @@ else echo With boot time statistics: No fi @@ -656,7 +678,7 @@ index 1276c5930..8ad5494f5 100644 You will need to create directory include/$cpu/$platform and a file include/$cpu/types.h. The latter following this template: diff --git a/docs/grub.texi b/docs/grub.texi -index a225f9a88..096a3cde0 100644 +index a225f9a88..d66997233 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -1,7 +1,7 @@ @@ -1215,25 +1237,40 @@ index a225f9a88..096a3cde0 100644 @samp{snap-129}. Trailing @samp{@@} after volume name is mandatory even if snapshot name is omitted. -@@ -3270,6 +3275,7 @@ These variables have special meaning to GRUB. +@@ -3260,6 +3265,7 @@ GRUB. Others may be used freely in GRUB configuration files. + @menu + * Special environment variables:: + * Environment block:: ++* Special environment block variables:: + @end menu + + +@@ -3270,6 +3276,8 @@ These variables have special meaning to GRUB. @menu * biosnum:: ++* blsuki_save_default:: +* check_appended_signatures:: * check_signatures:: * chosen:: * cmdpath:: -@@ -3334,11 +3340,18 @@ For an alternative approach which also changes BIOS drive mappings for the +@@ -3333,12 +3341,24 @@ this. + For an alternative approach which also changes BIOS drive mappings for the chain-loaded system, @pxref{drivemap}. - ++@node blsuki_save_default ++@subsection blsuki_save_default ++ ++If this variable is set, menu entries generated from BLS config files ++(@pxref{blscfg}) or UKI files (@pxref{uki}) will be set as the default boot ++entry when selected. ++ +@node check_appended_signatures +@subsection check_appended_signatures + +This variable controls whether GRUB enforces appended signature validation on +certain loaded files. @xref{Using appended signatures}. -+ -+ + @node check_signatures @subsection check_signatures @@ -1244,7 +1281,7 @@ index a225f9a88..096a3cde0 100644 @node chosen @subsection chosen -@@ -3502,7 +3515,7 @@ The more recent release of Minix would then be identified as +@@ -3502,7 +3522,7 @@ The more recent release of Minix would then be identified as @samp{other>minix>minix-3.4.0}. This variable is often set by @samp{GRUB_DEFAULT} (@pxref{Simple @@ -1253,7 +1290,7 @@ index a225f9a88..096a3cde0 100644 @node fallback -@@ -3592,7 +3605,7 @@ If this variable is set, it names the language code that the +@@ -3592,7 +3612,7 @@ If this variable is set, it names the language code that the example, French would be named as @samp{fr}, and Simplified Chinese as @samp{zh_CN}. @@ -1262,7 +1299,7 @@ index a225f9a88..096a3cde0 100644 reasonable default for this variable based on the system locale. -@@ -3600,10 +3613,10 @@ reasonable default for this variable based on the system locale. +@@ -3600,10 +3620,10 @@ reasonable default for this variable based on the system locale. @subsection locale_dir If this variable is set, it names the directory where translation files may @@ -1275,7 +1312,7 @@ index a225f9a88..096a3cde0 100644 default for this variable if internationalization is needed and any translation files are available. -@@ -3740,7 +3753,7 @@ input. The default is not to pause output. +@@ -3740,7 +3760,7 @@ input. The default is not to pause output. The location of the @samp{/boot/grub} directory as an absolute file name (@pxref{File name syntax}). This is normally set by GRUB at startup based @@ -1284,7 +1321,7 @@ index a225f9a88..096a3cde0 100644 dynamically loaded from this directory, so it must be set correctly in order for many parts of GRUB to work. -@@ -3852,17 +3865,17 @@ GRUB provides an ``environment block'' which can be used to save a small +@@ -3852,19 +3872,73 @@ GRUB provides an ``environment block'' which can be used to save a small amount of state. The environment block is a preallocated 1024-byte file, which normally lives @@ -1301,11 +1338,81 @@ index a225f9a88..096a3cde0 100644 using BIOS or EFI functions (no ATA, USB or IEEE1275). -@command{grub-mkconfig} uses this facility to implement ++On Btrfs filesystems, a reserved area in the filesystem header may be used to ++store the environment block. This static block avoids the problems of updating ++a normal file on a copy-on-write filesystem, where writing raw block is not ++stable and requires metadata update. The reserved area provides a fixed ++location that GRUB can update directly, allowing commands such as ++@command{grub-reboot} and @samp{GRUB_SAVEDEFAULT} to function correctly on ++Btrfs volumes. ++ +@command{grub2-mkconfig} uses this facility to implement @samp{GRUB_SAVEDEFAULT} (@pxref{Simple configuration}). ++@node Special environment block variables ++@section Special environment block variables ++ ++These special variables are usually written to the environment block ++(@pxref{Environment block}) to customize the behavior of @file{grub.cfg} ++generated by @command{grub-mkconfig}. ++ ++@menu ++* saved_entry:: ++* next_entry:: ++* env_block:: ++@end menu ++ ++@node saved_entry ++@subsection saved_entry ++ ++The @var{saved_entry} variable sets the default boot entry in @file{grub.cfg} ++created by @command{grub-mkconfig}. It can be set with ++@command{grub-set-default} to choose a default entry, or at runtime with the ++@code{savedefault} function in grub.cfg to save the current entry as the new ++default. This may require write access by GRUB. ++ ++@node next_entry ++@subsection next_entry ++ ++The @var{next_entry} variable sets the boot entry for the next boot only. After ++it is used, GRUB clears the value so it is not reused. This requires write ++access to the environment block (@pxref{Environment block}) at runtime. The ++@command{grub-reboot} command is usually used instead of changing this variable ++directly. ++ ++@node env_block ++@subsection env_block ++ ++If the filesystem is Btrfs and the disk is not an abstracted device such as ++LVM, RAID, or encryption, the reserved space in the Btrfs header can be used as ++the environment block (@pxref{Environment block}). This provides a fixed raw ++block that GRUB can reliably write to. The @var{env_block} records this ++location in GRUB blocklist syntax (@pxref{Block list syntax}) so that ++@command{grub-editenv} and @file{grub.cfg} know how to access and use the ++external raw block. ++ ++This variable is initialized when @file{grubenv} is first created by ++@command{grub-editenv} and is treated as read-only to avoid being overwritten ++with an unpredictable value. ++ @node Modules -@@ -4357,6 +4370,7 @@ you forget a command, you can run the command @command{help} + @chapter Modules + +@@ -4342,6 +4416,7 @@ you forget a command, you can run the command @command{help} + * background_image:: Load background image for active terminal + * badram:: Filter out bad regions of RAM + * blocklist:: Print a block list ++* blscfg:: Load Boot Loader Specification menu entries + * boot:: Start up your operating system + * cat:: Show the contents of a file + * clear:: Clear the screen +@@ -4352,11 +4427,13 @@ you forget a command, you can run the command @command{help} + * configfile:: Load a configuration file + * cpuid:: Check for CPU features + * crc:: Compute or check CRC32 checksums ++* cryptocheck:: Check if a device is encrypted + * cryptomount:: Mount a crypto device + * cutmem:: Remove memory regions * date:: Display or set current date and time * devicetree:: Load a device tree blob * distrust:: Remove a pubkey from trusted keys @@ -1313,7 +1420,7 @@ index a225f9a88..096a3cde0 100644 * drivemap:: Map a drive to another * echo:: Display a line of text * efitextmode:: Set/Get text output mode resolution -@@ -4373,6 +4387,7 @@ you forget a command, you can run the command @command{help} +@@ -4373,6 +4450,7 @@ you forget a command, you can run the command @command{help} * hexdump:: Show raw contents of a file or memory * insmod:: Insert a module * keystatus:: Check key modifier status @@ -1321,18 +1428,123 @@ index a225f9a88..096a3cde0 100644 * list_env:: List variables in environment block * list_trusted:: List trusted public keys * load_env:: Load variables from environment block -@@ -4411,8 +4426,10 @@ you forget a command, you can run the command @command{help} +@@ -4411,8 +4489,11 @@ you forget a command, you can run the command @command{help} * test:: Check file types and compare values * true:: Do nothing, successfully * trust:: Add public key to list of trusted keys +* trust_certificate:: Add an x509 certificate to the list of trusted certificates ++* uki:: Load Unified Kernel Image menu entries * unset:: Unset an environment variable @comment * vbeinfo:: List available video modes +* verify_appended:: Verify appended digital signature * verify_detached:: Verify detached digital signature * videoinfo:: List available video modes * wrmsr:: Write values to model-specific registers -@@ -4752,9 +4769,28 @@ These keys are used to validate signatures when environment variable +@@ -4524,6 +4605,72 @@ Print a block list (@pxref{Block list syntax}) for @var{file}. + @end deffn + + ++@node blscfg ++@subsection blscfg ++ ++@deffn Command blscfg [@option{-p|--path} dir] [@option{-f|--enable-fallback}] [@option{-d|--show-default}] [@option{-n|--show-non-default}] [@option{-e|--entry} file] ++Load Boot Loader Specification (BLS) entries into the GRUB menu. Boot entries ++generated from @command{blscfg} won't interfere with entries from @file{grub.cfg} appearing in ++the GRUB menu. Also, entries generated from @command{blscfg} exists only in memory and ++don't update @file{grub.cfg}. ++ ++By default, the BLS entries are stored in the @file{/loader/entries} directory in the ++boot partition. If BLS entries are stored elsewhere, the @option{--path} option can be ++used to check a different directory instead of the default location. If no BLS ++entries are found while using the @option{--path} option, the @option{--enable-fallback} option ++can be used to check for entries in the default location. ++ ++The @option{--show-default} option allows the default boot entry to be added to the ++GRUB menu from the BLS entries. ++ ++The @option{--show-non-default} option allows non-default boot entries to be added to ++the GRUB menu from the BLS entries. ++ ++The @option{--entry} option allows specific boot entries to be added to the GRUB menu ++from the BLS entries. ++ ++The @option{--entry}, @option{--show-default}, and @option{--show-non-default} options ++are used to filter which BLS entries are added to the GRUB menu. If none are ++used, all entries in the default location or the location specified by @option{--path} ++will be added to the GRUB menu. ++ ++A BLS config file example: ++@example ++# /boot/loader/entries/6a9857a393724b7a981ebb5b8495b9ea-3.8.0-2.fc19.x86_64.conf ++title Fedora 19 (Rawhide) ++sort-key fedora ++machine-id 6a9857a393724b7a981ebb5b8495b9ea ++version 3.8.0-2.fc19.x86_64 ++options root=UUID=6d3376e4-fc93-4509-95ec-a21d68011da2 quiet ++architecture x64 ++linux /6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/linux ++initrd /6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/initrd ++@end example ++ ++For more information on BLS entry keys as well as other information on BLS, ++see: @uref{https://uapi-group.org/specifications/specs/boot_loader_specification/, The Boot Loader Specification}. For the GRUB, there are a few additional ++BLS entry keys based on the @command{menuentry} command (@pxref{menuentry}). ++ ++The @code{grub_class} key may be used any number of times to group menu entries into ++classes. Menu themes may display different classes using different styles. ++ ++The @code{grub_users} key grants specific users access to specific menu ++entries. @xref{Security}. ++ ++The @code{grub_hotkey} key associates a hotkey with a menu entry. ++@var{key} may be a single letter, or one of the aliases @samp{backspace}, ++@samp{tab}, or @samp{delete}. ++ ++The @code{grub_args} key can be used for any other argument to be passed as positonal ++parameters when the list of commands generated from the BLS config file are ++executed. ++ ++Variable expansion using the @samp{$} character (@xref{Shell-like scripting}) may be ++used with BLS config files for the GRUB but might not be compatible with other ++bootloaders. ++@end deffn ++ ++ + @node boot + @subsection boot + +@@ -4657,6 +4804,18 @@ Alias for @code{hashsum --hash crc32 arg @dots{}}. See command @command{hashsum} + (@pxref{hashsum}) for full description. + @end deffn + ++@node cryptocheck ++@subsection cryptocheck ++ ++@deffn Command cryptocheck [ @option{--quiet} ] device ++Check if a given diskfilter device is backed by encrypted devices ++(@pxref{cryptomount} for additional information). ++ ++The command examines all backing devices, physical volumes, of a specified ++logical volume, like LVM2, and fails when at least one of them is unencrypted. ++ ++The option @option{--quiet} can be given to suppress the output. ++@end deffn + + @node cryptomount + @subsection cryptomount +@@ -4693,6 +4852,11 @@ namespace in addition to the cryptodisk namespace. + + Support for plain encryption mode (plain dm-crypt) is provided via separate + @command{@pxref{plainmount}} command. ++ ++On the EFI platform, GRUB tries to erase master keys from memory when the cryptodisk ++module is unloaded or the command @command{exit} is executed. All secrets remain in ++memory when the command @command{chainloader} is issued, because execution can ++return to GRUB on the EFI platform. + @end deffn + + @node cutmem +@@ -4752,9 +4916,28 @@ These keys are used to validate signatures when environment variable @code{check_signatures} is set to @code{enforce} (@pxref{check_signatures}), and by some invocations of @command{verify_detached} (@pxref{verify_detached}). @xref{Using @@ -1362,7 +1574,7 @@ index a225f9a88..096a3cde0 100644 @node drivemap @subsection drivemap -@@ -4924,7 +4960,7 @@ Translate @var{string} into the current language. +@@ -4924,7 +5107,7 @@ Translate @var{string} into the current language. The current language code is stored in the @samp{lang} variable in GRUB's environment (@pxref{lang}). Translation files in MO format are read from @@ -1371,7 +1583,7 @@ index a225f9a88..096a3cde0 100644 @end deffn -@@ -5031,6 +5067,21 @@ only if checking key modifier status is supported. +@@ -5031,6 +5214,21 @@ only if checking key modifier status is supported. @end deffn @@ -1393,7 +1605,7 @@ index a225f9a88..096a3cde0 100644 @node list_env @subsection list_env -@@ -5050,7 +5101,7 @@ The output is in GPG's v4 key fingerprint format (i.e., the output of +@@ -5050,7 +5248,7 @@ The output is in GPG's v4 key fingerprint format (i.e., the output of @code{gpg --fingerprint}). The least significant four bytes (last eight hexadecimal digits) can be used as an argument to @command{distrust} (@pxref{distrust}). @@ -1402,7 +1614,7 @@ index a225f9a88..096a3cde0 100644 these keys. @end deffn -@@ -5085,8 +5136,13 @@ When used with care, @option{--skip-sig} and the whitelist enable an +@@ -5085,8 +5283,13 @@ When used with care, @option{--skip-sig} and the whitelist enable an administrator to configure a system to boot only signed configurations, but to allow the user to select from among multiple configurations, and to enable ``one-shot'' boot attempts and @@ -1417,7 +1629,7 @@ index a225f9a88..096a3cde0 100644 @end deffn -@@ -5276,7 +5332,7 @@ Define a user named @var{user} with password @var{clear-password}. +@@ -5276,7 +5479,7 @@ Define a user named @var{user} with password @var{clear-password}. @deffn Command password_pbkdf2 user hashed-password Define a user named @var{user} with password hash @var{hashed-password}. @@ -1426,7 +1638,7 @@ index a225f9a88..096a3cde0 100644 to generate password hashes. @xref{Security}. @end deffn -@@ -5457,7 +5513,7 @@ read. It is possible to modify a digitally signed environment block +@@ -5457,7 +5660,7 @@ read. It is possible to modify a digitally signed environment block file from within GRUB using this command, such that its signature will no longer be valid on subsequent boots. Care should be taken in such advanced configurations to avoid rendering the system @@ -1435,7 +1647,32 @@ index a225f9a88..096a3cde0 100644 @end deffn -@@ -5873,11 +5929,32 @@ signatures when environment variable @code{check_signatures} is set to +@@ -5466,7 +5669,8 @@ unbootable. @xref{Using digital signatures}, for more information. + + @deffn Command search @ + [@option{--file}|@option{--label}|@option{--fs-uuid}] @ +- [@option{--set} [var]] [@option{--no-floppy}|@option{--efidisk-only}] name ++ [@option{--set} [var]] [@option{--no-floppy}|@option{--efidisk-only}|@option{--cryptodisk-only}] @ ++ name + Search devices by file (@option{-f}, @option{--file}), filesystem label + (@option{-l}, @option{--label}), or filesystem UUID (@option{-u}, + @option{--fs-uuid}). +@@ -5481,6 +5685,14 @@ devices, which can be slow. + The (@option{--efidisk-only}) option prevents searching any other devices then + EFI disks. This is typically used when chainloading to local EFI partition. + ++The (@option{--cryptodisk-only}) option prevents searching any devices other ++than encrypted disks. This is typically used when booting from an encrypted ++file system to ensure that no code gets executed from an unencrypted device ++having the same filesystem UUID or label. ++ ++This option implicitly invokes the command @command{cryptocheck}, if it is ++available (@pxref{cryptocheck} for additional information). ++ + The @samp{search.file}, @samp{search.fs_label}, and @samp{search.fs_uuid} + commands are aliases for @samp{search --file}, @samp{search --label}, and + @samp{search --fs-uuid} respectively. +@@ -5873,11 +6085,32 @@ signatures when environment variable @code{check_signatures} is set to must itself be properly signed. The @option{--skip-sig} option can be used to disable signature-checking when reading @var{pubkey_file} itself. It is expected that @option{--skip-sig} is useful for testing @@ -1469,7 +1706,46 @@ index a225f9a88..096a3cde0 100644 @node unset @subsection unset -@@ -5896,6 +5973,18 @@ only on PC BIOS platforms. +@@ -5886,6 +6119,38 @@ Unset the environment variable @var{envvar}. + @end deffn + + ++@node uki ++@subsection uki ++ ++@deffn Command uki [@option{-p|--path} dir] [@option{-f|--enable-fallback}] [@option{-d|--show-default}] [@option{-n|--show-non-default}] [@option{-e|--entry} file] ++Load Unified Kernel Image (UKI) files into the GRUB menu. Boot entries ++generated from @command{uki} won't interfere with entries from @file{grub.cfg} appearing in the ++GRUB menu. Also, entries generated from @command{uki} exists only in memory and don't ++update @file{grub.cfg}. ++ ++By default, the UKI files are stored in the @file{/EFI/Linux} directory in the EFI ++system partition. If UKI files are stored elsewhere, the @option{--path} option can be ++used to check a different directory instead of the default location. If no UKI ++files are found while using the @option{--path} option, the @option{--enable-fallback} option can ++be used to check for files in the default location. ++ ++The @option{--show-default} option allows the default boot entry to be added to the ++GRUB menu from the UKI files. ++ ++The @option{--show-non-default} option allows non-default boot entries to be added to ++the GRUB menu from the UKI files. ++ ++The @option{--entry} option allows specific boot entries to be added to the GRUB menu ++from the UKI files. ++ ++The @option{--entry}, @option{--show-default}, and @option{--show-non-default} options ++are used to filter which UKI files are added to the GRUB menu. If none are ++used, all files in the default location or the location specified by @option{--path} ++will be added to the GRUB menu. ++ ++For more information on UKI, see: @uref{https://uapi-group.org/specifications/specs/unified_kernel_image/, The Unified Kernel Image Specification} ++@end deffn ++ + @ignore + @node vbeinfo + @subsection vbeinfo +@@ -5896,6 +6161,18 @@ only on PC BIOS platforms. @end deffn @end ignore @@ -1488,7 +1764,7 @@ index a225f9a88..096a3cde0 100644 @node verify_detached @subsection verify_detached -@@ -5914,7 +6003,7 @@ tried. +@@ -5914,7 +6191,7 @@ tried. Exit code @code{$?} is set to 0 if the signature validates successfully. If validation fails, it is set to a non-zero value. @@ -1497,7 +1773,7 @@ index a225f9a88..096a3cde0 100644 @end deffn @node videoinfo -@@ -5950,6 +6039,7 @@ Note: The command is not allowed when lockdown is enforced (@pxref{Lockdown}). +@@ -5950,6 +6227,7 @@ Note: The command is not allowed when lockdown is enforced (@pxref{Lockdown}). * net_add_dns:: Add a DNS server * net_add_route:: Add routing entry * net_bootp:: Perform a bootp/DHCP autoconfiguration @@ -1505,7 +1781,7 @@ index a225f9a88..096a3cde0 100644 * net_del_addr:: Remove IP address from interface * net_del_dns:: Remove a DNS server * net_del_route:: Remove a route entry -@@ -6075,6 +6165,22 @@ Sets environment variable @samp{net_}@var{}@samp{_boot_file} +@@ -6075,6 +6353,22 @@ Sets environment variable @samp{net_}@var{}@samp{_boot_file} @end deffn @@ -1528,7 +1804,7 @@ index a225f9a88..096a3cde0 100644 @node net_get_dhcp_option @subsection net_get_dhcp_option -@@ -6375,12 +6481,14 @@ environment variables and commands are listed in the same order. +@@ -6375,12 +6669,14 @@ environment variables and commands are listed in the same order. @chapter Security @menu @@ -1549,7 +1825,7 @@ index a225f9a88..096a3cde0 100644 @end menu @node Authentication and authorisation -@@ -6402,8 +6510,8 @@ The @samp{password} (@pxref{password}) and @samp{password_pbkdf2} +@@ -6402,8 +6698,8 @@ The @samp{password} (@pxref{password}) and @samp{password_pbkdf2} which has an associated password. @samp{password} sets the password in plain text, requiring @file{grub.cfg} to be secure; @samp{password_pbkdf2} sets the password hashed using the Password-Based Key Derivation Function @@ -1560,7 +1836,20 @@ index a225f9a88..096a3cde0 100644 In order to enable authentication support, the @samp{superusers} environment variable must be set to a list of usernames, separated by any of spaces, -@@ -6448,18 +6556,18 @@ menuentry "May be run by user1 or a superuser" --users user1 @{ +@@ -6412,8 +6708,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 +@@ -6448,18 +6746,18 @@ menuentry "May be run by user1 or a superuser" --users user1 @{ @end group @end example @@ -1583,7 +1872,7 @@ index a225f9a88..096a3cde0 100644 platform's firmware (e.g., Coreboot) validates @file{core.img}. If environment variable @code{check_signatures} -@@ -6474,8 +6582,18 @@ validation fails, then file @file{foo} cannot be opened. This failure +@@ -6474,8 +6772,18 @@ validation fails, then file @file{foo} cannot be opened. This failure may halt or otherwise impact the boot process. An initial trusted public key can be embedded within the GRUB @file{core.img} @@ -1604,7 +1893,7 @@ index a225f9a88..096a3cde0 100644 GRUB uses GPG-style detached signatures (meaning that a file @file{foo.sig} will be produced when file @file{foo} is signed), and -@@ -6495,8 +6613,8 @@ gpg --detach-sign /path/to/file +@@ -6495,8 +6803,8 @@ gpg --detach-sign /path/to/file For successful validation of all of GRUB's subcomponents and the loaded OS kernel, they must all be signed. One way to accomplish this is the following (after having already produced the desired @@ -1615,7 +1904,7 @@ index a225f9a88..096a3cde0 100644 @example @group -@@ -6518,7 +6636,7 @@ See also: @ref{check_signatures}, @ref{verify_detached}, @ref{trust}, +@@ -6518,7 +6826,7 @@ See also: @ref{check_signatures}, @ref{verify_detached}, @ref{trust}, Note that internally signature enforcement is controlled by setting the environment variable @code{check_signatures} equal to @code{enforce}. Passing one or more @code{--pubkey} options to @@ -1624,7 +1913,7 @@ index a225f9a88..096a3cde0 100644 equal to @code{enforce} in @file{core.img} prior to processing any configuration files. -@@ -6538,6 +6656,86 @@ or BIOS) configuration to cause the machine to boot from a different +@@ -6538,6 +6846,86 @@ or BIOS) configuration to cause the machine to boot from a different (attacker-controlled) device. GRUB is at best only one link in a secure boot chain. @@ -1711,7 +2000,7 @@ index a225f9a88..096a3cde0 100644 @node UEFI secure boot and shim @section UEFI secure boot and shim support -@@ -6566,7 +6764,7 @@ UTF-8 strings as comma-separated values (CSV). See +@@ -6566,7 +6954,7 @@ UTF-8 strings as comma-separated values (CSV). See @uref{https://github.com/rhboot/shim/blob/main/SBAT.md} for more details. To add a data section containing the SBAT information into the binary, the @@ -1720,7 +2009,7 @@ index a225f9a88..096a3cde0 100644 of a CSV file, encoded with UTF-8, is copied as is to the .sbat data section into the generated EFI binary. The CSV file can be stored anywhere on the file system. -@@ -6616,12 +6814,73 @@ platforms. +@@ -6616,12 +7004,102 @@ platforms. @section Lockdown when booting on a secure setup The GRUB can be locked down when booted on a secure boot environment, for example @@ -1792,11 +2081,48 @@ index a225f9a88..096a3cde0 100644 +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 -@@ -6977,10 +7236,10 @@ Required files are: +@@ -6672,6 +7150,7 @@ USB support provides benefits similar to ATA (for USB disks) or AT (for USB + keyboards). In addition it allows USBserial. + + Chainloading refers to the ability to load another bootloader through the same protocol ++and on some platforms, like EFI, allow that bootloader to return to the GRUB. + + Hints allow faster disk discovery by already knowing in advance which is the disk in + question. On some platforms hints are correct unless you move the disk between boots. +@@ -6977,10 +7456,10 @@ Required files are: GRUB's normal start-up procedure involves setting the @samp{prefix} environment variable to a value set in the core image by @@ -1809,7 +2135,7 @@ index a225f9a88..096a3cde0 100644 things GRUB is supposed to do. If, instead, you only get a rescue shell, this usually means that GRUB -@@ -7006,8 +7265,8 @@ normal +@@ -7006,8 +7485,8 @@ normal However, any problem that leaves you in the rescue shell probably means that GRUB was not correctly installed. It may be more useful to try to reinstall @@ -1820,7 +2146,7 @@ index a225f9a88..096a3cde0 100644 @itemize @bullet{} @item -@@ -7019,7 +7278,7 @@ is usually better to use UUIDs or file system labels and avoid depending on +@@ -7019,7 +7498,7 @@ is usually better to use UUIDs or file system labels and avoid depending on drive ordering entirely. @item @@ -1829,7 +2155,7 @@ index a225f9a88..096a3cde0 100644 to a partition but GRUB has already been installed in the master boot record, then the GRUB installation in the partition will be ignored. -@@ -7054,33 +7313,40 @@ bootability on other machines. +@@ -7054,33 +7533,40 @@ bootability on other machines. @chapter User-space utilities @menu @@ -1884,7 +2210,7 @@ index a225f9a88..096a3cde0 100644 @table @option @item --help -@@ -7096,13 +7362,13 @@ separate partition or a removable disk. +@@ -7096,13 +7582,13 @@ separate partition or a removable disk. If this option is not specified then it defaults to @file{/boot}, so @example @@ -1900,7 +2226,7 @@ index a225f9a88..096a3cde0 100644 @end example Here is an example in which you have a separate @dfn{boot} partition which is -@@ -7110,16 +7376,16 @@ mounted on +@@ -7110,16 +7596,16 @@ mounted on @file{/mnt/boot}: @example @@ -1920,7 +2246,7 @@ index a225f9a88..096a3cde0 100644 extra space in the bootloader embedding area for Reed-Solomon error-correcting codes. This enables GRUB to still boot successfully if some blocks are corrupted. The exact amount of protection offered -@@ -7132,17 +7398,17 @@ installation}) where GRUB does not reside in any unpartitioned space +@@ -7132,17 +7618,17 @@ installation}) where GRUB does not reside in any unpartitioned space outside of the MBR. Disable the Reed-Solomon codes with this option. @end table @@ -1943,7 +2269,7 @@ index a225f9a88..096a3cde0 100644 @table @option @item --help -@@ -7158,17 +7424,17 @@ it to standard output. +@@ -7158,17 +7644,17 @@ it to standard output. @end table @@ -1966,7 +2292,7 @@ index a225f9a88..096a3cde0 100644 @table @option @item -c @var{number} -@@ -7186,23 +7452,23 @@ Length of the salt. Defaults to 64. +@@ -7186,23 +7672,23 @@ Length of the salt. Defaults to 64. @end table @@ -1996,7 +2322,7 @@ index a225f9a88..096a3cde0 100644 @table @option @item --help -@@ -7213,17 +7479,17 @@ Print the version number of GRUB and exit. +@@ -7213,17 +7699,17 @@ Print the version number of GRUB and exit. @end table @@ -2019,7 +2345,7 @@ index a225f9a88..096a3cde0 100644 passed on directly to @command{xorriso} in @command{mkisofs} emulation mode. Options passed to @command{xorriso} will normally be interpreted as @command{mkisofs} options; if the option @samp{--} is used, then anything -@@ -7235,10 +7501,10 @@ commonly used to add extra files to the image: +@@ -7235,10 +7721,10 @@ commonly used to add extra files to the image: @example mkdir -p disk/boot/grub @r{(add extra files to @file{disk/boot/grub})} @@ -2032,7 +2358,7 @@ index a225f9a88..096a3cde0 100644 @table @option @item --help -@@ -7266,15 +7532,15 @@ Use @var{file} as the @command{xorriso} program, rather than the built-in +@@ -7266,15 +7752,15 @@ Use @var{file} as the @command{xorriso} program, rather than the built-in default. @item --grub-mkimage=@var{file} @@ -2052,7 +2378,7 @@ index a225f9a88..096a3cde0 100644 system or file system image that GRUB understands, using GRUB's file system drivers via FUSE. (It is only available if FUSE development files were present when GRUB was built.) This has a number of uses: -@@ -7306,13 +7572,13 @@ even if nobody has yet written a FUSE module specifically for that file +@@ -7306,13 +7792,13 @@ even if nobody has yet written a FUSE module specifically for that file system type. @end itemize @@ -2069,7 +2395,7 @@ index a225f9a88..096a3cde0 100644 non-option arguments (if it is given more than one image, it will treat them as a RAID set), and also accepts the following options: -@@ -7334,13 +7600,13 @@ Show debugging output for conditions matching @var{string}. +@@ -7334,13 +7820,13 @@ Show debugging output for conditions matching @var{string}. @item -K prompt|@var{file} @itemx --zfs-key=prompt|@var{file} Load a ZFS encryption key. If you use @samp{prompt} as the argument, @@ -2085,7 +2411,7 @@ index a225f9a88..096a3cde0 100644 root of the supplied file system. If @var{device} is just a number, then it will be treated as a partition -@@ -7349,7 +7615,7 @@ an entire disk in @file{disk.img}, then you can use this command to mount +@@ -7349,7 +7835,7 @@ an entire disk in @file{disk.img}, then you can use this command to mount its second partition: @example @@ -2094,7 +2420,7 @@ index a225f9a88..096a3cde0 100644 @end example @item -v -@@ -7358,18 +7624,18 @@ Print verbose messages. +@@ -7358,18 +7844,18 @@ Print verbose messages. @end table @@ -2119,7 +2445,7 @@ index a225f9a88..096a3cde0 100644 argument, and also accepts the following options: @table @option -@@ -7382,16 +7648,16 @@ Print the version number of GRUB and exit. +@@ -7382,16 +7868,16 @@ Print the version number of GRUB and exit. @item -d @itemx --device If this option is given, then the non-option argument is a system device @@ -2139,7 +2465,7 @@ index a225f9a88..096a3cde0 100644 @item -t @var{target} @itemx --target=@var{target} -@@ -7444,19 +7710,19 @@ Print verbose messages. +@@ -7444,19 +7930,19 @@ Print verbose messages. @end table @@ -2346,7 +2672,7 @@ index f18550c1c..aa172391f 100644 $(MOD_FILES): %.mod : genmod.sh moddep.lst %.module$(EXEEXT) build-grub-module-verifier$(BUILD_EXEEXT) TARGET_OBJ2ELF=@TARGET_OBJ2ELF@ sh $^ $@ diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def -index 1571421d7..6ff483534 100644 +index 1571421d7..a545ee430 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -99,7 +99,7 @@ kernel = { @@ -2395,7 +2721,7 @@ index 1571421d7..6ff483534 100644 sparc64_ieee1275 = kern/sparc64/cache.S; sparc64_ieee1275 = kern/sparc64/dl.c; -@@ -363,6 +370,8 @@ kernel = { +@@ -363,10 +370,15 @@ kernel = { riscv64 = kern/riscv/cache_flush.S; riscv64 = kern/riscv/dl.c; @@ -2404,7 +2730,14 @@ index 1571421d7..6ff483534 100644 emu = disk/host.c; emu = kern/emu/cache_s.S; emu = kern/emu/hostdisk.c; -@@ -409,6 +418,11 @@ kernel = { + emu = osdep/unix/hostdisk.c; ++ emu = osdep/relpath.c; ++ emu = osdep/getroot.c; ++ emu = osdep/unix/getroot.c; + emu = osdep/exec.c; + extra_dist = osdep/unix/exec.c; + emu = osdep/devmapper/hostdisk.c; +@@ -409,6 +421,11 @@ kernel = { extra_dist = kern/mips/cache_flush.S; }; @@ -2416,7 +2749,7 @@ index 1571421d7..6ff483534 100644 program = { name = grub-emu; mansection = 1; -@@ -590,6 +604,11 @@ image = { +@@ -590,6 +607,11 @@ image = { enable = mips_loongson; }; @@ -2428,7 +2761,7 @@ index 1571421d7..6ff483534 100644 module = { name = disk; common = lib/disk.c; -@@ -824,6 +843,12 @@ module = { +@@ -824,6 +846,12 @@ module = { enable = efi; }; @@ -2441,7 +2774,7 @@ index 1571421d7..6ff483534 100644 module = { name = efifwsetup; efi = commands/efi/efifwsetup.c; -@@ -836,11 +861,27 @@ module = { +@@ -836,11 +864,39 @@ module = { enable = efi; }; @@ -2464,12 +2797,24 @@ index 1571421d7..6ff483534 100644 + enable = efi; + enable = i386_pc; + enable = emu; ++ enable = xen; ++ enable = i386_xen_pvh; ++}; ++ ++module = { ++ name = blsuki; ++ common = commands/blsuki.c; ++ common = lib/gnulib/filevercmp.c; ++ enable = powerpc_ieee1275; ++ enable = efi; ++ cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)'; ++ cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB)'; +}; + module = { name = boot; common = commands/boot.c; -@@ -975,6 +1016,18 @@ module = { +@@ -975,6 +1031,18 @@ module = { cppflags = '-I$(srcdir)/lib/posix_wrap'; }; @@ -2488,7 +2833,7 @@ index 1571421d7..6ff483534 100644 module = { name = hdparm; common = commands/hdparm.c; -@@ -1008,6 +1061,7 @@ module = { +@@ -1008,6 +1076,7 @@ module = { module = { name = loadenv; common = commands/loadenv.c; @@ -2496,7 +2841,7 @@ index 1571421d7..6ff483534 100644 common = lib/envblk.c; }; -@@ -1777,12 +1831,6 @@ module = { +@@ -1777,12 +1846,6 @@ module = { }; @@ -2509,7 +2854,7 @@ index 1571421d7..6ff483534 100644 module = { name = ntldr; i386_pc = loader/i386/pc/ntldr.c; -@@ -1838,10 +1886,9 @@ module = { +@@ -1838,10 +1901,9 @@ module = { module = { name = linux; @@ -2521,7 +2866,7 @@ index 1571421d7..6ff483534 100644 i386_xen_pvh = lib/i386/pc/vesa_modes_table.c; mips = loader/mips/linux.c; powerpc_ieee1275 = loader/powerpc/ieee1275/linux.c; -@@ -1854,8 +1901,12 @@ module = { +@@ -1854,8 +1916,12 @@ module = { loongarch64 = loader/efi/linux.c; riscv32 = loader/efi/linux.c; riscv64 = loader/efi/linux.c; @@ -2534,7 +2879,7 @@ index 1571421d7..6ff483534 100644 emu = loader/emu/linux.c; common = loader/linux.c; common = lib/cmdline.c; -@@ -1864,7 +1915,6 @@ module = { +@@ -1864,7 +1930,6 @@ module = { module = { name = fdt; efi = loader/efi/fdt.c; @@ -2542,7 +2887,7 @@ index 1571421d7..6ff483534 100644 enable = fdt; }; -@@ -2165,6 +2215,12 @@ module = { +@@ -2165,6 +2230,12 @@ module = { common = tests/setjmp_test.c; }; @@ -2555,7 +2900,7 @@ index 1571421d7..6ff483534 100644 module = { name = signature_test; common = tests/signature_test.c; -@@ -2338,6 +2394,12 @@ module = { +@@ -2338,6 +2409,12 @@ module = { common = hook/datehook.c; }; @@ -2568,7 +2913,7 @@ index 1571421d7..6ff483534 100644 module = { name = net; common = net/net.c; -@@ -2351,6 +2413,12 @@ module = { +@@ -2351,6 +2428,12 @@ module = { common = net/ethernet.c; common = net/arp.c; common = net/netbuff.c; @@ -2581,7 +2926,7 @@ index 1571421d7..6ff483534 100644 }; module = { -@@ -2392,6 +2460,7 @@ module = { +@@ -2392,6 +2475,7 @@ module = { common = commands/legacycfg.c; common = lib/legacy_parse.c; emu = lib/i386/pc/vesa_modes_table.c; @@ -2589,7 +2934,7 @@ index 1571421d7..6ff483534 100644 i386_efi = lib/i386/pc/vesa_modes_table.c; x86_64_efi = lib/i386/pc/vesa_modes_table.c; xen = lib/i386/pc/vesa_modes_table.c; -@@ -2440,15 +2509,12 @@ module = { +@@ -2440,15 +2524,12 @@ module = { module = { name = backtrace; @@ -2607,7 +2952,7 @@ index 1571421d7..6ff483534 100644 }; module = { -@@ -2525,6 +2591,14 @@ module = { +@@ -2525,6 +2606,14 @@ module = { cppflags = '$(CPPFLAGS_GCRY)'; }; @@ -2622,7 +2967,7 @@ index 1571421d7..6ff483534 100644 module = { name = all_video; common = lib/fake_module.c; -@@ -2594,4 +2668,33 @@ module = { +@@ -2594,4 +2683,33 @@ module = { name = bli; efi = commands/bli.c; enable = efi; @@ -2656,6 +3001,19 @@ index 1571421d7..6ff483534 100644 + common = lib/libtasn1_wrap/tests/Test_strings.c; + common = lib/libtasn1_wrap/wrap_tests.c; }; +diff --git a/grub-core/bus/usb/ehci.c b/grub-core/bus/usb/ehci.c +index 9abebc6bd..2db07c7c0 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/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c new file mode 100644 index 000000000..1b8a80780 @@ -5547,12 +5905,55 @@ index 825a8800e..8b5ec3913 100644 return 0; } +diff --git a/grub-core/commands/bli.c b/grub-core/commands/bli.c +index e0d8a54f7..298c5f70a 100644 +--- a/grub-core/commands/bli.c ++++ b/grub-core/commands/bli.c +@@ -48,6 +48,22 @@ get_part_uuid (const char *device_name, char **part_uuid) + if (device == NULL) + return grub_error (grub_errno, N_("cannot open device: %s"), device_name); + ++ if (device->disk == NULL) ++ { ++ grub_dprintf ("bli", "%s is not a disk device, partuuid skipped\n", device_name); ++ *part_uuid = NULL; ++ grub_device_close (device); ++ return GRUB_ERR_NONE; ++ } ++ ++ if (device->disk->partition == NULL) ++ { ++ grub_dprintf ("bli", "%s has no partition, partuuid skipped\n", device_name); ++ *part_uuid = NULL; ++ grub_device_close (device); ++ return GRUB_ERR_NONE; ++ } ++ + disk = grub_disk_open (device->disk->name); + if (disk == NULL) + { +@@ -99,7 +115,7 @@ set_loader_device_part_uuid (void) + + status = get_part_uuid (device_name, &part_uuid); + +- if (status == GRUB_ERR_NONE) ++ if (status == GRUB_ERR_NONE && part_uuid) + status = grub_efi_set_variable_to_string ("LoaderDevicePartUUID", &bli_vendor_guid, part_uuid, + GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS | + GRUB_EFI_VARIABLE_RUNTIME_ACCESS); +@@ -117,4 +133,6 @@ GRUB_MOD_INIT (bli) + GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS | + GRUB_EFI_VARIABLE_RUNTIME_ACCESS); + set_loader_device_part_uuid (); ++ /* No error here is critical, other than being logged */ ++ grub_print_error (); + } diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c new file mode 100644 -index 000000000..6e398fc17 +index 000000000..38913d696 --- /dev/null +++ b/grub-core/commands/blscfg.c -@@ -0,0 +1,1221 @@ +@@ -0,0 +1,1222 @@ +/*-*- Mode: C; c-basic-offset: 2; indent-tabs-mode: t -*-*/ + +/* bls.c - implementation of the boot loader spec */ @@ -6250,7 +6651,8 @@ index 000000000..6e398fc17 + return NULL; + + while (*value) { -+ if (*value == '$') { ++ /* It's a variable only when *value is '$' and it is not escaped with '\'*/ ++ if (*value == '$' && *end != '\\') { + if (start != end) { + buffer = field_append(is_var, buffer, start, end); + if (!buffer) @@ -6509,7 +6911,7 @@ index 000000000..6e398fc17 + clinux, options ? " " : "", options ? options : "", + initrd ? initrd : "", dt ? dt : ""); + -+ grub_normal_add_menu_entry (argc, argv, classes, id, users, hotkey, NULL, src, 0, &index, entry); ++ grub_normal_add_menu_entry (argc, argv, classes, id, users, hotkey, NULL, src, 0, &index, entry, NULL); + grub_dprintf ("blscfg", "Added entry %d id:\"%s\"\n", index, id); + +finish: @@ -6774,6 +7176,1503 @@ index 000000000..6e398fc17 + grub_unregister_extcmd (cmd); + grub_unregister_extcmd (oldcmd); +} +diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c +new file mode 100644 +index 000000000..bcd0114d8 +--- /dev/null ++++ b/grub-core/commands/blsuki.c +@@ -0,0 +1,1491 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2025 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef GRUB_MACHINE_EFI ++#include ++#include ++#include ++#endif ++ ++#ifdef GRUB_MACHINE_EMU ++#include ++#define GRUB_BOOT_DEVICE "/boot" ++#else ++#define GRUB_BOOT_DEVICE "" ++#endif ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++#define GRUB_BLS_CONFIG_PATH "/loader/entries/" ++#define GRUB_UKI_CONFIG_PATH "/EFI/Linux" ++ ++#define BLS_EXT_LEN (sizeof (".conf") - 1) ++#define UKI_EXT_LEN (sizeof (".efi") - 1) ++ ++/* ++ * It is highly unlikely to ever receive a large amount of keyval pairs. A ++ * limit of 10000 is more than enough. ++ */ ++#define BLSUKI_KEYVALS_MAX 10000 ++/* ++ * The only sections we read are ".cmdline" and ".osrel". The ".cmdline" ++ * section has a size limit of 4096 and it would be very unlikely for the size ++ * of the ".osrel" section to be 5 times larger than 4096. ++ */ ++#define UKI_SECTION_SIZE_MAX (5 * 4096) ++ ++enum blsuki_cmd_type ++ { ++ BLSUKI_BLS_CMD, ++ BLSUKI_UKI_CMD, ++ }; ++ ++static const struct grub_arg_option bls_opt[] = ++ { ++ {"path", 'p', 0, "Specify path to find BLS entries.", N_("DIR"), ARG_TYPE_PATHNAME}, ++ {"enable-fallback", 'f', 0, "Fallback to the default BLS path if --path fails to find BLS entries.", 0, ARG_TYPE_NONE}, ++ {"show-default", 'd', 0, "Allow the default BLS entry to be added to the GRUB menu.", 0, ARG_TYPE_NONE}, ++ {"show-non-default", 'n', 0, "Allow the non-default BLS entries to be added to the GRUB menu.", 0, ARG_TYPE_NONE}, ++ {"entry", 'e', 0, "Allow specific BLS entries to be added to the GRUB menu.", N_("FILE"), ARG_TYPE_FILE}, ++ {0, 0, 0, 0, 0, 0} ++ }; ++ ++#ifdef GRUB_MACHINE_EFI ++static const struct grub_arg_option uki_opt[] = ++ { ++ {"path", 'p', 0, N_("Specify path to find UKI entries."), N_("DIR"), ARG_TYPE_PATHNAME}, ++ {"enable-fallback", 'f', 0, "Fallback to the default BLS path if --path fails to find UKI entries.", 0, ARG_TYPE_NONE}, ++ {"show-default", 'd', 0, N_("Allow the default UKI entry to be added to the GRUB menu."), 0, ARG_TYPE_NONE}, ++ {"show-non-default", 'n', 0, N_("Allow the non-default UKI entries to be added to the GRUB menu."), 0, ARG_TYPE_NONE}, ++ {"entry", 'e', 0, N_("Allow specificUKII entries to be added to the GRUB menu."), N_("FILE"), ARG_TYPE_FILE}, ++ {0, 0, 0, 0, 0, 0} ++ }; ++#endif ++ ++struct keyval ++{ ++ const char *key; ++ char *val; ++}; ++ ++struct read_entry_info ++{ ++ const char *devid; ++ const char *dirname; ++ enum blsuki_cmd_type cmd_type; ++ grub_file_t file; ++}; ++ ++struct find_entry_info ++{ ++ const char *dirname; ++ const char *devid; ++ grub_device_t dev; ++ grub_fs_t fs; ++}; ++ ++static grub_blsuki_entry_t *entries = NULL; ++ ++#define FOR_BLSUKI_ENTRIES(var) FOR_LIST_ELEMENTS (var, entries) ++ ++/* ++ * BLS appears to make paths relative to the filesystem that snippets are ++ * on, not /. Attempt to cope. ++ */ ++static char *blsuki_update_boot_device (char *tmp) ++{ ++#ifdef GRUB_MACHINE_EMU ++ static int separate_boot = -1; ++ char *ret; ++ ++ if (separate_boot != -1) ++ goto probed; ++ ++ separate_boot = 0; ++ ++ ret = grub_make_system_path_relative_to_its_root (GRUB_BOOT_DEVICE); ++ ++ if (ret != NULL && ret[0] == '\0') ++ separate_boot = 1; ++ ++ probed: ++ if (separate_boot == 0) ++ return tmp; ++#endif ++ ++ return grub_stpcpy (tmp, GRUB_BOOT_DEVICE); ++} ++ ++/* ++ * This function will add a new keyval pair to a list of keyvals stored in the ++ * entry parameter. ++ */ ++static grub_err_t ++blsuki_add_keyval (grub_blsuki_entry_t *entry, char *key, char *val) ++{ ++ char *k, *v; ++ struct keyval **kvs, *kv; ++ grub_size_t size; ++ int new_n = entry->nkeyvals + 1; ++ ++ if (new_n > BLSUKI_KEYVALS_MAX) ++ return grub_error (GRUB_ERR_BAD_NUMBER, "too many keyval pairs"); ++ ++ if (entry->keyvals_size == 0) ++ { ++ size = sizeof (struct keyval *); ++ kvs = grub_malloc (size); ++ if (kvs == NULL) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't allocate space for BLS key values"); ++ ++ entry->keyvals = kvs; ++ entry->keyvals_size = size; ++ } ++ else if (entry->keyvals_size < new_n * sizeof (struct keyval *)) ++ { ++ size = entry->keyvals_size * 2; ++ kvs = grub_realloc (entry->keyvals, size); ++ if (kvs == NULL) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't reallocate space for BLS key values"); ++ ++ entry->keyvals = kvs; ++ entry->keyvals_size = size; ++ } ++ ++ kv = grub_malloc (sizeof (struct keyval)); ++ if (kv == NULL) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't find space for new BLS key value"); ++ ++ k = grub_strdup (key); ++ if (k == NULL) ++ { ++ grub_free (kv); ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't find space for new BLS key value"); ++ } ++ ++ v = grub_strdup (val); ++ if (v == NULL) ++ { ++ grub_free (k); ++ grub_free (kv); ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't find space for new BLS key value"); ++ } ++ ++ kv->key = k; ++ kv->val = v; ++ entry->keyvals[entry->nkeyvals] = kv; ++ entry->nkeyvals = new_n; ++ ++ return GRUB_ERR_NONE; ++} ++ ++/* ++ * Find the value of the key named by keyname. If there are allowed to be ++ * more than one, pass a pointer set to -1 to the last parameter the first ++ * time, and pass the same pointer through each time after, and it'll return ++ * them in sorted order. ++ */ ++static char * ++blsuki_get_val (grub_blsuki_entry_t *entry, const char *keyname, int *last) ++{ ++ int idx, start = (last != NULL) ? (*last + 1) : 0; ++ struct keyval *kv = NULL; ++ char *ret = NULL; ++ ++ for (idx = start; idx < entry->nkeyvals; idx++) ++ { ++ kv = entry->keyvals[idx]; ++ ++ if (grub_strcmp (keyname, kv->key) == 0) ++ { ++ ret = kv->val; ++ break; ++ } ++ } ++ ++ if (last != NULL) ++ { ++ if (idx == entry->nkeyvals) ++ *last = -1; ++ else ++ *last = idx; ++ } ++ ++ return ret; ++} ++ ++/* ++ * Add a new grub_blsuki_entry_t struct to the entries list and sort it's ++ * position on the list. ++ */ ++static grub_err_t ++blsuki_add_entry (grub_blsuki_entry_t *entry) ++{ ++ grub_blsuki_entry_t *e, *last = NULL; ++ int rc; ++ ++ if (entries == NULL) ++ { ++ grub_dprintf ("blsuki", "Add entry with id \"%s\"\n", entry->filename); ++ entries = entry; ++ return GRUB_ERR_NONE; ++ } ++ ++ FOR_BLSUKI_ENTRIES (e) ++ { ++ rc = filevercmp (entry->filename, e->filename); ++ if (rc == 0) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("duplicate file: `%s'"), entry->filename); ++ ++ if (rc > 0) ++ { ++ grub_dprintf ("blsuki", "Add entry with id \"%s\"\n", entry->filename); ++ grub_list_push (GRUB_AS_LIST_P (&e), GRUB_AS_LIST (entry)); ++ if (entry->next == entries) ++ { ++ entries = entry; ++ entry->prev = NULL; ++ } ++ else if (last != NULL) ++ last->next = entry; ++ ++ return GRUB_ERR_NONE; ++ } ++ last = e; ++ } ++ ++ if (last != NULL) ++ { ++ grub_dprintf ("blsuki", "Add entry with id \"%s\"\n", entry->filename); ++ last->next = entry; ++ entry->prev = &last; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++/* ++ * This function parses each line of a BLS config file to obtain the key value ++ * pairs that will be used to setup the GRUB menu entries. The key value pair ++ * will be stored in a list in the entry parameter. ++ */ ++static grub_err_t ++bls_parse_keyvals (grub_file_t f, grub_blsuki_entry_t *entry) ++{ ++ grub_err_t err = GRUB_ERR_NONE; ++ ++ for (;;) ++ { ++ char *line, *key, *val; ++ ++ line = grub_file_getline (f); ++ if (line == NULL) ++ break; ++ ++ key = grub_strtok_r (line, " \t", &val); ++ if (key == NULL) ++ { ++ grub_free (line); ++ break; ++ } ++ if (*key == '#') ++ { ++ grub_free (line); ++ continue; ++ } ++ ++ while (*val == ' ' || *val == '\t') ++ val++; ++ ++ if (*val == '\0') ++ { ++ grub_free (line); ++ break; ++ } ++ ++ err = blsuki_add_keyval (entry, key, val); ++ grub_free (line); ++ if (err != GRUB_ERR_NONE) ++ break; ++ } ++ ++ return err; ++} ++ ++#ifdef GRUB_MACHINE_EFI ++/* ++ * This function searches for the .cmdline, .osrel, and .linux sections of a ++ * UKI. We only need to store the data for the .cmdline and .osrel sections, ++ * but we also need to verify that the .linux section exists. ++ */ ++static grub_err_t ++uki_parse_keyvals (grub_file_t f, grub_blsuki_entry_t *entry) ++{ ++ struct grub_msdos_image_header *dos = NULL; ++ struct grub_pe_image_header *pe = NULL; ++ grub_off_t section_offset = 0; ++ struct grub_pe32_section_table *section = NULL; ++ struct grub_pe32_coff_header *coff_header = NULL; ++ char *val = NULL; ++ char *key = NULL; ++ const char *target[] = {".cmdline", ".osrel", ".linux", NULL}; ++ bool has_linux = false; ++ grub_err_t err = GRUB_ERR_NONE; ++ ++ dos = grub_zalloc (sizeof (*dos)); ++ if (dos == NULL) ++ return grub_errno; ++ if (grub_file_read (f, dos, sizeof (*dos)) < (grub_ssize_t) sizeof (*dos)) ++ { ++ err = grub_error (GRUB_ERR_FILE_READ_ERROR, "failed to read UKI image header"); ++ goto finish; ++ } ++ if (dos->msdos_magic != GRUB_DOS_MAGIC) ++ { ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "plain image kernel is not supported"); ++ goto finish; ++ } ++ ++ grub_dprintf ("blsuki", "PE/COFF header @ %08x\n", dos->pe_image_header_offset); ++ pe = grub_zalloc (sizeof (*pe)); ++ if (pe == NULL) ++ { ++ err = grub_errno; ++ goto finish; ++ } ++ if (grub_file_seek (f, dos->pe_image_header_offset) == (grub_off_t) -1 || ++ grub_file_read (f, pe, sizeof (*pe)) != sizeof (*pe)) ++ { ++ err = grub_error (GRUB_ERR_FILE_READ_ERROR, "failed to read COFF image header"); ++ goto finish; ++ } ++ if (pe->optional_header.magic != GRUB_PE32_NATIVE_MAGIC) ++ { ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "non-native image not supported"); ++ goto finish; ++ } ++ ++ coff_header = &(pe->coff_header); ++ section_offset = dos->pe_image_header_offset + sizeof (*pe); ++ ++ for (int i = 0; i < coff_header->num_sections; i++) ++ { ++ section = grub_zalloc (sizeof (*section)); ++ if (section == NULL) ++ { ++ err = grub_errno; ++ goto finish; ++ } ++ ++ if (grub_file_seek (f, section_offset) == (grub_off_t) -1 || ++ grub_file_read (f, section, sizeof (*section)) != sizeof (*section)) ++ { ++ err = grub_error (GRUB_ERR_FILE_READ_ERROR, "failed to read section header"); ++ goto finish; ++ } ++ ++ key = grub_strndup (section->name, 8); ++ if (key == NULL) ++ { ++ err = grub_errno; ++ goto finish; ++ } ++ ++ for (int j = 0; target[j] != NULL; j++) ++ { ++ if (grub_strcmp (key, target[j]) == 0) ++ { ++ /* ++ * We don't need to read the contents of the .linux PE section, but we ++ * should verify that the section exists. ++ */ ++ if (grub_strcmp (key, ".linux") == 0) ++ { ++ has_linux = true; ++ break; ++ } ++ ++ if (section->raw_data_size > UKI_SECTION_SIZE_MAX) ++ { ++ err = grub_error (GRUB_ERR_BAD_NUMBER, "UKI section size is larger than expected"); ++ goto finish; ++ } ++ ++ val = grub_zalloc (section->raw_data_size); ++ if (val == NULL) ++ { ++ err = grub_errno; ++ goto finish; ++ } ++ ++ if (grub_file_seek (f, section->raw_data_offset) == (grub_off_t) -1 || ++ grub_file_read (f, val, section->raw_data_size) != (grub_ssize_t) section->raw_data_size) ++ { ++ err = grub_error (GRUB_ERR_FILE_READ_ERROR, "failed to read section"); ++ goto finish; ++ } ++ ++ err = blsuki_add_keyval (entry, key, val); ++ if (err != GRUB_ERR_NONE) ++ goto finish; ++ ++ break; ++ } ++ } ++ ++ section_offset += sizeof (*section); ++ grub_free (section); ++ grub_free (val); ++ grub_free (key); ++ section = NULL; ++ val = NULL; ++ key = NULL; ++ } ++ ++ if (has_linux == false) ++ err = grub_error (GRUB_ERR_NO_KERNEL, "UKI is missing the '.linux' section"); ++ ++ finish: ++ grub_free (dos); ++ grub_free (pe); ++ grub_free (section); ++ grub_free (val); ++ grub_free (key); ++ return err; ++} ++ ++/* ++ * This function obtains the keyval pairs when the .osrel data is input into ++ * the osrel_ptr parameter and returns the keyval pair. Since we are using ++ * grub_strtok_r(), the osrel_ptr will be updated to the following line of ++ * osrel. This function returns NULL when it reaches the end of osrel. ++ */ ++static char * ++uki_read_osrel (char **osrel_ptr, char **val_ret) ++{ ++ char *key, *val; ++ grub_size_t val_size; ++ ++ for (;;) ++ { ++ key = grub_strtok_r (NULL, "\n\r", osrel_ptr); ++ if (key == NULL) ++ return NULL; ++ ++ /* Remove leading white space */ ++ while (*key == ' ' || *key == '\t') ++ key++; ++ ++ /* Skip commented lines */ ++ if (*key == '#') ++ continue; ++ ++ /* Split key/value */ ++ key = grub_strtok_r (key, "=", &val); ++ if (key == NULL || *val == '\0') ++ continue; ++ ++ /* Remove quotes from value */ ++ val_size = grub_strlen (val); ++ if ((*val == '\"' && val[val_size - 1] == '\"') || ++ (*val == '\'' && val[val_size - 1] == '\'')) ++ { ++ val[val_size - 1] = '\0'; ++ val++; ++ } ++ ++ *val_ret = val; ++ break; ++ } ++ ++ return key; ++} ++#endif ++ ++/* ++ * If a file hasn't already been opened, this function opens a BLS config file ++ * or UKI and initializes entry data before parsing keyvals and adding the entry ++ * to the list of BLS or UKI entries. ++ */ ++static int ++blsuki_read_entry (const char *filename, ++ const struct grub_dirhook_info *dirhook_info __attribute__ ((__unused__)), ++ void *data) ++{ ++ grub_size_t path_len = 0, ext_len = 0, filename_len; ++ grub_err_t err = GRUB_ERR_NONE; ++ char *p = NULL; ++ const char *ext = NULL; ++ grub_file_t f = NULL; ++ enum grub_file_type file_type = 0; ++ grub_blsuki_entry_t *entry; ++ struct read_entry_info *info = (struct read_entry_info *) data; ++ ++ grub_dprintf ("blsuki", "filename: \"%s\"\n", filename); ++ ++ filename_len = grub_strlen (filename); ++ ++ if (info->cmd_type == BLSUKI_BLS_CMD) ++ { ++ ext = ".conf"; ++ ext_len = BLS_EXT_LEN; ++ file_type = GRUB_FILE_TYPE_CONFIG; ++ } ++#ifdef GRUB_MACHINE_EFI ++ else if (info->cmd_type == BLSUKI_UKI_CMD) ++ { ++ ext = ".efi"; ++ ext_len = UKI_EXT_LEN; ++ file_type = GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE; ++ } ++#endif ++ ++ if (info->file != NULL) ++ f = info->file; ++ else ++ { ++ if (filename_len < ext_len || ++ grub_strcmp (filename + filename_len - ext_len, ext) != 0) ++ return 0; ++ ++ p = grub_xasprintf ("(%s)%s/%s", info->devid, info->dirname, filename); ++ f = grub_file_open (p, file_type); ++ grub_free (p); ++ if (f == NULL) ++ goto finish; ++ } ++ ++ entry = grub_zalloc (sizeof (*entry)); ++ if (entry == NULL) ++ goto finish; ++ ++ /* ++ * If a file is opened before this function, the filename may have a path. ++ * Since the filename is used for the ID of the GRUB menu entry, we can ++ * remove the path. ++ */ ++ if (info->file != NULL) ++ { ++ char *slash; ++ ++ slash = grub_strrchr (filename, '/'); ++ if (slash != NULL) ++ path_len = slash - filename + 1; ++ } ++ filename_len -= path_len; ++ ++ entry->filename = grub_strndup (filename + path_len, filename_len); ++ if (entry->filename == NULL) ++ { ++ grub_free (entry); ++ goto finish; ++ } ++ ++ entry->dirname = grub_strdup (info->dirname); ++ if (entry->dirname == NULL) ++ { ++ grub_free (entry); ++ goto finish; ++ } ++ ++ entry->devid = grub_strdup (info->devid); ++ if (entry->devid == NULL) ++ { ++ grub_free (entry); ++ goto finish; ++ } ++ ++ if (info->cmd_type == BLSUKI_BLS_CMD) ++ err = bls_parse_keyvals (f, entry); ++#ifdef GRUB_MACHINE_EFI ++ else if (info->cmd_type == BLSUKI_UKI_CMD) ++ err = uki_parse_keyvals (f, entry); ++#endif ++ ++ if (err == GRUB_ERR_NONE) ++ blsuki_add_entry (entry); ++ else ++ grub_free (entry); ++ ++ finish: ++ if (f != NULL) ++ grub_file_close (f); ++ ++ return 0; ++} ++ ++/* ++ * This function returns a list of values that had the same key in the BLS ++ * config file or UKI. The number of entries in this list is returned by the len ++ * parameter. ++ */ ++static char ** ++blsuki_make_list (grub_blsuki_entry_t *entry, const char *key, int *len) ++{ ++ int last = -1; ++ char *val; ++ int nlist = 0; ++ char **list; ++ ++ list = grub_zalloc (sizeof (char *)); ++ if (list == NULL) ++ return NULL; ++ ++ while (1) ++ { ++ char **new; ++ ++ /* ++ * Since the same key might appear more than once, the 'last' variable ++ * starts at -1 and increments to indicate the last index in the list ++ * we obtained from blsuki_get_val(). ++ */ ++ val = blsuki_get_val (entry, key, &last); ++ if (val == NULL) ++ break; ++ ++ new = grub_realloc (list, (nlist + 2) * sizeof (char *)); ++ if (new == NULL) ++ break; ++ ++ list = new; ++ list[nlist++] = val; ++ list[nlist] = NULL; ++ } ++ ++ if (nlist == 0) ++ { ++ grub_free (list); ++ return NULL; ++ } ++ ++ if (len != NULL) ++ *len = nlist; ++ ++ return list; ++} ++ ++/* ++ * This function appends a field to the end of a buffer. If the field given is ++ * an enviornmental variable, it gets the value stored for that variable and ++ * appends that to the buffer instead. ++ */ ++static char * ++blsuki_field_append (bool is_env_var, char *buffer, const char *start, const char *end) ++{ ++ char *tmp; ++ const char *field; ++ grub_size_t size = 0; ++ ++ tmp = grub_strndup (start, end - start + 1); ++ if (tmp == NULL) ++ return NULL; ++ ++ field = tmp; ++ ++ if (is_env_var == true) ++ { ++ field = grub_env_get (tmp); ++ if (field == NULL) ++ return buffer; ++ } ++ ++ if (grub_add (grub_strlen (field), 1, &size)) ++ return NULL; ++ ++ if (buffer == NULL) ++ buffer = grub_zalloc (size); ++ else ++ { ++ if (grub_add (size, grub_strlen (buffer), &size)) ++ return NULL; ++ ++ buffer = grub_realloc (buffer, size); ++ } ++ ++ if (buffer == NULL) ++ return NULL; ++ ++ tmp = buffer + grub_strlen (buffer); ++ tmp = grub_stpcpy (tmp, field); ++ ++ if (is_env_var == true) ++ tmp = grub_stpcpy (tmp, " "); ++ ++ return buffer; ++} ++ ++/* ++ * This function takes a value string, checks for environmental variables, and ++ * returns the value string with all environmental variables replaced with the ++ * value stored in the variable. ++ */ ++static char * ++blsuki_expand_val (const char *value) ++{ ++ char *buffer = NULL; ++ const char *start = value; ++ const char *end = value; ++ bool is_env_var = false; ++ ++ if (value == NULL) ++ return NULL; ++ ++ while (*value != '\0') ++ { ++ if (*value == '$') ++ { ++ if (start != end) ++ { ++ buffer = blsuki_field_append (is_env_var, buffer, start, end); ++ if (buffer == NULL) ++ return NULL; ++ } ++ ++ is_env_var = true; ++ start = value + 1; ++ } ++ else if (is_env_var == true) ++ { ++ if (grub_isalnum (*value) == 0 && *value != '_') ++ { ++ buffer = blsuki_field_append (is_env_var, buffer, start, end); ++ is_env_var = false; ++ start = value; ++ if (*start == ' ') ++ start++; ++ } ++ } ++ ++ end = value; ++ value++; ++ } ++ ++ if (start != end) ++ { ++ buffer = blsuki_field_append (is_env_var, buffer, start, end); ++ if (buffer == NULL) ++ return NULL; ++ } ++ ++ return buffer; ++} ++ ++/* ++ * This function returns a string with the command to load a linux kernel with ++ * kernel command-line options based on what was specified in the BLS config ++ * file. ++ */ ++static char * ++bls_get_linux (grub_blsuki_entry_t *entry) ++{ ++ char *linux_path; ++ char *linux_cmd = NULL; ++ char *options = NULL; ++ char *tmp; ++ grub_size_t size; ++ ++ linux_path = blsuki_get_val (entry, "linux", NULL); ++ options = blsuki_expand_val (blsuki_get_val (entry, "options", NULL)); ++ ++ if (grub_add (sizeof ("linux " GRUB_BOOT_DEVICE), grub_strlen (linux_path), &size)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while calculating linux buffer size"); ++ goto finish; ++ } ++ ++ if (options != NULL) ++ { ++ if (grub_add (size, grub_strlen (options), &size) || ++ grub_add (size, 1, &size)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while calculating linux buffer size"); ++ goto finish; ++ } ++ } ++ ++ linux_cmd = grub_malloc (size); ++ if (linux_cmd == NULL) ++ goto finish; ++ ++ tmp = linux_cmd; ++ tmp = grub_stpcpy (tmp, "linux "); ++ tmp = blsuki_update_boot_device (tmp); ++ tmp = grub_stpcpy (tmp, linux_path); ++ if (options != NULL) ++ { ++ tmp = grub_stpcpy (tmp, " "); ++ tmp = grub_stpcpy (tmp, options); ++ } ++ ++ tmp = grub_stpcpy (tmp, "\n"); ++ ++ finish: ++ grub_free (options); ++ return linux_cmd; ++} ++ ++/* ++ * This function returns a string with the command to load all initrds for a ++ * linux kernel image based on the list provided by the BLS config file. ++ */ ++static char * ++bls_get_initrd (grub_blsuki_entry_t *entry) ++{ ++ char **initrd_list; ++ char *initrd_cmd = NULL; ++ char *tmp; ++ grub_size_t size; ++ int i; ++ ++ initrd_list = blsuki_make_list (entry, "initrd", NULL); ++ if (initrd_list != NULL) ++ { ++ size = sizeof ("initrd"); ++ ++ for (i = 0; initrd_list != NULL && initrd_list[i] != NULL; i++) ++ { ++ if (grub_add (size, sizeof (" " GRUB_BOOT_DEVICE) - 1, &size) || ++ grub_add (size, grub_strlen (initrd_list[i]), &size)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected calculating initrd buffer size"); ++ goto finish; ++ } ++ } ++ ++ if (grub_add (size, 1, &size)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected calculating initrd buffer size"); ++ goto finish; ++ } ++ ++ initrd_cmd = grub_malloc (size); ++ if (initrd_cmd == NULL) ++ goto finish; ++ ++ tmp = grub_stpcpy (initrd_cmd, "initrd"); ++ for (i = 0; initrd_list != NULL && initrd_list[i] != NULL; i++) ++ { ++ grub_dprintf ("blsuki", "adding initrd %s\n", initrd_list[i]); ++ tmp = grub_stpcpy (tmp, " "); ++ tmp = blsuki_update_boot_device (tmp); ++ tmp = grub_stpcpy (tmp, initrd_list[i]); ++ } ++ tmp = grub_stpcpy (tmp, "\n"); ++ } ++ ++ finish: ++ grub_free (initrd_list); ++ return initrd_cmd; ++} ++ ++/* ++ * This function returns a string with the command to load a device tree blob ++ * from the BLS config file. ++ */ ++static char * ++bls_get_devicetree (grub_blsuki_entry_t *entry) ++{ ++ char *dt_path; ++ char *dt_cmd = NULL; ++ char *tmp; ++ grub_size_t size; ++ ++ dt_path = blsuki_expand_val (blsuki_get_val (entry, "devicetree", NULL)); ++ if (dt_path != NULL) ++ { ++ if (grub_add (sizeof ("devicetree " GRUB_BOOT_DEVICE), grub_strlen (dt_path), &size) || ++ grub_add (size, 1, &size)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected calculating device tree buffer size"); ++ return NULL; ++ } ++ ++ dt_cmd = grub_malloc (size); ++ if (dt_cmd == NULL) ++ return NULL; ++ ++ tmp = dt_cmd; ++ tmp = grub_stpcpy (dt_cmd, "devicetree "); ++ tmp = blsuki_update_boot_device (tmp); ++ tmp = grub_stpcpy (tmp, dt_path); ++ tmp = grub_stpcpy (tmp, "\n"); ++ } ++ ++ return dt_cmd; ++} ++ ++/* ++ * This function puts together all of the commands generated from the contents ++ * of the BLS config file and creates a new entry in the GRUB boot menu. ++ */ ++static void ++bls_create_entry (grub_blsuki_entry_t *entry) ++{ ++ int argc = 0; ++ const char **argv = NULL; ++ char *title = NULL; ++ char *linux_path = NULL; ++ char *linux_cmd = NULL; ++ char *initrd_cmd = NULL; ++ char *dt_cmd = NULL; ++ char *id = entry->filename; ++ grub_size_t id_len; ++ char *hotkey = NULL; ++ char *users = NULL; ++ char **classes = NULL; ++ char **args = NULL; ++ char *src = NULL; ++ int i; ++ grub_size_t size; ++ bool blsuki_save_default; ++ ++ linux_path = blsuki_get_val (entry, "linux", NULL); ++ if (linux_path == NULL) ++ { ++ grub_dprintf ("blsuki", "Skipping file %s with no 'linux' key.\n", entry->filename); ++ goto finish; ++ } ++ ++ id_len = grub_strlen (id); ++ if (id_len >= BLS_EXT_LEN && grub_strcmp (id + id_len - BLS_EXT_LEN, ".conf") == 0) ++ id[id_len - BLS_EXT_LEN] = '\0'; ++ ++ title = blsuki_get_val (entry, "title", NULL); ++ hotkey = blsuki_get_val (entry, "grub_hotkey", NULL); ++ users = blsuki_expand_val (blsuki_get_val (entry, "grub_users", NULL)); ++ classes = blsuki_make_list (entry, "grub_class", NULL); ++ args = blsuki_make_list (entry, "grub_arg", &argc); ++ ++ argc++; ++ if (grub_mul (argc + 1, sizeof (char *), &size)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected creating argv list")); ++ goto finish; ++ } ++ ++ argv = grub_malloc (size); ++ if (argv == NULL) ++ goto finish; ++ ++ argv[0] = (title != NULL) ? title : linux_path; ++ for (i = 1; i < argc; i++) ++ argv[i] = args[i - 1]; ++ argv[argc] = NULL; ++ ++ linux_cmd = bls_get_linux (entry); ++ if (linux_cmd == NULL) ++ goto finish; ++ ++ initrd_cmd = bls_get_initrd (entry); ++ if (grub_errno != GRUB_ERR_NONE) ++ goto finish; ++ ++ dt_cmd = bls_get_devicetree (entry); ++ if (grub_errno != GRUB_ERR_NONE) ++ goto finish; ++ ++ blsuki_save_default = grub_env_get_bool ("blsuki_save_default", false); ++ src = grub_xasprintf ("%s%s%s%s", ++ blsuki_save_default ? "savedefault\n" : "", ++ linux_cmd, initrd_cmd ? initrd_cmd : "", ++ dt_cmd ? dt_cmd : ""); ++ ++ grub_normal_add_menu_entry (argc, argv, classes, id, users, hotkey, NULL, src, 0, NULL, NULL, entry); ++ ++ finish: ++ grub_free (linux_cmd); ++ grub_free (dt_cmd); ++ grub_free (initrd_cmd); ++ grub_free (classes); ++ grub_free (args); ++ grub_free (argv); ++ grub_free (src); ++} ++ ++#ifdef GRUB_MACHINE_EFI ++/* ++ * This function puts together the section data received from the UKI and ++ * generates a new entry in the GRUB boot menu. ++ */ ++static void ++uki_create_entry (grub_blsuki_entry_t *entry) ++{ ++ const char **argv = NULL; ++ char *id = entry->filename; ++ char *title = NULL; ++ char *options = NULL; ++ char *osrel, *osrel_line; ++ char *key = NULL; ++ char *value = NULL; ++ char *src = NULL; ++ bool blsuki_save_default; ++ ++ /* ++ * Although .osrel is listed as optional in the UKI specification, the .osrel ++ * section is needed to generate the GRUB menu entry title. ++ */ ++ osrel = blsuki_get_val (entry, ".osrel", NULL); ++ if (osrel == NULL) ++ { ++ grub_dprintf ("blsuki", "Skipping file %s with no '.osrel' key.\n", entry->filename); ++ goto finish; ++ } ++ ++ osrel_line = osrel; ++ while ((key = uki_read_osrel (&osrel_line, &value)) != NULL) ++ { ++ if (grub_strcmp ("PRETTY_NAME", key) == 0) ++ { ++ title = value; ++ break; ++ } ++ } ++ ++ options = blsuki_get_val (entry, ".cmdline", NULL); ++ ++ argv = grub_zalloc (2 * sizeof (char *)); ++ if (argv == NULL) ++ goto finish; ++ argv[0] = title; ++ ++ blsuki_save_default = grub_env_get_bool ("blsuki_save_default", false); ++ src = grub_xasprintf ("%schainloader (%s)%s/%s%s%s\n", ++ blsuki_save_default ? "savedefault\n" : "", ++ entry->devid, entry->dirname, ++ entry->filename, ++ (options != NULL) ? " " : "", ++ (options != NULL) ? options : ""); ++ ++ grub_normal_add_menu_entry (1, argv, NULL, id, NULL, NULL, NULL, src, 0, NULL, NULL, entry); ++ ++ finish: ++ grub_free (argv); ++ grub_free (src); ++ grub_free (options); ++ grub_free (osrel); ++} ++#endif ++ ++/* ++ * This function fills a find_entry_info struct passed in by the info parameter. ++ * If the dirname or devid parameters are set to NULL, the dirname and devid ++ * fields in the info parameter will be set to default values. If info already ++ * has a value in the dev fields, we can compare it to the value passed in by ++ * the devid parameter or the default devid to see if we need to open a new ++ * device. ++ */ ++static grub_err_t ++blsuki_set_find_entry_info (struct find_entry_info *info, const char *dirname, const char *devid, enum blsuki_cmd_type cmd_type) ++{ ++ grub_device_t dev; ++ grub_fs_t fs; ++ ++ if (info == NULL) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "info parameter is not set"); ++ ++ if (devid == NULL) ++ { ++ if (cmd_type == BLSUKI_BLS_CMD) ++ { ++#ifdef GRUB_MACHINE_EMU ++ devid = "host"; ++#else ++ devid = grub_env_get ("root"); ++#endif ++ } ++#ifdef GRUB_MACHINE_EFI ++ else if (cmd_type == BLSUKI_UKI_CMD) ++ { ++ grub_efi_loaded_image_t *image = grub_efi_get_loaded_image (grub_efi_image_handle); ++ ++ if (image == NULL) ++ return grub_error (GRUB_ERR_BAD_DEVICE, N_("unable to find boot device")); ++ devid = grub_efidisk_get_device_name (image->device_handle); ++ } ++#endif ++ if (devid == NULL) ++ return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable '%s' isn't set"), "root"); ++ } ++ ++ /* Check that we aren't closing and opening the same device. */ ++ if (info->dev != NULL && grub_strcmp (info->devid, devid) != 0) ++ { ++ grub_device_close (info->dev); ++ info->dev = NULL; ++ } ++ /* If we are using the same device, then we can skip this step and only set the directory. */ ++ if (info->dev == NULL) ++ { ++ grub_dprintf ("blsuki", "opening %s\n", devid); ++ dev = grub_device_open (devid); ++ if (dev == NULL) ++ return grub_errno; ++ ++ grub_dprintf ("blsuki", "probing fs\n"); ++ fs = grub_fs_probe (dev); ++ if (fs == NULL) ++ { ++ grub_device_close (dev); ++ return grub_errno; ++ } ++ ++ info->devid = devid; ++ info->dev = dev; ++ info->fs = fs; ++ } ++ ++ info->dirname = dirname; ++ ++ return GRUB_ERR_NONE; ++} ++ ++/* ++ * This function searches for BLS config files and UKIs based on the data in the ++ * info parameter. If the fallback option is enabled, the default location will ++ * be checked for BLS config files or UKIs if the first attempt fails. ++ */ ++static grub_err_t ++blsuki_find_entry (struct find_entry_info *info, bool enable_fallback, enum blsuki_cmd_type cmd_type) ++{ ++ struct read_entry_info read_entry_info; ++ char *default_dir = NULL; ++ const char *cmd_dir = NULL; ++ char *tmp; ++ grub_size_t default_size; ++ grub_fs_t dir_fs = NULL; ++ grub_device_t dir_dev = NULL; ++ bool fallback = false; ++ int r; ++ ++ do ++ { ++ read_entry_info.file = NULL; ++ read_entry_info.dirname = info->dirname; ++ ++ grub_dprintf ("blsuki", "scanning dir: %s\n", info->dirname); ++ dir_dev = info->dev; ++ dir_fs = info->fs; ++ read_entry_info.devid = info->devid; ++ read_entry_info.cmd_type = cmd_type; ++ ++ r = dir_fs->fs_dir (dir_dev, read_entry_info.dirname, blsuki_read_entry, ++ &read_entry_info); ++ if (r != 0) ++ { ++ grub_dprintf ("blsuki", "blsuki_read_entry returned error\n"); ++ grub_errno = GRUB_ERR_NONE; ++ } ++ ++ /* ++ * If we aren't able to find BLS entries in the directory given by info->dirname, ++ * we can fallback to the default location "/boot/loader/entries/" and see if we ++ * can find the files there. If we can't find UKI entries, fallback to ++ * "/EFI/Linux" on the EFI system partition. ++ */ ++ if (entries == NULL && fallback == false && enable_fallback == true) ++ { ++ if (cmd_type == BLSUKI_BLS_CMD) ++ cmd_dir = GRUB_BLS_CONFIG_PATH; ++#ifdef GRUB_MACHINE_EFI ++ else if (cmd_type == BLSUKI_UKI_CMD) ++ cmd_dir = GRUB_UKI_CONFIG_PATH; ++#endif ++ ++ default_size = sizeof (GRUB_BOOT_DEVICE) + grub_strlen (cmd_dir); ++ default_dir = grub_malloc (default_size); ++ if (default_dir == NULL) ++ return grub_errno; ++ ++ tmp = blsuki_update_boot_device (default_dir); ++ tmp = grub_stpcpy (tmp, cmd_dir); ++ ++ blsuki_set_find_entry_info (info, default_dir, NULL, cmd_type); ++ grub_dprintf ("blsuki", "Entries weren't found in %s, fallback to %s\n", ++ read_entry_info.dirname, info->dirname); ++ fallback = true; ++ } ++ else ++ fallback = false; ++ } ++ while (fallback == true); ++ ++ grub_free (default_dir); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++blsuki_load_entries (char *path, bool enable_fallback, enum blsuki_cmd_type cmd_type) ++{ ++ grub_size_t len, ext_len = 0; ++ static grub_err_t r; ++ const char *devid = NULL; ++ char *dir = NULL; ++ char *default_dir = NULL; ++ char *tmp; ++ const char *cmd_dir = NULL; ++ grub_size_t dir_size; ++ const char *ext = NULL; ++ struct find_entry_info info = { ++ .dev = NULL, ++ .fs = NULL, ++ .dirname = NULL, ++ }; ++ struct read_entry_info rei = { ++ .devid = NULL, ++ .dirname = NULL, ++ .cmd_type = cmd_type, ++ }; ++ ++ if (path != NULL) ++ { ++ if (cmd_type == BLSUKI_BLS_CMD) ++ { ++ ext = ".conf"; ++ ext_len = BLS_EXT_LEN; ++ } ++#ifdef GRUB_MACHINE_EFI ++ else if (cmd_type == BLSUKI_UKI_CMD) ++ { ++ ext = ".efi"; ++ ext_len = UKI_EXT_LEN; ++ } ++#endif ++ ++ len = grub_strlen (path); ++ if (len >= ext_len && grub_strcmp (path + len - ext_len, ext) == 0) ++ { ++ rei.file = grub_file_open (path, GRUB_FILE_TYPE_CONFIG); ++ if (rei.file == NULL) ++ return grub_errno; ++ ++ /* blsuki_read_entry() closes the file. */ ++ return blsuki_read_entry (path, NULL, &rei); ++ } ++ else if (path[0] == '(') ++ { ++ devid = path + 1; ++ ++ dir = grub_strchr (path, ')'); ++ if (dir == NULL) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid file name `%s'"), path); ++ ++ *dir = '\0'; ++ ++ /* Check if there is more than the devid in the path. */ ++ if (dir + 1 < path + len) ++ dir = dir + 1; ++ } ++ else if (path[0] == '/') ++ dir = path; ++ } ++ ++ if (dir == NULL) ++ { ++ if (cmd_type == BLSUKI_BLS_CMD) ++ cmd_dir = GRUB_BLS_CONFIG_PATH; ++#ifdef GRUB_MACHINE_EFI ++ else if (cmd_type == BLSUKI_UKI_CMD) ++ cmd_dir = GRUB_UKI_CONFIG_PATH; ++#endif ++ ++ dir_size = sizeof (GRUB_BOOT_DEVICE) + grub_strlen (cmd_dir); ++ default_dir = grub_malloc (dir_size); ++ if (default_dir == NULL) ++ return grub_errno; ++ ++ tmp = blsuki_update_boot_device (default_dir); ++ tmp = grub_stpcpy (tmp, cmd_dir); ++ dir = default_dir; ++ } ++ ++ r = blsuki_set_find_entry_info (&info, dir, devid, cmd_type); ++ if (r == GRUB_ERR_NONE) ++ r = blsuki_find_entry (&info, enable_fallback, cmd_type); ++ ++ if (info.dev != NULL) ++ grub_device_close (info.dev); ++ ++ grub_free (default_dir); ++ return r; ++} ++ ++static bool ++blsuki_is_default_entry (const char *def_entry, grub_blsuki_entry_t *entry, int idx) ++{ ++ const char *title; ++ const char *def_entry_end; ++ long def_idx; ++ ++ if (def_entry == NULL || *def_entry == '\0') ++ return false; ++ ++ if (grub_strcmp (def_entry, entry->filename) == 0) ++ return true; ++ ++ title = blsuki_get_val (entry, "title", NULL); ++ ++ if (title != NULL && grub_strcmp (def_entry, title) == 0) ++ return true; ++ ++ def_idx = grub_strtol (def_entry, &def_entry_end, 0); ++ if (*def_entry_end != '\0' || def_idx < 0 || def_idx > GRUB_INT_MAX) ++ return false; ++ ++ if ((int) def_idx == idx) ++ return true; ++ ++ return false; ++} ++ ++/* ++ * This function creates a GRUB boot menu entry for each BLS or UKI entry in ++ * the entries list. ++ */ ++static grub_err_t ++blsuki_create_entries (bool show_default, bool show_non_default, char *entry_id, enum blsuki_cmd_type cmd_type) ++{ ++ const char *def_entry = NULL; ++ grub_blsuki_entry_t *entry = NULL; ++ int idx = 0; ++ ++ def_entry = grub_env_get ("default"); ++ ++ FOR_BLSUKI_ENTRIES(entry) ++ { ++ if (entry->visible == true) ++ { ++ idx++; ++ continue; ++ } ++ if ((show_default == true && blsuki_is_default_entry (def_entry, entry, idx) == true) || ++ (show_non_default == true && blsuki_is_default_entry (def_entry, entry, idx) == false) || ++ (entry_id != NULL && grub_strcmp (entry_id, entry->filename) == 0)) ++ { ++ if (cmd_type == BLSUKI_BLS_CMD) ++ bls_create_entry (entry); ++#ifdef GRUB_MACHINE_EFI ++ else if (cmd_type == BLSUKI_UKI_CMD) ++ uki_create_entry (entry); ++#endif ++ entry->visible = true; ++ } ++ ++ idx++; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++blsuki_cmd (grub_extcmd_context_t ctxt, enum blsuki_cmd_type cmd_type) ++{ ++ grub_err_t err; ++ struct grub_arg_list *state = ctxt->state; ++ char *path = NULL; ++ char *entry_id = NULL; ++ bool enable_fallback = false; ++ bool show_default = false; ++ bool show_non_default = false; ++ bool all = true; ++ entries = NULL; ++ ++ if (state[0].set) ++ path = state[0].arg; ++ if (state[1].set) ++ enable_fallback = true; ++ if (state[2].set) ++ { ++ show_default = true; ++ all = false; ++ } ++ if (state[3].set) ++ { ++ show_non_default = true; ++ all = false; ++ } ++ if (state[4].set) ++ { ++ entry_id = state[4].arg; ++ all = false; ++ } ++ if (all == true) ++ { ++ show_default = true; ++ show_non_default = true; ++ } ++ ++ err = blsuki_load_entries (path, enable_fallback, cmd_type); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ ++ return blsuki_create_entries (show_default, show_non_default, entry_id, cmd_type); ++} ++ ++static grub_err_t ++grub_cmd_blscfg (grub_extcmd_context_t ctxt, int argc __attribute__ ((unused)), ++ char **args __attribute__ ((unused))) ++{ ++ return blsuki_cmd (ctxt, BLSUKI_BLS_CMD); ++} ++ ++static grub_extcmd_t bls_cmd; ++ ++#ifdef GRUB_MACHINE_EFI ++static grub_err_t ++grub_cmd_uki (grub_extcmd_context_t ctxt, int argc __attribute__ ((unused)), ++ char **args __attribute__ ((unused))) ++{ ++ return blsuki_cmd (ctxt, BLSUKI_UKI_CMD); ++} ++ ++static grub_extcmd_t uki_cmd; ++#endif ++ ++GRUB_MOD_INIT(blsuki) ++{ ++#ifdef GRUB_MACHINE_EFI ++ uki_cmd = grub_register_extcmd ("uki", grub_cmd_uki, 0, ++ N_("[-p|--path] DIR [-f|--enable-fallback] [-d|--show-default] [-n|--show-non-default] [-e|--entry] FILE"), ++ N_("Import Unified Kernel Images"), uki_opt); ++#endif ++} ++ ++GRUB_MOD_FINI(blsuki) ++{ ++ grub_unregister_extcmd (bls_cmd); ++#ifdef GRUB_MACHINE_EFI ++ grub_unregister_extcmd (uki_cmd); ++#endif ++} diff --git a/grub-core/commands/efi/connectefi.c b/grub-core/commands/efi/connectefi.c new file mode 100644 index 000000000..9d02f2780 @@ -7173,6 +9072,45 @@ index 7b8316d41..3635cd99b 100644 #include #include #include +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/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/grub-core/commands/increment.c b/grub-core/commands/increment.c new file mode 100644 index 000000000..79cf13765 @@ -7317,7 +9255,7 @@ index 584baec8f..7b2999b14 100644 grub_unregister_extcmd (cmd_read_word); grub_unregister_extcmd (cmd_read_dword); diff --git a/grub-core/commands/legacycfg.c b/grub-core/commands/legacycfg.c -index e9e9d94ef..2c5d1a0ef 100644 +index e9e9d94ef..a5d296769 100644 --- a/grub-core/commands/legacycfg.c +++ b/grub-core/commands/legacycfg.c @@ -143,7 +143,7 @@ legacy_file (const char *filename) @@ -7325,17 +9263,24 @@ index e9e9d94ef..2c5d1a0ef 100644 grub_normal_add_menu_entry (1, args, NULL, NULL, "legacy", NULL, NULL, - entrysrc, 0); -+ entrysrc, 0, NULL, NULL); ++ entrysrc, 0, NULL, NULL, NULL); grub_free (args); entrysrc[0] = 0; grub_free (oldname); -@@ -205,7 +205,8 @@ legacy_file (const char *filename) +@@ -198,14 +198,14 @@ legacy_file (const char *filename) + const char **args = grub_malloc (sizeof (args[0])); + if (!args) + { +- grub_file_close (file); + grub_free (suffix); + grub_free (entrysrc); + return grub_errno; } args[0] = entryname; grub_normal_add_menu_entry (1, args, NULL, NULL, NULL, - NULL, NULL, entrysrc, 0); + NULL, NULL, entrysrc, 0, NULL, -+ NULL); ++ NULL, NULL); grub_free (args); } @@ -7533,8 +9478,25 @@ index 000000000..952f46121 + + return 0; +} +diff --git a/grub-core/commands/ls.c b/grub-core/commands/ls.c +index 6a1c7f5d3..f660946a2 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; ++ + ctx.dirname = grub_strndup (dirname, p - dirname); + if (ctx.dirname == NULL) + goto fail; diff --git a/grub-core/commands/memrw.c b/grub-core/commands/memrw.c -index d401a6db0..39cf3a06d 100644 +index d401a6db0..9d8a54a4b 100644 --- a/grub-core/commands/memrw.c +++ b/grub-core/commands/memrw.c @@ -23,6 +23,7 @@ @@ -7545,7 +9507,7 @@ index d401a6db0..39cf3a06d 100644 GRUB_MOD_LICENSE ("GPLv3+"); -@@ -121,6 +122,9 @@ grub_cmd_write (grub_command_t cmd, int argc, char **argv) +@@ -121,18 +122,24 @@ grub_cmd_write (grub_command_t cmd, int argc, char **argv) GRUB_MOD_INIT(memrw) { @@ -7553,9 +9515,33 @@ index d401a6db0..39cf3a06d 100644 + return; + cmd_read_byte = - grub_register_extcmd ("read_byte", grub_cmd_read, 0, - N_("ADDR"), N_("Read 8-bit value from ADDR."), -@@ -149,6 +153,9 @@ GRUB_MOD_INIT(memrw) +- 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]"), +@@ -149,6 +156,9 @@ GRUB_MOD_INIT(memrw) GRUB_MOD_FINI(memrw) { @@ -7566,7 +9552,7 @@ index d401a6db0..39cf3a06d 100644 grub_unregister_extcmd (cmd_read_word); grub_unregister_extcmd (cmd_read_dword); diff --git a/grub-core/commands/menuentry.c b/grub-core/commands/menuentry.c -index 720e6d8ea..b175a1b43 100644 +index 720e6d8ea..d6cf32920 100644 --- a/grub-core/commands/menuentry.c +++ b/grub-core/commands/menuentry.c @@ -29,7 +29,7 @@ static const struct grub_arg_option options[] = @@ -7583,7 +9569,7 @@ index 720e6d8ea..b175a1b43 100644 const char *users, const char *hotkey, const char *prefix, const char *sourcecode, - int submenu) -+ int submenu, int *index, struct bls_entry *bls) ++ int submenu, int *index, struct bls_entry *bls, grub_blsuki_entry_t *blsuki) { int menu_hotkey = 0; char **menu_args = NULL; @@ -7614,11 +9600,12 @@ index 720e6d8ea..b175a1b43 100644 *last = grub_zalloc (sizeof (**last)); if (! *last) -@@ -188,8 +195,11 @@ grub_normal_add_menu_entry (int argc, const char **args, +@@ -188,8 +195,12 @@ grub_normal_add_menu_entry (int argc, const char **args, (*last)->args = menu_args; (*last)->sourcecode = menu_sourcecode; (*last)->submenu = submenu; + (*last)->bls = bls; ++ (*last)->blsuki = blsuki; menu->size++; + if (index) @@ -7626,7 +9613,7 @@ index 720e6d8ea..b175a1b43 100644 return GRUB_ERR_NONE; fail: -@@ -271,7 +281,7 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) +@@ -271,7 +282,7 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) if (! ctxt->state[3].set && ! ctxt->script) return grub_error (GRUB_ERR_BAD_ARGUMENT, "no menuentry definition"); @@ -7635,31 +9622,51 @@ index 720e6d8ea..b175a1b43 100644 users = ctxt->state[1].arg; else if (ctxt->state[5].set) users = NULL; -@@ -286,7 +296,8 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) +@@ -286,7 +297,8 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) users, ctxt->state[2].arg, 0, ctxt->state[3].arg, - ctxt->extcmd->cmd->name[0] == 's'); + ctxt->extcmd->cmd->name[0] == 's', -+ NULL, NULL); ++ NULL, NULL, NULL); src = args[argc - 1]; args[argc - 1] = NULL; -@@ -303,7 +314,8 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) +@@ -303,7 +315,8 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) ctxt->state[0].args, ctxt->state[4].arg, users, ctxt->state[2].arg, prefix, src + 1, - ctxt->extcmd->cmd->name[0] == 's'); + ctxt->extcmd->cmd->name[0] == 's', NULL, -+ NULL); ++ NULL, NULL); src[len - 1] = ch; args[argc - 1] = src; diff --git a/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c -index fa498931e..2bd3ac76f 100644 +index fa498931e..eb786766a 100644 --- a/grub-core/commands/minicmd.c +++ b/grub-core/commands/minicmd.c -@@ -182,12 +182,24 @@ grub_mini_cmd_lsmod (struct grub_command *cmd __attribute__ ((unused)), +@@ -29,6 +29,10 @@ + #include + #include + ++#ifdef GRUB_MACHINE_EFI ++#include ++#endif ++ + GRUB_MOD_LICENSE ("GPLv3+"); + + /* cat FILE */ +@@ -167,7 +171,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) +@@ -182,12 +186,31 @@ grub_mini_cmd_lsmod (struct grub_command *cmd __attribute__ ((unused)), } /* exit */ @@ -7684,12 +9691,30 @@ index fa498931e..2bd3ac76f 100644 + retval = n; + } + ++#ifdef GRUB_MACHINE_EFI ++ /* ++ * The "exit" command is often used to launch the next boot application. ++ * So, erase the secrets. ++ */ ++ grub_cryptodisk_erasesecrets (); ++#endif + grub_exit (retval); /* Not reached. */ } +@@ -203,8 +226,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/grub-core/commands/pgp.c b/grub-core/commands/pgp.c -index c6766f044..847a5046a 100644 +index c6766f044..fa3ef5c75 100644 --- a/grub-core/commands/pgp.c +++ b/grub-core/commands/pgp.c @@ -24,6 +24,7 @@ @@ -7754,6 +9779,64 @@ index c6766f044..847a5046a 100644 continue; pseudo_file.fs = &pseudo_fs; +@@ -1010,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/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/grub-core/commands/reboot.c b/grub-core/commands/reboot.c index 46d364c99..f5cc22836 100644 --- a/grub-core/commands/reboot.c @@ -7782,7 +9865,7 @@ index 46d364c99..f5cc22836 100644 + grub_unregister_command (reset_cmd); } diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c -index 263f1501c..d538b3621 100644 +index 263f1501c..c432c0ac6 100644 --- a/grub-core/commands/search.c +++ b/grub-core/commands/search.c @@ -30,6 +30,8 @@ @@ -7794,7 +9877,7 @@ index 263f1501c..d538b3621 100644 GRUB_MOD_LICENSE ("GPLv3+"); -@@ -54,6 +56,100 @@ struct search_ctx +@@ -54,6 +56,135 @@ struct search_ctx int is_cache; }; @@ -7891,14 +9974,69 @@ index 263f1501c..d538b3621 100644 + + return ret; +} ++ ++static bool ++is_unencrypted_disk (grub_disk_t disk) ++{ ++ grub_command_t cmd; ++ char *disk_str; ++ int disk_str_len; ++ int res; ++ ++ if (disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID) ++ return false; /* This is (crypto) disk. */ ++ ++ if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID) ++ { ++ char opt[] = "--quiet"; ++ char *args[2]; ++ ++ cmd = grub_command_find ("cryptocheck"); ++ if (cmd == NULL) /* No diskfilter module loaded for some reason. */ ++ return true; ++ ++ disk_str_len = grub_strlen (disk->name) + 2 + 1; ++ disk_str = grub_malloc (disk_str_len); ++ if (disk_str == NULL) /* Something is wrong, better report as unencrypted. */ ++ return true; ++ ++ grub_snprintf (disk_str, disk_str_len, "(%s)", disk->name); ++ args[0] = opt; ++ args[1] = disk_str; ++ res = cmd->func (cmd, 2, args); ++ grub_free (disk_str); ++ return (res != GRUB_ERR_NONE) ? true : false; /* GRUB_ERR_NONE for encrypted. */ ++ } ++ return true; ++} + /* Helper for FUNC_NAME. */ static int iterate_device (const char *name, void *data) -@@ -86,6 +182,66 @@ iterate_device (const char *name, void *data) +@@ -86,6 +217,86 @@ iterate_device (const char *name, void *data) grub_device_close (dev); } ++ /* Limit to encrypted disks when requested. */ ++ if (ctx->flags & SEARCH_FLAGS_CRYPTODISK_ONLY) ++ { ++ grub_device_t dev; ++ ++ dev = grub_device_open (name); ++ if (dev == NULL) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ return 0; ++ } ++ if (dev->disk == NULL || is_unencrypted_disk (dev->disk) == true) ++ { ++ grub_device_close (dev); ++ grub_errno = GRUB_ERR_NONE; ++ return 0; ++ } ++ grub_device_close (dev); ++ } ++ + /* Skip it if it's not the root device when requested. */ + if (ctx->flags & SEARCH_FLAGS_ROOTDEV_ONLY) + { @@ -7963,35 +10101,134 @@ index 263f1501c..d538b3621 100644 #define compare_fn grub_strcasecmp #else diff --git a/grub-core/commands/search_wrap.c b/grub-core/commands/search_wrap.c -index 318581f3b..4fe6440c6 100644 +index 318581f3b..ec2fb638f 100644 --- a/grub-core/commands/search_wrap.c +++ b/grub-core/commands/search_wrap.c -@@ -41,6 +41,7 @@ static const struct grub_arg_option options[] = +@@ -41,6 +41,8 @@ static const struct grub_arg_option options[] = ARG_TYPE_STRING}, {"no-floppy", 'n', 0, N_("Do not probe any floppy drive."), 0, 0}, {"efidisk-only", 0, 0, N_("Only probe EFI disks."), 0, 0}, ++ {"cryptodisk-only", 0, 0, N_("Only probe encrypted disks."), 0, 0}, + {"root-dev-only", 'r', 0, N_("Only probe root device."), 0, 0}, {"hint", 'h', GRUB_ARG_OPTION_REPEATABLE, N_("First try the device HINT. If HINT ends in comma, " "also try subpartitions"), N_("HINT"), ARG_TYPE_STRING}, -@@ -75,6 +76,7 @@ enum options +@@ -75,6 +77,8 @@ enum options SEARCH_SET, SEARCH_NO_FLOPPY, SEARCH_EFIDISK_ONLY, ++ SEARCH_CRYPTODISK_ONLY, + SEARCH_ROOTDEV_ONLY, SEARCH_HINT, SEARCH_HINT_IEEE1275, SEARCH_HINT_BIOS, -@@ -189,6 +191,9 @@ grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args) +@@ -189,6 +193,12 @@ grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args) if (state[SEARCH_EFIDISK_ONLY].set) flags |= SEARCH_FLAGS_EFIDISK_ONLY; ++ if (state[SEARCH_CRYPTODISK_ONLY].set) ++ flags |= SEARCH_FLAGS_CRYPTODISK_ONLY; ++ + if (state[SEARCH_ROOTDEV_ONLY].set) + flags |= SEARCH_FLAGS_ROOTDEV_ONLY; + if (state[SEARCH_LABEL].set) grub_search_label (id, var, flags, hints, nhints); else if (state[SEARCH_FS_UUID].set) +@@ -210,7 +220,7 @@ GRUB_MOD_INIT(search) + cmd = + grub_register_extcmd ("search", grub_cmd_search, + GRUB_COMMAND_FLAG_EXTRACTOR | GRUB_COMMAND_ACCEPT_DASH, +- N_("[-f|-l|-u|-s|-n] [--hint HINT [--hint HINT] ...]" ++ N_("[-f|-l|-u|-s|-n] [--cryptodisk-only] [--hint HINT [--hint HINT] ...]" + " NAME"), + N_("Search devices by file, filesystem label" + " or filesystem UUID." +diff --git a/grub-core/commands/test.c b/grub-core/commands/test.c +index 62d3fb398..ee47ab264 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/grub-core/commands/usbtest.c b/grub-core/commands/usbtest.c +index 2c6d93fe6..3184ac9af 100644 +--- a/grub-core/commands/usbtest.c ++++ b/grub-core/commands/usbtest.c +@@ -90,7 +90,7 @@ grub_usb_get_string (grub_usb_device_t dev, grub_uint8_t index, int langid, + 0x06, (3 << 8) | index, + langid, descstr.length, (char *) descstrp); + +- if (descstrp->length == 0) ++ if (descstrp->length < 2) + { + grub_free (descstrp); + *string = grub_strdup (""); +@@ -99,7 +99,7 @@ grub_usb_get_string (grub_usb_device_t dev, grub_uint8_t index, int langid, + return GRUB_USB_ERR_NONE; + } + +- *string = grub_malloc (descstr.length * 2 + 1); ++ *string = grub_malloc (descstrp->length * 2 + 1); + if (! *string) + { + grub_free (descstrp); diff --git a/grub-core/commands/version.c b/grub-core/commands/version.c new file mode 100644 index 000000000..de0acb07b @@ -8088,11 +10325,49 @@ index ed6586505..5455242c3 100644 { *optr++ = iptr[1]; iptr += 2; +diff --git a/grub-core/disk/ahci.c b/grub-core/disk/ahci.c +index e7b5dc5f2..b247161b9 100644 +--- a/grub-core/disk/ahci.c ++++ b/grub-core/disk/ahci.c +@@ -1038,7 +1038,7 @@ grub_ahci_readwrite_real (struct grub_ahci_device *dev, + grub_dprintf ("ahci", "AHCI tfd = %x\n", + dev->hba->ports[dev->port].task_file_data); + +- endtime = grub_get_time_ms () + (spinup ? 20000 : 20000); ++ endtime = grub_get_time_ms () + 20000; + while ((dev->hba->ports[dev->port].command_issue & 1)) + if (grub_get_time_ms () > endtime || + (dev->hba->ports[dev->port].intstatus & GRUB_AHCI_HBA_PORT_IS_FATAL_MASK)) +diff --git a/grub-core/disk/ata.c b/grub-core/disk/ata.c +index 7b6ac7bfc..a2433e29e 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/cryptodisk.c b/grub-core/disk/cryptodisk.c -index 2246af51b..98e176a13 100644 +index 2246af51b..26457095d 100644 --- a/grub-core/disk/cryptodisk.c +++ b/grub-core/disk/cryptodisk.c -@@ -721,7 +721,7 @@ grub_cryptodisk_open (const char *name, grub_disk_t disk) +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + #ifdef GRUB_UTIL + #include +@@ -721,7 +722,7 @@ grub_cryptodisk_open (const char *name, grub_disk_t disk) #ifdef GRUB_UTIL if (dev->cheat) { @@ -8101,11 +10376,228 @@ index 2246af51b..98e176a13 100644 unsigned int cheat_log_sector_size; if (!GRUB_UTIL_FD_IS_VALID (dev->cheat_fd)) +@@ -1144,7 +1145,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"); +@@ -1161,6 +1164,7 @@ grub_cryptodisk_scan_device_real (const char *name, + + if (askpass) + { ++ grub_memset (cargs->key_data, 0, cargs->key_len); + cargs->key_len = 0; + grub_free (cargs->key_data); + } +@@ -1473,7 +1477,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; +@@ -1482,10 +1486,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 +@@ -1493,14 +1493,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; + +@@ -1576,6 +1597,114 @@ 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; ++} ++ ++void ++grub_cryptodisk_erasesecrets (void) ++{ ++ grub_cryptodisk_t i; ++ grub_uint8_t *buf; ++ ++ buf = grub_zalloc (GRUB_CRYPTODISK_MAX_KEYLEN); ++ if (buf == NULL) ++ grub_fatal ("grub_cryptodisk_erasesecrets: cannot allocate memory"); ++ ++ for (i = cryptodisk_list; i != NULL; i = i->next) ++ if (grub_cryptodisk_setkey (i, buf, i->keysize)) ++ grub_fatal ("grub_cryptodisk_erasesecrets: cannot erase secrets for %s", i->source); ++ else ++ grub_printf ("Erased crypto secrets for %s\n", i->source); ++ /* ++ * Unfortunately, there is no way to "force unmount" a given disk, it may ++ * have mounted "child" disks as well, e.g., an LVM volume. So, this ++ * function MUST be called when there is no way back, e.g., when exiting. ++ * Otherwise, subsequent read calls for a cryptodisk will return garbage. ++ */ ++ ++ grub_free (buf); ++} ++#endif /* GRUB_MACHINE_EFI */ ++ + struct grub_procfs_entry luks_script = + { + .name = "luks_script", +@@ -1597,6 +1726,9 @@ GRUB_MOD_INIT (cryptodisk) + + GRUB_MOD_FINI (cryptodisk) + { ++#ifdef GRUB_MACHINE_EFI ++ grub_cryptodisk_erasesecrets (); ++#endif + grub_disk_dev_unregister (&grub_cryptodisk_dev); + cryptodisk_cleanup (); + grub_unregister_extcmd (cmd); diff --git a/grub-core/disk/diskfilter.c b/grub-core/disk/diskfilter.c -index 21e239511..c35ce8915 100644 +index 21e239511..04b64aebc 100644 --- a/grub-core/disk/diskfilter.c +++ b/grub-core/disk/diskfilter.c -@@ -188,6 +188,8 @@ scan_disk (const char *name, int accept_diskfilter) +@@ -20,10 +20,12 @@ + #include + #include + #include ++#include + #include + #include + #include + #include ++#include + #ifdef GRUB_UTIL + #include + #include +@@ -188,6 +190,8 @@ scan_disk (const char *name, int accept_diskfilter) grub_disk_t disk; static int scan_depth = 0; @@ -8114,7 +10606,29 @@ index 21e239511..c35ce8915 100644 if (!accept_diskfilter && is_valid_diskfilter_name (name)) return 0; -@@ -1247,6 +1249,7 @@ insert_array (grub_disk_t disk, const struct grub_diskfilter_pv_id *id, +@@ -1039,7 +1043,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; +@@ -1140,7 +1144,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; + +@@ -1247,6 +1255,7 @@ insert_array (grub_disk_t disk, const struct grub_diskfilter_pv_id *id, the same. */ if (pv->disk && grub_disk_native_sectors (disk) >= pv->part_size) return GRUB_ERR_NONE; @@ -8122,6 +10636,115 @@ index 21e239511..c35ce8915 100644 pv->disk = grub_disk_open (disk->name); if (!pv->disk) return grub_errno; +@@ -1357,6 +1366,86 @@ grub_diskfilter_get_pv_from_disk (grub_disk_t disk, + } + #endif + ++static int ++grub_diskfilter_check_pvs_encrypted (grub_disk_t disk, int *pvs_cnt) ++{ ++ struct grub_diskfilter_lv *lv = disk->data; ++ struct grub_diskfilter_pv *pv; ++ ++ *pvs_cnt = 0; ++ ++ if (lv->vg->pvs) ++ for (pv = lv->vg->pvs; pv; pv = pv->next) ++ { ++ (*pvs_cnt)++; ++ ++ if (pv->disk == NULL) ++ { ++ /* Can be a partially activated VG, bail out. */ ++ return GRUB_ERR_TEST_FAILURE; ++ } ++ ++ if (pv->disk->dev->id != GRUB_DISK_DEVICE_CRYPTODISK_ID) ++ { ++ /* All backing devices must be cryptodisks, stop. */ ++ return GRUB_ERR_TEST_FAILURE; ++ } ++ } ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_cryptocheck (grub_command_t cmd __attribute__ ((unused)), ++ int argc, char **args) ++{ ++ grub_disk_t disk; ++ int check_pvs_res; ++ int namelen; ++ int pvs_cnt; ++ int opt_quiet = 0; ++ ++ if (argc == 2) ++ { ++ if (grub_strcmp (args[0], "--quiet") == 0) ++ { ++ opt_quiet = 1; ++ argc--; ++ args++; ++ } ++ else ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unrecognized option: %s"), args[0]); ++ } ++ ++ if (argc != 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("disk name expected")); ++ ++ namelen = grub_strlen (args[0]); ++ if (namelen > 2 && (args[0][0] == '(') && (args[0][namelen - 1] == ')')) ++ args[0][namelen - 1] = 0; ++ else ++ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("invalid disk: %s"), ++ args[0]); ++ ++ if (!is_valid_diskfilter_name (&args[0][1])) ++ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("unrecognized disk: %s"), ++ &args[0][1]); ++ ++ disk = grub_disk_open (&args[0][1]); ++ if (disk == NULL) ++ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("no such disk: %s"), ++ &args[0][1]); ++ ++ check_pvs_res = grub_diskfilter_check_pvs_encrypted (disk, &pvs_cnt); ++ grub_disk_close (disk); ++ if (!opt_quiet) ++ grub_printf ("%s is %sencrypted (%d pv%s examined)\n", &args[0][1], ++ (check_pvs_res == GRUB_ERR_NONE) ? "" : "un", ++ pvs_cnt, ++ (pvs_cnt > 1) ? "s" : ""); ++ ++ return check_pvs_res; ++} ++ + static struct grub_disk_dev grub_diskfilter_dev = + { + .name = "diskfilter", +@@ -1373,14 +1462,21 @@ static struct grub_disk_dev grub_diskfilter_dev = + .next = 0 + }; + ++static grub_command_t cmd; ++ + + GRUB_MOD_INIT(diskfilter) + { + grub_disk_dev_register (&grub_diskfilter_dev); ++ cmd = grub_register_command ("cryptocheck", grub_cmd_cryptocheck, ++ N_("[--quiet] DEVICE"), ++ N_("Check if a logical volume resides on encrypted disks.")); + } + + GRUB_MOD_FINI(diskfilter) + { + grub_disk_dev_unregister (&grub_diskfilter_dev); ++ if (cmd != NULL) ++ grub_unregister_command (cmd); + free_array (); + } diff --git a/grub-core/disk/efi/efidisk.c b/grub-core/disk/efi/efidisk.c index 3b5ed5691..af69cc3bc 100644 --- a/grub-core/disk/efi/efidisk.c @@ -8154,19 +10777,127 @@ index 3b5ed5691..af69cc3bc 100644 parent = grub_disk_open (device_name); grub_free (dup_dp); +diff --git a/grub-core/disk/ieee1275/obdisk.c b/grub-core/disk/ieee1275/obdisk.c +index cd923b90f..fcc39e0a2 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,8 +413,22 @@ 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); ++ 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); +@@ -413,6 +444,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 +460,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 c6cba0c8a..57624fde5 100644 +index c6cba0c8a..71237b256 100644 --- a/grub-core/disk/ieee1275/ofdisk.c +++ b/grub-core/disk/ieee1275/ofdisk.c -@@ -24,6 +24,7 @@ +@@ -24,6 +24,8 @@ #include #include #include +#include ++#include static char *last_devpath; static grub_ieee1275_ihandle_t last_ihandle; -@@ -44,7 +45,7 @@ struct ofdisk_hash_ent +@@ -44,7 +46,7 @@ struct ofdisk_hash_ent }; static grub_err_t @@ -8175,18 +10906,99 @@ index c6cba0c8a..57624fde5 100644 struct ofdisk_hash_ent *op); #define OFDISK_HASH_SZ 8 -@@ -225,7 +226,9 @@ dev_iterate (const struct grub_ieee1275_devalias *alias) +@@ -80,6 +82,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 +90,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 +107,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,8 +239,10 @@ dev_iterate (const struct grub_ieee1275_devalias *alias) + args; char *buf, *bufptr; unsigned i; ++ grub_size_t sz; - if (grub_ieee1275_open (alias->path, &ihandle)) -+ + RETRY_IEEE1275_OFDISK_OPEN(alias->path, &ihandle) + if (! ihandle) return; /* This method doesn't need memory allocation for the table. Open -@@ -305,7 +308,9 @@ dev_iterate (const struct grub_ieee1275_devalias *alias) +@@ -243,9 +260,19 @@ 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; ++ { ++ grub_ieee1275_close (ihandle); ++ return; ++ } + bufptr = grub_stpcpy (buf, alias->path); + + for (i = 0; i < args.nentries; i++) +@@ -287,9 +314,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; ++ ++ 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 (grub_strlen (alias->path) + +- sizeof ("/disk@7766554433221100")); ++ buf = grub_malloc (sz); + if (!buf) + return; + bufptr = grub_stpcpy (buf, alias->path); +@@ -305,7 +338,9 @@ dev_iterate (const struct grub_ieee1275_devalias *alias) return; } @@ -8197,7 +11009,26 @@ index c6cba0c8a..57624fde5 100644 { grub_free (buf); grub_free (table); -@@ -461,6 +466,7 @@ grub_ofdisk_open (const char *name, grub_disk_t disk) +@@ -427,9 +462,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; + +@@ -461,6 +504,7 @@ grub_ofdisk_open (const char *name, grub_disk_t disk) grub_ssize_t actual; grub_uint32_t block_size = 0; grub_err_t err; @@ -8205,7 +11036,7 @@ index c6cba0c8a..57624fde5 100644 if (grub_strncmp (name, "ieee1275/", sizeof ("ieee1275/") - 1) != 0) return grub_error (GRUB_ERR_UNKNOWN_DEVICE, -@@ -471,6 +477,35 @@ grub_ofdisk_open (const char *name, grub_disk_t disk) +@@ -471,6 +515,35 @@ grub_ofdisk_open (const char *name, grub_disk_t disk) grub_dprintf ("disk", "Opening `%s'.\n", devpath); @@ -8241,7 +11072,7 @@ index c6cba0c8a..57624fde5 100644 if (grub_ieee1275_finddevice (devpath, &dev)) { grub_free (devpath); -@@ -491,25 +526,18 @@ grub_ofdisk_open (const char *name, grub_disk_t disk) +@@ -491,25 +564,18 @@ grub_ofdisk_open (const char *name, grub_disk_t disk) return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a block device"); } @@ -8270,7 +11101,7 @@ index c6cba0c8a..57624fde5 100644 if (err) { grub_free (devpath); -@@ -528,13 +556,6 @@ grub_ofdisk_open (const char *name, grub_disk_t disk) +@@ -528,13 +594,6 @@ grub_ofdisk_open (const char *name, grub_disk_t disk) static void grub_ofdisk_close (grub_disk_t disk) { @@ -8284,7 +11115,7 @@ index c6cba0c8a..57624fde5 100644 disk->data = 0; } -@@ -551,7 +572,7 @@ grub_ofdisk_prepare (grub_disk_t disk, grub_disk_addr_t sector) +@@ -551,7 +610,7 @@ grub_ofdisk_prepare (grub_disk_t disk, grub_disk_addr_t sector) last_ihandle = 0; last_devpath = NULL; @@ -8293,7 +11124,7 @@ index c6cba0c8a..57624fde5 100644 if (! last_ihandle) return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); last_devpath = disk->data; -@@ -578,12 +599,23 @@ grub_ofdisk_read (grub_disk_t disk, grub_disk_addr_t sector, +@@ -578,12 +637,23 @@ grub_ofdisk_read (grub_disk_t disk, grub_disk_addr_t sector, return err; grub_ieee1275_read (last_ihandle, buf, size << disk->log_sector_size, &actual); @@ -8318,7 +11149,30 @@ index c6cba0c8a..57624fde5 100644 return 0; } -@@ -681,7 +713,7 @@ grub_ofdisk_init (void) +@@ -625,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) +@@ -635,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 (); +@@ -681,7 +758,7 @@ grub_ofdisk_init (void) } static grub_err_t @@ -8327,7 +11181,7 @@ index c6cba0c8a..57624fde5 100644 struct ofdisk_hash_ent *op) { struct size_args_ieee1275 -@@ -694,16 +726,6 @@ grub_ofdisk_get_block_size (const char *device, grub_uint32_t *block_size, +@@ -694,16 +771,6 @@ grub_ofdisk_get_block_size (const char *device, grub_uint32_t *block_size, grub_ieee1275_cell_t size2; } args_ieee1275; @@ -8344,11 +11198,106 @@ index c6cba0c8a..57624fde5 100644 *block_size = 0; if (op->block_size_fails >= 2) +diff --git a/grub-core/disk/ldm.c b/grub-core/disk/ldm.c +index 34bfe6bd1..048e29cd0 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,21 @@ 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); ++ 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; + +@@ -343,7 +364,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 +482,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) +@@ -490,7 +518,12 @@ make_vg (grub_disk_t disk, + grub_free (comp); + 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); +@@ -640,7 +673,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/loopback.c b/grub-core/disk/loopback.c -index 4635dcfde..11a5e0cbd 100644 +index 4635dcfde..f39281323 100644 --- a/grub-core/disk/loopback.c +++ b/grub-core/disk/loopback.c -@@ -21,20 +21,13 @@ +@@ -21,20 +21,14 @@ #include #include #include @@ -8356,6 +11305,7 @@ index 4635dcfde..11a5e0cbd 100644 #include #include #include ++#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -8370,6 +11320,162 @@ index 4635dcfde..11a5e0cbd 100644 static struct grub_loopback *loopback_list; static unsigned long last_id = 0; +@@ -64,6 +58,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; + +@@ -120,6 +116,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; +@@ -161,6 +158,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) +@@ -178,6 +178,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) +@@ -220,6 +229,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/grub-core/disk/luks2.c b/grub-core/disk/luks2.c +index d5106402f..8036d76ff 100644 +--- a/grub-core/disk/luks2.c ++++ b/grub-core/disk/luks2.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -569,6 +570,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"); +@@ -577,7 +579,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/lvm.c b/grub-core/disk/lvm.c +index 794248540..b2dff76d1 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 = ["); +@@ -671,8 +681,9 @@ 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])); ++ if (seg->nodes == NULL) ++ goto lvs_segment_fail; + + p = grub_strstr (p, "mirrors = ["); + if (p == NULL) +@@ -760,8 +771,9 @@ 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])); ++ if (seg->nodes == NULL) ++ goto lvs_segment_fail; + + p = grub_strstr (p, "raids = ["); + if (p == NULL) diff --git a/grub-core/disk/mdraid1x_linux.c b/grub-core/disk/mdraid1x_linux.c index 72e5cb6f4..3b5b6c423 100644 --- a/grub-core/disk/mdraid1x_linux.c @@ -8403,8 +11509,168 @@ index e40216f51..98fcfb1be 100644 /* The sector where the mdraid 0.90 superblock is stored, if available. */ size = grub_disk_native_sectors (disk); if (size == GRUB_DISK_SIZE_UNKNOWN) +diff --git a/grub-core/disk/memdisk.c b/grub-core/disk/memdisk.c +index 613779cf3..2d7afaea3 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,8 +97,14 @@ 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); ++ 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/grub-core/disk/plainmount.c b/grub-core/disk/plainmount.c +index 47e64805f..21ec4072c 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/grub-core/fs/affs.c b/grub-core/fs/affs.c +index ed606b3f1..520a001c7 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+"); + +@@ -703,11 +704,16 @@ static struct grub_fs grub_affs_fs = + + GRUB_MOD_INIT(affs) + { +- 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/archelp.c b/grub-core/fs/archelp.c +index c1dcc6285..0816b28de 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/bfs.c b/grub-core/fs/bfs.c +index 07cb3e3ac..c92fd7916 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+"); + +@@ -1106,7 +1107,11 @@ GRUB_MOD_INIT (bfs) + { + COMPILE_TIME_ASSERT (1 << LOG_EXTENT_SIZE == + sizeof (struct grub_bfs_extent)); +- grub_fs_register (&grub_bfs_fs); ++ if (!grub_is_lockdown ()) ++ { ++ grub_bfs_fs.mod = mod; ++ grub_fs_register (&grub_bfs_fs); ++ } + } + + #ifdef MODE_AFS +@@ -1115,5 +1120,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/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c -index ba0c58352..ad35e7575 100644 +index ba0c58352..2222c57ab 100644 --- a/grub-core/fs/btrfs.c +++ b/grub-core/fs/btrfs.c @@ -38,6 +38,10 @@ @@ -8608,6 +11874,17 @@ index ba0c58352..ad35e7575 100644 if (!dev->disk) { +@@ -1276,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); @@ -1287,6 +1420,16 @@ grub_btrfs_mount (grub_device_t dev) data->devices_attached[0].dev = dev; data->devices_attached[0].id = data->sblock.this_device.device_id; @@ -8717,7 +11994,7 @@ index ba0c58352..ad35e7575 100644 static grub_err_t find_path (struct grub_btrfs_data *data, const char *path, struct grub_btrfs_key *key, -@@ -1796,31 +2024,66 @@ find_path (struct grub_btrfs_data *data, +@@ -1796,31 +2024,67 @@ find_path (struct grub_btrfs_data *data, grub_size_t allocated = 0; struct grub_btrfs_dir_item *direl = NULL; struct grub_btrfs_key key_out; @@ -8728,6 +12005,7 @@ index ba0c58352..ad35e7575 100644 char *origpath = NULL; unsigned symlinks_max = 32; + const char *relpath = grub_env_get ("btrfs_relative_path"); ++ grub_size_t sz; - err = get_root (data, key, tree, type); - if (err) @@ -8797,7 +12075,7 @@ index ba0c58352..ad35e7575 100644 if (*type != GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY) { -@@ -1831,7 +2094,9 @@ find_path (struct grub_btrfs_data *data, +@@ -1831,7 +2095,9 @@ find_path (struct grub_btrfs_data *data, if (ctokenlen == 1 && ctoken[0] == '.') { @@ -8808,7 +12086,7 @@ index ba0c58352..ad35e7575 100644 continue; } if (ctokenlen == 2 && ctoken[0] == '.' && ctoken[1] == '.') -@@ -1862,8 +2127,9 @@ find_path (struct grub_btrfs_data *data, +@@ -1862,8 +2128,9 @@ find_path (struct grub_btrfs_data *data, *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; key->object_id = key_out.offset; @@ -8820,7 +12098,25 @@ index ba0c58352..ad35e7575 100644 continue; } -@@ -1932,7 +2198,9 @@ find_path (struct grub_btrfs_data *data, +@@ -1891,9 +2158,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); +@@ -1932,7 +2205,9 @@ find_path (struct grub_btrfs_data *data, return err; } @@ -8831,7 +12127,26 @@ index ba0c58352..ad35e7575 100644 if (cdirel->type == GRUB_BTRFS_DIR_ITEM_TYPE_SYMLINK) { struct grub_btrfs_inode inode; -@@ -1982,13 +2250,37 @@ find_path (struct grub_btrfs_data *data, +@@ -1955,8 +2230,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); +@@ -1982,13 +2265,37 @@ find_path (struct grub_btrfs_data *data, path = path_alloc = tmp; if (path[0] == '/') { @@ -8875,11 +12190,12 @@ index ba0c58352..ad35e7575 100644 } } continue; -@@ -2078,11 +2370,20 @@ grub_btrfs_dir (grub_device_t device, const char *path, +@@ -2078,11 +2385,21 @@ grub_btrfs_dir (grub_device_t device, const char *path, grub_uint64_t tree; grub_uint8_t type; grub_size_t est_size = 0; + char *new_path = NULL; ++ grub_size_t sz; if (!data) return grub_errno; @@ -8897,7 +12213,25 @@ index ba0c58352..ad35e7575 100644 if (err) { grub_btrfs_unmount (data); -@@ -2209,11 +2510,21 @@ grub_btrfs_open (struct grub_file *file, const char *name) +@@ -2119,9 +2436,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; +@@ -2209,11 +2532,21 @@ grub_btrfs_open (struct grub_file *file, const char *name) struct grub_btrfs_inode inode; grub_uint8_t type; struct grub_btrfs_key key_in; @@ -8920,7 +12254,7 @@ index ba0c58352..ad35e7575 100644 if (err) { grub_btrfs_unmount (data); -@@ -2256,6 +2567,20 @@ grub_btrfs_read (grub_file_t file, char *buf, grub_size_t len) +@@ -2256,6 +2589,20 @@ grub_btrfs_read (grub_file_t file, char *buf, grub_size_t len) data->tree, file->offset, buf, len); } @@ -8941,7 +12275,7 @@ index ba0c58352..ad35e7575 100644 static grub_err_t grub_btrfs_uuid (grub_device_t device, char **uuid) { -@@ -2267,15 +2592,7 @@ grub_btrfs_uuid (grub_device_t device, char **uuid) +@@ -2267,15 +2614,7 @@ grub_btrfs_uuid (grub_device_t device, char **uuid) if (!data) return grub_errno; @@ -8958,7 +12292,40 @@ index ba0c58352..ad35e7575 100644 grub_btrfs_unmount (data); -@@ -2396,6 +2713,618 @@ grub_btrfs_embed (grub_device_t device __attribute__ ((unused)), +@@ -2308,14 +2647,20 @@ struct embed_region { + }; + + /* +- * https://btrfs.wiki.kernel.org/index.php/Manpage/btrfs(5)#BOOTLOADER_SUPPORT ++ * https://btrfs.readthedocs.io/en/latest/btrfs-man5.html#man-btrfs5-bootloader-support ++ * or invoke "man 5 btrfs" and visit the "bootloader support" subsection. + * The first 1 MiB on each device is unused with the exception of primary + * superblock that is on the offset 64 KiB and spans 4 KiB. ++ * ++ * Note: If this table is modified, also update ++ * util/grub-editenv.c::fs_envblk_spec, which describes the file-system ++ * specific layout of reserved raw blocks used as environment blocks so that ++ * both stay consistent. + */ + + static const struct { + struct embed_region available; +- struct embed_region used[6]; ++ struct embed_region used[9]; + } btrfs_head = { + .available = {0, GRUB_DISK_KiB_TO_SECTORS (1024)}, /* The first 1 MiB. */ + .used = { +@@ -2323,6 +2668,9 @@ static const struct { + {GRUB_DISK_KiB_TO_SECTORS (64) - 1, 1}, /* Overflow guard. */ + {GRUB_DISK_KiB_TO_SECTORS (64), GRUB_DISK_KiB_TO_SECTORS (4)}, /* 4 KiB superblock. */ + {GRUB_DISK_KiB_TO_SECTORS (68), 1}, /* Overflow guard. */ ++ {(GRUB_ENV_BTRFS_OFFSET >> GRUB_DISK_SECTOR_BITS) - 1, 1}, /* Overflow guard. */ ++ {(GRUB_ENV_BTRFS_OFFSET >> GRUB_DISK_SECTOR_BITS), 1}, /* Environment Block. */ ++ {(GRUB_ENV_BTRFS_OFFSET >> GRUB_DISK_SECTOR_BITS) + 1, 1}, /* Overflow guard. */ + {GRUB_DISK_KiB_TO_SECTORS (1024) - 1, 1}, /* Overflow guard. */ + {0, 0} /* Array terminator. */ + } +@@ -2396,6 +2744,618 @@ grub_btrfs_embed (grub_device_t device __attribute__ ((unused)), } #endif @@ -9577,7 +12944,7 @@ index ba0c58352..ad35e7575 100644 static struct grub_fs grub_btrfs_fs = { .name = "btrfs", .fs_dir = grub_btrfs_dir, -@@ -2411,12 +3340,101 @@ static struct grub_fs grub_btrfs_fs = { +@@ -2411,12 +3371,102 @@ static struct grub_fs grub_btrfs_fs = { #endif }; @@ -9643,6 +13010,7 @@ index ba0c58352..ad35e7575 100644 + 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", @@ -9679,11 +13047,1195 @@ index ba0c58352..ad35e7575 100644 } + +// vim: si et sw=2: +diff --git a/grub-core/fs/cbfs.c b/grub-core/fs/cbfs.c +index 8ab7106af..b62c8777c 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,12 +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_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/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/cpio_common.c b/grub-core/fs/cpio_common.c +index 5d41b6fdb..45ac119a8 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; + +@@ -60,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) +@@ -76,7 +88,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 +125,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/ext2.c b/grub-core/fs/ext2.c +index e1cc5e62a..a5650c34c 100644 +--- a/grub-core/fs/ext2.c ++++ b/grub-core/fs/ext2.c +@@ -495,6 +495,11 @@ 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; ++ /* maximum number of extent entries in the inode's inline extent area */ ++ const grub_uint16_t max_inline_ext = sizeof (inode->blocks) / sizeof (*ext) - 1; /* Minus 1 extent header. */ ++ /* maximum number of extent entries in the external extent block */ ++ const grub_uint16_t max_external_ext = EXT2_BLOCK_SIZE(data) / sizeof (*ext) - 1; /* Minus 1 extent header. */ + + if (grub_ext4_find_leaf (data, (struct grub_ext4_extent_header *) inode->blocks.dir_blocks, + fileblock, &leaf) != GRUB_ERR_NONE) +@@ -508,7 +513,23 @@ grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) + return 0; + + 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); ++ ++ /* ++ * Determine the effective number of extent entries (nent) to process: ++ * If the extent header (leaf) is stored inline in the inode’s block ++ * area (i.e. at inode->blocks.dir_blocks), then only max_inline_ext ++ * entries can fit. ++ * Otherwise, if the header was read from an external extent block, use ++ * the larger limit, max_external_ext, based on the full block size. ++ */ ++ if (leaf == (struct grub_ext4_extent_header *) inode->blocks.dir_blocks) ++ nent = grub_min (nent, max_inline_ext); ++ else ++ nent = grub_min (nent, max_external_ext); ++ ++ for (i = 0; i < nent; i++) + { + if (fileblock < grub_le_to_cpu32 (ext[i].block)) + break; +@@ -1123,6 +1144,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 855e24618..72b4aa1e6 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+"); + +@@ -872,6 +873,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; +@@ -955,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) + { +@@ -965,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; + +@@ -994,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) + { +@@ -1007,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; + +@@ -1350,6 +1366,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 c5efed724..6e62b915d 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 91dc0e69c..ce7581dd5 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) +@@ -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 295822f69..3f203abcc 100644 +--- a/grub-core/fs/hfsplus.c ++++ b/grub-core/fs/hfsplus.c +@@ -405,7 +405,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); +@@ -1176,6 +1176,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/hfspluscomp.c b/grub-core/fs/hfspluscomp.c +index 48ae438d8..a80954ee6 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/iso9660.c b/grub-core/fs/iso9660.c +index 8c348b59a..c73cb9ce0 100644 +--- a/grub-core/fs/iso9660.c ++++ b/grub-core/fs/iso9660.c +@@ -551,6 +551,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; + } +@@ -625,9 +628,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; +@@ -1247,6 +1260,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 6f7c43904..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+"); + +@@ -41,6 +42,13 @@ 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 ++#define GRUB_JFS_DIR_MAX_SLOTS 128 ++ + struct grub_jfs_sblock + { + /* The magic for JFS. It should contain the string "JFS1". */ +@@ -203,9 +211,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 +@@ -258,7 +266,21 @@ static grub_dl_t my_mod; + + static grub_err_t grub_jfs_lookup_symlink (struct grub_jfs_data *data, grub_uint32_t ino); + +-static grub_int64_t ++/* ++ * 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_uint64_t + getblk (struct grub_jfs_treehead *treehead, + struct grub_jfs_tree_extent *extents, + int max_extents, +@@ -267,28 +289,33 @@ getblk (struct grub_jfs_treehead *treehead, + { + int found = -1; + 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++) + { ++ 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; + } + + if (found != -1) + { +- grub_int64_t ret = -1; ++ grub_uint64_t ret = 0; + struct + { + struct grub_jfs_treehead treehead; +@@ -297,13 +324,12 @@ 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) 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))) +@@ -311,19 +337,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) + { +@@ -354,7 +381,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; +@@ -453,6 +480,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; +@@ -468,7 +502,16 @@ 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); ++ 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 = 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. */ +@@ -486,7 +529,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)); +@@ -963,11 +1006,16 @@ static struct grub_fs grub_jfs_fs = + + GRUB_MOD_INIT(jfs) + { +- 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 5354951d1..4440fcca8 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+"); + +@@ -734,7 +735,11 @@ GRUB_MOD_INIT(minix) + #endif + #endif + { +- grub_fs_register (&grub_minix_fs); ++ if (!grub_is_lockdown ()) ++ { ++ grub_minix_fs.mod = mod; ++ grub_fs_register (&grub_minix_fs); ++ } + my_mod = mod; + } + +@@ -756,5 +761,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/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 fc7374ead..26e6077ff 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,11 +1232,16 @@ GRUB_MOD_INIT (nilfs2) + grub_nilfs2_dat_entry)); + COMPILE_TIME_ASSERT (1 << LOG_INODE_SIZE + == sizeof (struct grub_nilfs2_inode)); +- 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 de435aa14..960833a34 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+"); + +@@ -70,6 +71,170 @@ 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) ++{ ++ 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); ++ if (validate_attribute (next, end) == false) ++ return NULL; ++ ++ return next; ++} ++ ++ + grub_ntfscomp_func_t grub_ntfscomp_func; + + static grub_err_t +@@ -119,13 +284,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 +@@ -139,16 +311,18 @@ 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: +- 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) + { +@@ -172,15 +346,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", +@@ -191,9 +386,10 @@ 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); ++ 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)) +@@ -236,13 +432,21 @@ 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; +- while (at->attr_nxt < at->attr_end) ++ ++ /* 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)) + 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)) +@@ -263,7 +467,11 @@ 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) ++ ++ if (validate_attribute (pa, pa_end) == true) ++ pa = NULL; ++ ++ while (pa) + { + if (*pa != attr) + break; +@@ -279,7 +487,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; +@@ -295,7 +503,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; +@@ -311,7 +521,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; +@@ -363,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 */ +@@ -513,14 +724,17 @@ 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) ++ if (validate_attribute (pa, at->attr_end) == false) ++ pa = NULL; ++ ++ 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); +@@ -582,7 +796,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; + } +@@ -808,7 +1022,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); +@@ -839,7 +1055,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; +@@ -1204,6 +1422,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); + +@@ -1229,7 +1448,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)) +@@ -1320,11 +1542,16 @@ static struct grub_fs grub_ntfs_fs = + + GRUB_MOD_INIT (ntfs) + { +- 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/ntfscomp.c b/grub-core/fs/ntfscomp.c +index a009f2c2d..b68bf5e40 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+"); + +@@ -29,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 - +@@ -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/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 36b26ac98..42818c376 100644 +index 36b26ac98..ca47e0a43 100644 --- a/grub-core/fs/reiserfs.c +++ b/grub-core/fs/reiserfs.c -@@ -42,16 +42,6 @@ +@@ -39,19 +39,10 @@ + #include + #include + #include ++#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -9700,7 +14252,7 @@ index 36b26ac98..42818c376 100644 #define REISERFS_SUPER_BLOCK_OFFSET 0x10000 #define REISERFS_MAGIC_LEN 12 #define REISERFS_MAGIC_STRING "ReIsEr" -@@ -1076,7 +1066,7 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, +@@ -1076,7 +1067,7 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, grub_reiserfs_set_key_type (&key, GRUB_REISERFS_ANY, 2); initial_position = off; current_position = 0; @@ -9709,7 +14261,7 @@ index 36b26ac98..42818c376 100644 grub_dprintf ("reiserfs", "Reading from %lld to %lld (%lld instead of requested %ld)\n", (unsigned long long) initial_position, -@@ -1115,8 +1105,8 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, +@@ -1115,8 +1106,8 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, grub_dprintf ("reiserfs_blocktype", "D: %u\n", (unsigned) block); if (initial_position < current_position + item_size) { @@ -9720,7 +14272,7 @@ index 36b26ac98..42818c376 100644 - offset); grub_dprintf ("reiserfs", "Reading direct block %u from %u to %u...\n", -@@ -1161,9 +1151,9 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, +@@ -1161,9 +1152,9 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, grub_dprintf ("reiserfs_blocktype", "I: %u\n", (unsigned) block); if (current_position + block_size >= initial_position) { @@ -9733,7 +14285,7 @@ index 36b26ac98..42818c376 100644 - offset); grub_dprintf ("reiserfs", "Reading indirect block %u from %u to %u...\n", -@@ -1205,7 +1195,7 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, +@@ -1205,7 +1196,7 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, switch (found.type) { case GRUB_REISERFS_DIRECT: @@ -9742,7 +14294,7 @@ index 36b26ac98..42818c376 100644 grub_disk_read (found.data->disk, (found.block_number * block_size) / GRUB_DISK_SECTOR_SIZE, grub_le_to_cpu16 (found.header.item_location) + file->offset, -@@ -1224,12 +1214,12 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, +@@ -1224,12 +1215,12 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, item_size, (char *) indirect_block_ptr); if (grub_errno) goto fail; @@ -9757,11 +14309,466 @@ index 36b26ac98..42818c376 100644 grub_disk_read (found.data->disk, (grub_le_to_cpu32 (indirect_block_ptr[indirect_block]) * block_size) / GRUB_DISK_SECTOR_SIZE, file->offset % block_size, read, +@@ -1417,11 +1408,16 @@ static struct grub_fs grub_reiserfs_fs = + + GRUB_MOD_INIT(reiserfs) + { +- 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 1f7dcfca1..eafab03b2 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,10 +476,15 @@ static struct grub_fs grub_romfs_fs = + + GRUB_MOD_INIT(romfs) + { +- 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 983e88008..bad4ae8d1 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+"); +@@ -428,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); +@@ -779,11 +783,16 @@ static struct grub_fs grub_sfs_fs = + + GRUB_MOD_INIT(sfs) + { +- 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/squash4.c b/grub-core/fs/squash4.c +index a30e6ebe1..cf2bca822 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; + } + +@@ -580,6 +580,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) +@@ -595,7 +596,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, +@@ -816,10 +822,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); +@@ -1044,6 +1050,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 c551ed6b5..1eaa5349f 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,8 +77,10 @@ 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; + + for (reread = 0; reread < 3; reread++) + { +@@ -96,8 +99,13 @@ 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)); +- *name = grub_malloc (namesize + 1); ++ grub_size_t namesize; ++ ++ 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); + if (*name == NULL) + return grub_errno; + err = grub_disk_read (data->disk, 0, +@@ -116,16 +124,21 @@ 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)); +- if (data->linkname_alloc < linksize + 1) ++ grub_size_t linksize; ++ ++ 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) + { + 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, +@@ -148,7 +161,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]) +@@ -160,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. */ +@@ -202,6 +225,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; + } + +@@ -336,6 +363,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 b836e6107..3d5ee5af5 100644 +--- a/grub-core/fs/udf.c ++++ b/grub-core/fs/udf.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -1455,11 +1456,16 @@ static struct grub_fs grub_udf_fs = { + + GRUB_MOD_INIT (udf) + { +- 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 a354c92d9..8b5adbd48 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+"); + +@@ -463,7 +464,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) +@@ -899,7 +900,11 @@ GRUB_MOD_INIT(ufs1) + #endif + #endif + { +- grub_fs_register (&grub_ufs_fs); ++ if (!grub_is_lockdown ()) ++ { ++ grub_ufs_fs.mod = mod; ++ grub_fs_register (&grub_ufs_fs); ++ } + my_mod = mod; + } + +@@ -913,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/grub-core/fs/xfs.c b/grub-core/fs/xfs.c -index bc2224dbb..8e02ab4a3 100644 +index bc2224dbb..0519105aa 100644 --- a/grub-core/fs/xfs.c +++ b/grub-core/fs/xfs.c -@@ -902,6 +902,7 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, +@@ -88,7 +88,10 @@ GRUB_MOD_LICENSE ("GPLv3+"); + #define XFS_SB_FEAT_INCOMPAT_META_UUID (1 << 2) /* metadata UUID */ + #define XFS_SB_FEAT_INCOMPAT_BIGTIME (1 << 3) /* large timestamps */ + #define XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR (1 << 4) /* needs xfs_repair */ +-#define XFS_SB_FEAT_INCOMPAT_NREXT64 (1 << 5) /* large extent counters */ ++#define XFS_SB_FEAT_INCOMPAT_NREXT64 (1 << 5) /* large extent counters */ ++#define XFS_SB_FEAT_INCOMPAT_EXCHRANGE (1 << 6) /* exchangerange supported */ ++#define XFS_SB_FEAT_INCOMPAT_PARENT (1 << 7) /* parent pointers */ ++#define XFS_SB_FEAT_INCOMPAT_METADIR (1 << 8) /* metadata dir tree */ + + /* + * Directory entries with ftype are explicitly handled by GRUB code. +@@ -98,6 +101,15 @@ GRUB_MOD_LICENSE ("GPLv3+"); + * + * We do not currently verify metadata UUID, so it is safe to read filesystems + * with the XFS_SB_FEAT_INCOMPAT_META_UUID feature. ++ * ++ * We do not currently replay the log, so it is safe to read filesystems ++ * with the XFS_SB_FEAT_INCOMPAT_EXCHRANGE feature. ++ * ++ * We do not currently read directory parent pointers, so it is safe to read ++ * filesystems with the XFS_SB_FEAT_INCOMPAT_PARENT feature. ++ * ++ * We do not currently look at realtime or quota metadata, so it is safe to ++ * read filesystems with the XFS_SB_FEAT_INCOMPAT_METADIR feature. + */ + #define XFS_SB_FEAT_INCOMPAT_SUPPORTED \ + (XFS_SB_FEAT_INCOMPAT_FTYPE | \ +@@ -105,7 +117,10 @@ GRUB_MOD_LICENSE ("GPLv3+"); + XFS_SB_FEAT_INCOMPAT_META_UUID | \ + XFS_SB_FEAT_INCOMPAT_BIGTIME | \ + XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR | \ +- XFS_SB_FEAT_INCOMPAT_NREXT64) ++ XFS_SB_FEAT_INCOMPAT_NREXT64 | \ ++ XFS_SB_FEAT_INCOMPAT_EXCHRANGE | \ ++ XFS_SB_FEAT_INCOMPAT_PARENT | \ ++ XFS_SB_FEAT_INCOMPAT_METADIR) + + struct grub_xfs_sblock + { +@@ -327,6 +342,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; + } + +@@ -595,6 +612,17 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) + do + { + grub_uint64_t 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++) + { +@@ -705,6 +733,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) + { +@@ -726,7 +755,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; + +@@ -776,8 +810,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 (); +@@ -902,6 +943,7 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, grub_xfs_first_de(dir->data, dirblock); int entries = -1; char *end = dirblock + dirblk_size; @@ -9769,7 +14776,7 @@ index bc2224dbb..8e02ab4a3 100644 numread = grub_xfs_read_file (dir, 0, 0, blk << dirblk_log2, -@@ -912,6 +913,15 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, +@@ -912,11 +954,20 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, return 0; } @@ -9785,6 +14792,241 @@ index bc2224dbb..8e02ab4a3 100644 /* * Leaf and tail information are only in the data block if the number * of extents is 1. + */ +- if (dir->inode.nextents == grub_cpu_to_be32_compile_time (1)) ++ if (grub_xfs_get_inode_nextents(&dir->inode) == 1) + { + struct grub_xfs_dirblock_tail *tail = grub_xfs_dir_tail (dir->data, dirblock); + +@@ -970,7 +1021,7 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + * The expected number of directory entries is only tracked for the + * single extent case. + */ +- if (dir->inode.nextents == grub_cpu_to_be32_compile_time (1)) ++ if (grub_xfs_get_inode_nextents(&dir->inode) == 1) + { + /* Check if last direntry in this block is reached. */ + entries--; +@@ -1047,7 +1098,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); +@@ -1281,6 +1332,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 b5453e006..5ff647ffb 100644 +--- a/grub-core/fs/zfs/zfs.c ++++ b/grub-core/fs/zfs/zfs.c +@@ -614,6 +614,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,8 +725,13 @@ 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])); ++ if (!fill->children) ++ { ++ grub_free (type); ++ return grub_errno; ++ } + } + + for (i = 0; i < nelm; i++) +@@ -2387,6 +2394,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; +@@ -2448,8 +2456,19 @@ 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 (!buf) ++ { ++ grub_free (l); ++ return grub_errno; ++ } + if (zap_leaf_array_get (l, endian, blksft, + grub_zfs_to_cpu16 (le->le_name_chunk, + endian), +@@ -2465,6 +2484,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), +@@ -2872,6 +2897,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; +@@ -2923,7 +2949,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); +@@ -2960,6 +2997,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) + { +@@ -2993,7 +3031,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); +@@ -3263,6 +3309,8 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol, + filename = 0; + snapname = 0; + fsname = grub_strdup (fullpath); ++ if (!fsname) ++ return grub_errno; + } + else + { +@@ -3568,6 +3616,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); +@@ -3602,7 +3651,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)); +@@ -3678,8 +3732,13 @@ 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])); ++ if (!data->devices_attached) ++ { ++ grub_free (data); ++ return NULL; ++ } + data->n_devices_attached = 0; + err = scan_disk (dev, data, 1, &inserted); + if (err) +@@ -4193,6 +4252,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; + +@@ -4213,7 +4273,13 @@ 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); ++ if (!name2) ++ return grub_errno; ++ + name2[0] = '@'; + grub_memcpy (name2 + 1, name, grub_strlen (name) + 1); + ret = ctx->hook (name2, &info, ctx->hook_data); +@@ -4424,6 +4490,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/gdb/cstub.c b/grub-core/gdb/cstub.c index b64acd70f..99281472d 100644 --- a/grub-core/gdb/cstub.c @@ -9828,10 +15070,49 @@ index cc987a53a..ab457cb2b 100644 printf "error: %u: unrecognized input format\n", NR >"/dev/stderr"; error++; diff --git a/grub-core/gettext/gettext.c b/grub-core/gettext/gettext.c -index 7a1c14e4f..631af7a94 100644 +index 7a1c14e4f..1ca152ddd 100644 --- a/grub-core/gettext/gettext.c +++ b/grub-core/gettext/gettext.c -@@ -424,6 +424,13 @@ grub_gettext_init_ext (struct grub_gettext_context *ctx, +@@ -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; + +@@ -323,8 +328,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); +@@ -424,6 +429,13 @@ grub_gettext_init_ext (struct grub_gettext_context *ctx, grub_free (lang); } @@ -9845,6 +15126,50 @@ index 7a1c14e4f..631af7a94 100644 if (locale[0] == 'e' && locale[1] == 'n' && (locale[2] == '\0' || locale[2] == '_')) grub_errno = err = GRUB_ERR_NONE; +@@ -497,6 +509,8 @@ grub_cmd_translate (grub_command_t cmd __attribute__ ((unused)), + return 0; + } + ++static grub_command_t cmd; ++ + GRUB_MOD_INIT (gettext) + { + const char *lang; +@@ -516,13 +530,14 @@ GRUB_MOD_INIT (gettext) + grub_register_variable_hook ("locale_dir", NULL, read_main); + grub_register_variable_hook ("secondary_locale_dir", NULL, read_secondary); + +- grub_register_command_p1 ("gettext", grub_cmd_translate, +- N_("STRING"), +- /* TRANSLATORS: It refers to passing the string through gettext. +- So it's "translate" in the same meaning as in what you're +- doing now. +- */ +- N_("Translates the string with the current settings.")); ++ cmd = grub_register_command_p1 ("gettext", grub_cmd_translate, ++ N_("STRING"), ++ /* ++ * TRANSLATORS: It refers to passing the string through gettext. ++ * So it's "translate" in the same meaning as in what you're ++ * doing now. ++ */ ++ N_("Translates the string with the current settings.")); + + /* Reload .mo file information if lang changes. */ + grub_register_variable_hook ("lang", NULL, grub_gettext_env_write_lang); +@@ -535,6 +550,12 @@ 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_unregister_command (cmd); ++ + grub_gettext_delete_list (&main_context); + grub_gettext_delete_list (&secondary_context); + diff --git a/grub-core/io/bufio.c b/grub-core/io/bufio.c index a458c3aca..163773153 100644 --- a/grub-core/io/bufio.c @@ -10169,10 +15494,21 @@ index 670e213cf..d01963747 100644 { name = grub_env_get ("root"); diff --git a/grub-core/kern/disk.c b/grub-core/kern/disk.c -index 1eda58fe9..355b6579d 100644 +index 1eda58fe9..5747ad85c 100644 --- a/grub-core/kern/disk.c +++ b/grub-core/kern/disk.c -@@ -285,6 +285,8 @@ grub_disk_open (const char *name) +@@ -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; + +@@ -285,6 +289,8 @@ grub_disk_open (const char *name) return 0; } @@ -10181,7 +15517,7 @@ index 1eda58fe9..355b6579d 100644 return disk; } -@@ -310,8 +312,10 @@ grub_disk_close (grub_disk_t disk) +@@ -310,8 +316,10 @@ grub_disk_close (grub_disk_t disk) grub_free (disk->partition); disk->partition = part; } @@ -10192,14 +15528,89 @@ index 1eda58fe9..355b6579d 100644 } /* Small read (less than cache size and not pass across cache unit boundaries). +@@ -417,6 +425,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 +437,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 +459,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 +472,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 +507,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 +541,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/grub-core/kern/dl.c b/grub-core/kern/dl.c -index 0bf40caa6..2eaef7150 100644 +index 0bf40caa6..cb49bdc4b 100644 --- a/grub-core/kern/dl.c +++ b/grub-core/kern/dl.c -@@ -32,12 +32,21 @@ +@@ -32,12 +32,22 @@ #include #include #include ++#include +#include /* Platforms where modules are in a readonly area of memory. */ @@ -10218,7 +15629,7 @@ index 0bf40caa6..2eaef7150 100644 #pragma GCC diagnostic ignored "-Wcast-align" -@@ -115,6 +124,50 @@ grub_dl_resolve_symbol (const char *name) +@@ -115,6 +125,50 @@ grub_dl_resolve_symbol (const char *name) return 0; } @@ -10269,7 +15680,7 @@ index 0bf40caa6..2eaef7150 100644 /* Register a symbol with the name NAME and the address ADDR. */ grub_err_t grub_dl_register_symbol (const char *name, void *addr, int isfunc, -@@ -224,22 +277,37 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) +@@ -224,22 +278,37 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) { unsigned i; const Elf_Shdr *s; @@ -10311,7 +15722,7 @@ index 0bf40caa6..2eaef7150 100644 } #if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && \ -@@ -247,12 +315,18 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) +@@ -247,12 +316,18 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) err = grub_arch_dl_get_tramp_got_size (e, &tramp, &got); if (err) return err; @@ -10336,7 +15747,7 @@ index 0bf40caa6..2eaef7150 100644 #endif #ifdef GRUB_MACHINE_EMU -@@ -269,6 +343,9 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) +@@ -269,6 +344,9 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) i < e->e_shnum; i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize)) { @@ -10346,7 +15757,7 @@ index 0bf40caa6..2eaef7150 100644 if (s->sh_flags & SHF_ALLOC) { grub_dl_segment_t seg; -@@ -281,17 +358,19 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) +@@ -281,17 +359,19 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) { void *addr; @@ -10369,7 +15780,7 @@ index 0bf40caa6..2eaef7150 100644 break; } -@@ -300,7 +379,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) +@@ -300,7 +380,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) else seg->addr = 0; @@ -10378,7 +15789,7 @@ index 0bf40caa6..2eaef7150 100644 seg->section = i; seg->next = mod->segment; mod->segment = seg; -@@ -308,16 +387,17 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) +@@ -308,16 +388,17 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) } #if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && \ !defined (__loongarch__) @@ -10398,7 +15809,7 @@ index 0bf40caa6..2eaef7150 100644 return GRUB_ERR_NONE; } -@@ -330,6 +410,7 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e) +@@ -330,6 +411,7 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e) const char *str; Elf_Word size, entsize; @@ -10406,7 +15817,48 @@ index 0bf40caa6..2eaef7150 100644 for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); i < e->e_shnum; i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) -@@ -584,6 +665,7 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr) +@@ -532,7 +614,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; +@@ -543,10 +625,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; +@@ -557,10 +642,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) +@@ -584,6 +672,7 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr) Elf_Shdr *s; unsigned i; @@ -10414,7 +15866,7 @@ index 0bf40caa6..2eaef7150 100644 for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); i < e->e_shnum; i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) -@@ -592,22 +674,134 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr) +@@ -592,22 +681,137 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr) grub_dl_segment_t seg; grub_err_t err; @@ -10422,21 +15874,24 @@ index 0bf40caa6..2eaef7150 100644 - for (seg = mod->segment; seg; seg = seg->next) - if (seg->section == s->sh_info) - break; -+ seg = grub_dl_find_segment(mod, s->sh_info); -+ if (!seg) -+ continue; ++ if (!(s->sh_flags & SHF_INFO_LINK)) ++ continue; - if (seg) - { - if (!mod->symtab) - return grub_error (GRUB_ERR_BAD_MODULE, "relocation without symbol table"); -+ if (!mod->symtab) -+ return grub_error (GRUB_ERR_BAD_MODULE, "relocation without symbol table"); ++ seg = grub_dl_find_segment(mod, s->sh_info); ++ if (!seg) ++ continue; - err = grub_arch_dl_relocate_symbols (mod, ehdr, s, seg); - if (err) - return err; - } ++ if (!mod->symtab) ++ return grub_error (GRUB_ERR_BAD_MODULE, "relocation without symbol table"); ++ + err = grub_arch_dl_relocate_symbols (mod, ehdr, s, seg); + if (err) + return err; @@ -10561,7 +16016,7 @@ index 0bf40caa6..2eaef7150 100644 return GRUB_ERR_NONE; } -@@ -644,6 +838,7 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size) +@@ -644,6 +848,7 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size) mod->ref_count = 1; grub_dprintf ("modules", "relocating to %p\n", mod); @@ -10569,7 +16024,7 @@ index 0bf40caa6..2eaef7150 100644 /* Me, Vladimir Serbinenko, hereby I add this module check as per new GNU module policy. Note that this license check is informative only. Modules have to be licensed under GPLv3 or GPLv3+ (optionally -@@ -657,7 +852,8 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size) +@@ -657,7 +862,8 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size) || grub_dl_resolve_dependencies (mod, e) || grub_dl_load_segments (mod, e) || grub_dl_resolve_symbols (mod, e) @@ -10579,7 +16034,7 @@ index 0bf40caa6..2eaef7150 100644 { mod->fini = 0; grub_dl_unload (mod); -@@ -669,6 +865,8 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size) +@@ -669,6 +875,8 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size) grub_dprintf ("modules", "module name: %s\n", mod->name); grub_dprintf ("modules", "init function: %p\n", mod->init); @@ -10588,7 +16043,7 @@ index 0bf40caa6..2eaef7150 100644 if (grub_dl_add (mod)) { grub_dl_unload (mod); -@@ -706,6 +904,19 @@ grub_dl_load_file (const char *filename) +@@ -706,6 +914,19 @@ grub_dl_load_file (const char *filename) void *core = 0; grub_dl_t mod = 0; @@ -11437,7 +16892,7 @@ index 521220b49..7b9731b7e 100644 + return switchroot; +} diff --git a/grub-core/kern/err.c b/grub-core/kern/err.c -index 53c734de7..aebfe0cf8 100644 +index 53c734de7..ba04b57fb 100644 --- a/grub-core/kern/err.c +++ b/grub-core/kern/err.c @@ -33,15 +33,24 @@ static struct grub_error_saved grub_error_stack_items[GRUB_ERROR_STACK_SIZE]; @@ -11450,14 +16905,14 @@ index 53c734de7..aebfe0cf8 100644 + grub_err_t -grub_error (grub_err_t n, const char *fmt, ...) -+grub_error (grub_err_t n, const char *file, const int line, const char *fmt, ...) ++grub_error (grub_err_t n, const char *file, const char *function, const int line, const char *fmt, ...) { va_list ap; + int m; grub_errno = n; -+ m = grub_snprintf (grub_errmsg, sizeof (grub_errmsg), "%s:%d:", file, line); ++ m = grub_snprintf (grub_errmsg, sizeof (grub_errmsg), "%s:%s:%d:", file, function, line); + if (m < 0) + m = 0; + @@ -11468,10 +16923,16 @@ index 53c734de7..aebfe0cf8 100644 return n; diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c -index 750177248..75510df7c 100644 +index 750177248..f051bd48f 100644 --- a/grub-core/kern/file.c +++ b/grub-core/kern/file.c -@@ -30,6 +30,14 @@ void (*EXPORT_VAR (grub_grubnet_fini)) (void); +@@ -25,11 +25,20 @@ + #include + #include + #include ++#include + + void (*EXPORT_VAR (grub_grubnet_fini)) (void); grub_file_filter_t grub_file_filters[GRUB_FILE_FILTER_MAX]; @@ -11486,7 +16947,7 @@ index 750177248..75510df7c 100644 /* Get the device part of the filename NAME. It is enclosed by parentheses. */ char * grub_file_get_device_name (const char *name) -@@ -66,6 +74,8 @@ grub_file_open (const char *name, enum grub_file_type type) +@@ -66,6 +75,8 @@ grub_file_open (const char *name, enum grub_file_type type) const char *file_name; grub_file_filter_id_t filter; @@ -11495,7 +16956,20 @@ index 750177248..75510df7c 100644 /* Reset grub_errno before we start. */ grub_errno = GRUB_ERR_NONE; -@@ -122,6 +132,9 @@ grub_file_open (const char *name, enum grub_file_type type) +@@ -114,6 +125,12 @@ 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; ++ ++ if (file->fs->mod) ++ grub_dl_ref (file->fs->mod); ++ + file->name = grub_strdup (name); + grub_errno = GRUB_ERR_NONE; + +@@ -122,6 +139,9 @@ grub_file_open (const char *name, enum grub_file_type type) if (grub_file_filters[filter]) { last_file = file; @@ -11505,7 +16979,7 @@ index 750177248..75510df7c 100644 file = grub_file_filters[filter] (file, type); if (file && file != last_file) { -@@ -132,6 +145,8 @@ grub_file_open (const char *name, enum grub_file_type type) +@@ -132,6 +152,8 @@ grub_file_open (const char *name, enum grub_file_type type) if (!file) grub_file_close (last_file); @@ -11514,7 +16988,7 @@ index 750177248..75510df7c 100644 return file; fail: -@@ -143,6 +158,8 @@ grub_file_open (const char *name, enum grub_file_type type) +@@ -143,6 +165,8 @@ grub_file_open (const char *name, enum grub_file_type type) grub_free (file); @@ -11523,7 +16997,7 @@ index 750177248..75510df7c 100644 return 0; } -@@ -155,25 +172,30 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len) +@@ -155,25 +179,30 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len) grub_disk_read_hook_t read_hook; void *read_hook_data; @@ -11565,7 +17039,7 @@ index 750177248..75510df7c 100644 read_hook = file->read_hook; read_hook_data = file->read_hook_data; if (!file->read_hook) -@@ -194,11 +216,18 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len) +@@ -194,11 +223,21 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len) grub_err_t grub_file_close (grub_file_t file) { @@ -11573,6 +17047,9 @@ index 750177248..75510df7c 100644 if (file->fs->fs_close) (file->fs->fs_close) (file); ++ if (file->fs->mod) ++ grub_dl_unref (file->fs->mod); ++ if (file->device) grub_device_close (file->device); + @@ -11585,7 +17062,7 @@ index 750177248..75510df7c 100644 grub_free (file); return grub_errno; diff --git a/grub-core/kern/fs.c b/grub-core/kern/fs.c -index 7ad0aaf4e..f25bace62 100644 +index 7ad0aaf4e..9f6f4ef9d 100644 --- a/grub-core/kern/fs.c +++ b/grub-core/kern/fs.c @@ -74,6 +74,7 @@ grub_fs_probe (grub_device_t device) @@ -11596,6 +17073,46 @@ index 7ad0aaf4e..f25bace62 100644 grub_error_push (); /* The grub_error_push() does not touch grub_errmsg. */ grub_dprintf ("fs", _("error: %s.\n"), grub_errmsg); +@@ -215,12 +216,15 @@ grub_fs_blocklist_read (grub_file_t file, char *buf, grub_size_t len) + grub_disk_addr_t sector; + grub_off_t offset; + grub_ssize_t ret = 0; ++ grub_disk_t disk = file->device->disk; + + if (len > file->size - file->offset) + len = file->size - file->offset; + + sector = (file->offset >> GRUB_DISK_SECTOR_BITS); + offset = (file->offset & (GRUB_DISK_SECTOR_SIZE - 1)); ++ disk->read_hook = file->read_hook; ++ disk->read_hook_data = file->read_hook_data; + for (p = file->data; p->length && len > 0; p++) + { + if (sector < p->length) +@@ -232,9 +236,12 @@ grub_fs_blocklist_read (grub_file_t file, char *buf, grub_size_t len) + >> GRUB_DISK_SECTOR_BITS) > p->length - sector) + size = ((p->length - sector) << GRUB_DISK_SECTOR_BITS) - offset; + +- if (grub_disk_read (file->device->disk, p->offset + sector, offset, ++ if (grub_disk_read (disk, p->offset + sector, offset, + size, buf) != GRUB_ERR_NONE) +- return -1; ++ { ++ ret = -1; ++ break; ++ } + + ret += size; + len -= size; +@@ -244,6 +251,8 @@ grub_fs_blocklist_read (grub_file_t file, char *buf, grub_size_t len) + else + sector -= p->length; + } ++ disk->read_hook = NULL; ++ disk->read_hook_data = NULL; + + return ret; + } diff --git a/grub-core/kern/i386/backtrace.c b/grub-core/kern/i386/backtrace.c new file mode 100644 index 000000000..2413f9a57 @@ -11872,7 +17389,7 @@ index e74de3248..810a089a9 100644 /* Old Macs have no key repeat, newer ones have fully working one. The ones inbetween when repeated key generates an escaoe sequence diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c -index fb7d1a3ba..6c5f4fb77 100644 +index fb7d1a3ba..482cad209 100644 --- a/grub-core/kern/ieee1275/init.c +++ b/grub-core/kern/ieee1275/init.c @@ -49,8 +49,9 @@ @@ -11964,6 +17481,15 @@ index fb7d1a3ba..6c5f4fb77 100644 } GRUB_PACKED; struct pvr_entry +@@ -766,7 +782,7 @@ struct cas_vector + + /* + * Call ibm,client-architecture-support to try to get more RMA. +- * We ask for 512MB which should be enough to verify a distro kernel. ++ * We ask for 768MB which should be enough to verify a distro kernel. + * We ignore most errors: if we don't succeed we'll proceed with whatever + * memory we have. + */ @@ -775,6 +791,13 @@ grub_ieee1275_ibm_cas (void) { int rc; @@ -12025,6 +17551,15 @@ index fb7d1a3ba..6c5f4fb77 100644 struct cas_vector vector = { .pvr_list = { { 0x00000000, 0xffffffff } }, /* any processor */ +@@ -791,7 +854,7 @@ grub_ieee1275_ibm_cas (void) + .vec1 = 0x80, /* ignore */ + .vec2_size = 1 + sizeof (struct option_vector2) - 2, + .vec2 = { +- 0, 0, -1, -1, -1, -1, -1, 512, -1, 0, 48 ++ 0, 0, -1, -1, -1, -1, -1, 768, -1, 0, 48 + }, + .vec3_size = 2 - 1, + .vec3 = 0x00e0, /* ask for FP + VMX + DFP but don't halt if unsatisfied */ @@ -799,7 +862,7 @@ grub_ieee1275_ibm_cas (void) .vec4 = 0x0001, /* set required minimum capacity % to the lowest value */ .vec5_size = 1 + sizeof (struct option_vector5) - 2, @@ -12034,10 +17569,66 @@ index fb7d1a3ba..6c5f4fb77 100644 } }; -@@ -848,6 +911,19 @@ grub_claim_heap (void) - } - #endif +@@ -828,6 +891,10 @@ grub_claim_heap (void) + { + grub_err_t err; + grub_uint32_t total = HEAP_MAX_SIZE; ++#if defined(__powerpc__) ++ grub_uint32_t ibm_ca_support_reboot = 0; ++ grub_ssize_t actual; ++#endif + err = grub_ieee1275_total_mem (&rmo_top); + +@@ -840,10 +907,60 @@ grub_claim_heap (void) + grub_mm_add_region_fn = grub_ieee1275_mm_add_region; + + #if defined(__powerpc__) ++ /* Check if it's a CAS reboot with below property. If so, we will skip CAS call */ ++ if (grub_ieee1275_get_integer_property (grub_ieee1275_chosen, ++ "ibm,client-architecture-support-reboot", ++ &ibm_ca_support_reboot, ++ sizeof (ibm_ca_support_reboot), ++ &actual) >= 0) ++ grub_dprintf ("ieee1275", "ibm,client-architecture-support-reboot: %" PRIuGRUB_UINT32_T "\n", ++ ibm_ca_support_reboot); ++ + if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_CAN_TRY_CAS_FOR_MORE_MEMORY)) + { ++ /* ++ * If we have an error, don't call CAS. Just hope for the best. ++ * Along with the above, if the rmo_top is 512 MB or above. We ++ * will skip the CAS call. However, if we call CAS, the rmo_top ++ * will be set to 768 MB via CAS Vector2. But we need to call ++ * CAS with "rmo_top < 512 MB" to avoid the issue on the older ++ * Linux kernel, which still uses rmo_top as 512 MB. If we call ++ * CAS with a condition "rmo_top < 768 MB", it will result in an ++ * issue due to the IBM CAS reboot feature and we won't be able ++ * to boot the newer kernel. Whenever a reboot is detected as ++ * the CAS reboot by GRUB. It will boot the machine with the ++ * last booted kernel by reading the variable "boot-last-label" ++ * which has the info related to the last boot and it's specific ++ * to IBM PowerPC. Due to this, the machine will boot with the ++ * last booted kernel which has rmo_top as 512 MB. Also, if the ++ * reboot is detected as a CAS reboot, the GRUB will skip the CAS ++ * call. As the CAS has already been called earlier, so it is ++ * not required to call CAS even if the other conditions are met. ++ * This condition will also prevent a scenario where the machine ++ * get stuck in the CAS reboot loop while booting. A machine with ++ * an older kernel, having option_vector2 MIN_RMA as 512 MB in ++ * Linux prom_init.c and GRUB uses "rmo_top < 768 MB" condition ++ * for calling CAS. Due to their respective conditions, linux ++ * CAS and GRUB CAS will keep doing the CAS calls and change ++ * the MIN_RMA from 768(changed by GRUB) to 512(changed by Linux) ++ * to 768(changed by GRUB) to 512(changed by Linux) and so on, ++ * and the machine will stuck in this CAS reboot loop forever. ++ * IBM PAPR : https://openpower.foundation/specifications/linuxonpower/ ++ */ ++ if (!ibm_ca_support_reboot && err == GRUB_ERR_NONE && rmo_top < (512 * 1024 * 1024)) ++ grub_ieee1275_ibm_cas (); ++ } ++#endif ++ +#if defined(__powerpc__) + if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_CAN_TRY_CAS_FOR_MORE_MEMORY)) + { @@ -12045,16 +17636,13 @@ index fb7d1a3ba..6c5f4fb77 100644 + grub_err_t err; + + err = grub_ieee1275_total_mem (&rma_size); -+ /* if we have an error, don't call CAS, just hope for the best */ + /* if we have an error, don't call CAS, just hope for the best */ +- if (err == GRUB_ERR_NONE && rmo_top < (512 * 1024 * 1024)) + if (err == GRUB_ERR_NONE && rma_size < (512 * 1024 * 1024)) -+ grub_ieee1275_ibm_cas (); -+ } -+#endif -+ - grub_machine_mmap_iterate (heap_init, &total); - } + grub_ieee1275_ibm_cas (); + } #endif -@@ -892,6 +968,30 @@ grub_parse_cmdline (void) +@@ -892,6 +1009,30 @@ grub_parse_cmdline (void) } } @@ -12085,7 +17673,7 @@ index fb7d1a3ba..6c5f4fb77 100644 grub_addr_t grub_modbase; void -@@ -917,6 +1017,8 @@ grub_machine_init (void) +@@ -917,6 +1058,8 @@ grub_machine_init (void) #else grub_install_get_time_ms (grub_rtc_get_time_ms); #endif @@ -12175,10 +17763,26 @@ index 11b2beb2f..65616254e 100644 + return 0; +} diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c -index 731c07c29..8e89763f4 100644 +index 731c07c29..2e6b79ee3 100644 --- a/grub-core/kern/main.c +++ b/grub-core/kern/main.c -@@ -128,16 +128,24 @@ grub_set_prefix_and_root (void) +@@ -30,11 +30,15 @@ + #include + #include + #include ++#include + + #ifdef GRUB_MACHINE_PCBIOS + #include + #endif + ++static bool cli_disabled = false; ++static bool cli_need_auth = false; ++ + grub_addr_t + grub_modules_get_end (void) + { +@@ -128,16 +132,24 @@ grub_set_prefix_and_root (void) grub_machine_get_bootlocation (&fwdevice, &fwpath); @@ -12188,12 +17792,12 @@ index 731c07c29..8e89763f4 100644 - char *cmdpath; + char *fw_path; + char separator[3] = ")"; ++ ++ grub_dprintf ("fw_path", "\n"); ++ grub_dprintf ("fw_path", "fwdevice:\"%s\" fwpath:\"%s\"\n", fwdevice, fwpath); - cmdpath = grub_xasprintf ("(%s)%s", fwdevice, fwpath ? : ""); - if (cmdpath) -+ grub_dprintf ("fw_path", "\n"); -+ grub_dprintf ("fw_path", "fwdevice:\"%s\" fwpath:\"%s\"\n", fwdevice, fwpath); -+ + if (!grub_strncmp(fwdevice, "http", 4) && fwpath[0] != '/') + grub_strcpy(separator, ")/"); + @@ -12210,7 +17814,7 @@ index 731c07c29..8e89763f4 100644 } } -@@ -209,12 +217,66 @@ grub_set_prefix_and_root (void) +@@ -209,12 +221,66 @@ grub_set_prefix_and_root (void) { char *prefix_set; @@ -12281,6 +17885,56 @@ index 731c07c29..8e89763f4 100644 grub_env_set ("root", device); } +@@ -237,6 +303,39 @@ grub_load_normal_mode (void) + grub_command_execute ("normal", 0, 0); + } + ++bool ++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) ++{ ++ 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) + { +@@ -294,6 +393,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/mips/arc/init.c b/grub-core/kern/mips/arc/init.c index 2ed3ff319..5c40c3407 100644 --- a/grub-core/kern/mips/arc/init.c @@ -12337,10 +17991,10 @@ index b5477b87f..69488a34e 100644 grub_halt (); } diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c -index 7cee5d75c..98700423d 100644 +index 7cee5d75c..2568a5489 100644 --- a/grub-core/kern/misc.c +++ b/grub-core/kern/misc.c -@@ -26,6 +26,10 @@ +@@ -26,6 +26,11 @@ #include #include #include @@ -12348,10 +18002,11 @@ index 7cee5d75c..98700423d 100644 +#if DEBUG_WITH_TIMESTAMPS +#include +#endif ++#include union printf_arg { -@@ -182,6 +186,19 @@ int grub_err_printf (const char *fmt, ...) +@@ -182,6 +187,19 @@ int grub_err_printf (const char *fmt, ...) __attribute__ ((alias("grub_printf"))); #endif @@ -12371,7 +18026,12 @@ index 7cee5d75c..98700423d 100644 int grub_debug_enabled (const char * condition) { -@@ -235,9 +252,26 @@ grub_real_dprintf (const char *file, const int line, const char *condition, +@@ -231,14 +249,49 @@ grub_debug_enabled (const char * condition) + } + + void +-grub_real_dprintf (const char *file, const int line, const char *condition, ++grub_real_dprintf (const char *file, const char *function, const int line, const char *condition, const char *fmt, ...) { va_list args; @@ -12382,6 +18042,7 @@ index 7cee5d75c..98700423d 100644 if (grub_debug_enabled (condition)) { +- grub_printf ("%s:%d:%s: ", file, line, condition); +#if DEBUG_WITH_TIMESTAMPS + /* Don't print timestamp if last printed message isn't terminated yet */ + if (last_had_cr) { @@ -12395,13 +18056,14 @@ index 7cee5d75c..98700423d 100644 + else + last_had_cr = 0; +#endif - grub_printf ("%s:%d:%s: ", file, line, condition); - va_start (args, fmt); - grub_vprintf (fmt, args); -@@ -246,6 +280,24 @@ grub_real_dprintf (const char *file, const int line, const char *condition, - } - } - ++ grub_printf ("%s:%s:%d:%s: ", file, function, line, condition); ++ va_start (args, fmt); ++ grub_vprintf (fmt, args); ++ va_end (args); ++ grub_refresh (); ++ } ++} ++ +void +grub_qdprintf (const char *condition, const char *fmt, ...) +{ @@ -12413,17 +18075,79 @@ index 7cee5d75c..98700423d 100644 + + if (grub_strword (debug, "all") || grub_strword (debug, condition)) + { -+ va_start (args, fmt); -+ grub_vprintf (fmt, args); -+ va_end (args); -+ grub_refresh (); + va_start (args, fmt); + grub_vprintf (fmt, args); + va_end (args); +@@ -401,6 +454,68 @@ grub_strword (const char *haystack, const char *needle) + return 0; + } + ++char * ++grub_strtok_r (char *s, const char *delim, char **save_ptr) ++{ ++ char *token; ++ const char *c; ++ bool is_delim; ++ ++ if (s == NULL) ++ s = *save_ptr; ++ ++ /* Scan leading delimiters. */ ++ while (*s != '\0') ++ { ++ is_delim = false; ++ for (c = delim; *c != '\0'; c++) ++ { ++ if (*s == *c) ++ { ++ is_delim = true; ++ break; ++ } ++ } ++ if (is_delim == true) ++ s++; ++ else ++ break; + } ++ ++ if (*s == '\0') ++ { ++ *save_ptr = s; ++ return NULL; ++ } ++ ++ /* Find the end of the token. */ ++ token = s; ++ while (*s != '\0') ++ { ++ for (c = delim; *c != '\0'; c++) ++ { ++ if (*s == *c) ++ { ++ *s = '\0'; ++ *save_ptr = s + 1; ++ return token; ++ } ++ } ++ s++; ++ } ++ ++ *save_ptr = s; ++ return token; ++} ++ ++char * ++grub_strtok (char *s, const char *delim) ++{ ++ static char *last; ++ ++ return grub_strtok_r (s, delim, &last); +} + - #define PREALLOC_SIZE 255 - int -@@ -611,6 +663,36 @@ grub_reverse (char *str) + grub_isspace (int c) + { +@@ -611,6 +726,36 @@ grub_reverse (char *str) } } @@ -12460,7 +18184,89 @@ index 7cee5d75c..98700423d 100644 /* Divide N by D, return the quotient, and store the remainder in *R. */ grub_uint64_t grub_divmod64 (grub_uint64_t n, grub_uint64_t d, grub_uint64_t *r) -@@ -1301,7 +1383,12 @@ grub_printf_fmt_check (const char *fmt, const char *fmt_expected) +@@ -739,6 +884,9 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args, + COMPILE_TIME_ASSERT (sizeof (long) <= sizeof (long long)); + COMPILE_TIME_ASSERT (sizeof (long long) == sizeof (void *) + || sizeof (int) == sizeof (void *)); ++ COMPILE_TIME_ASSERT (sizeof (size_t) == sizeof (unsigned) ++ || sizeof (size_t) == sizeof (unsigned long) ++ || sizeof (size_t) == sizeof (unsigned long long)); + + fmt = fmt0; + while ((c = *fmt++) != 0) +@@ -773,11 +921,17 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args, + fmt++; + + c = *fmt++; ++ if (c == 'z') ++ { ++ c = *fmt++; ++ goto do_count; ++ } + if (c == 'l') + c = *fmt++; + if (c == 'l') + c = *fmt++; + ++ do_count: + switch (c) + { + case 'p': +@@ -830,7 +984,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 != '%') +@@ -848,7 +1002,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++; + } + +@@ -871,6 +1028,14 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args, + continue; + } + ++ if (c == 'z') ++ { ++ c = *fmt++; ++ if (sizeof (size_t) == sizeof (unsigned long)) ++ longfmt = 1; ++ else if (sizeof (size_t) == sizeof (unsigned long long)) ++ longfmt = 2; ++ } + if (c == 'l') + { + c = *fmt++; +@@ -1034,6 +1199,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; +@@ -1045,6 +1212,8 @@ grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt0, + } + + c = *fmt++; ++ if (c == 'z') ++ c = *fmt++; + if (c == 'l') + c = *fmt++; + if (c == 'l') +@@ -1301,7 +1470,12 @@ grub_printf_fmt_check (const char *fmt, const char *fmt_expected) void __attribute__ ((noreturn)) grub_abort (void) { @@ -12474,23 +18280,23 @@ index 7cee5d75c..98700423d 100644 #ifndef GRUB_UTIL if (grub_term_inputs) -@@ -1311,14 +1398,24 @@ grub_abort (void) +@@ -1311,14 +1485,24 @@ grub_abort (void) grub_getkey (); } - grub_exit (); + grub_exit (1); - } - ++} ++ +#if defined (__clang__) && !defined (GRUB_UTIL) +/* clang emits references to abort(). */ +void __attribute__ ((noreturn)) +abort (void) +{ + grub_abort (); -+} + } +#endif -+ + void grub_fatal (const char *fmt, ...) { @@ -12500,7 +18306,7 @@ index 7cee5d75c..98700423d 100644 va_start (ap, fmt); grub_vprintf (_(fmt), ap); va_end (ap); -@@ -1389,6 +1486,7 @@ grub_real_boot_time (const char *file, +@@ -1389,6 +1573,7 @@ grub_real_boot_time (const char *file, va_start (args, fmt); n->msg = grub_xvasprintf (fmt, args); @@ -12538,6 +18344,59 @@ index 027a25cd1..819bc5126 100644 /* Align up heap growth to make it friendly to CPU/MMU. */ if (grow > ~(grub_size_t) (GRUB_MM_HEAP_GROW_ALIGN - 1)) +diff --git a/grub-core/kern/partition.c b/grub-core/kern/partition.c +index edad9f9e4..c6a578cf4 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 +@@ -122,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. */ +@@ -208,7 +219,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/grub-core/kern/powerpc/dl.c b/grub-core/kern/powerpc/dl.c index 7b6418eab..0eb8bc5bd 100644 --- a/grub-core/kern/powerpc/dl.c @@ -12555,6 +18414,30 @@ index 7b6418eab..0eb8bc5bd 100644 +{ + return 1; +} +diff --git a/grub-core/kern/rescue_reader.c b/grub-core/kern/rescue_reader.c +index dcd7d4439..a71ada8fb 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_is_cli_need_auth ()) ++ { ++ 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/kern/riscv/dl.c b/grub-core/kern/riscv/dl.c index 896653bb4..1fa085b4a 100644 --- a/grub-core/kern/riscv/dl.c @@ -12576,6 +18459,34 @@ index 896653bb4..1fa085b4a 100644 + return 1; +#endif +} +diff --git a/grub-core/kern/riscv/efi/init.c b/grub-core/kern/riscv/efi/init.c +index 38795fe67..0d7de4f54 100644 +--- a/grub-core/kern/riscv/efi/init.c ++++ b/grub-core/kern/riscv/efi/init.c +@@ -33,16 +33,15 @@ grub_efi_get_time_ms (void) + grub_uint64_t tmr; + + #if __riscv_xlen == 64 +- asm volatile ("rdcycle %0" : "=r" (tmr)); ++ asm volatile ("rdtime %0" : "=r"(tmr)); + #else + grub_uint32_t lo, hi, tmp; +- asm volatile ( +- "1:\n" +- "rdcycleh %0\n" +- "rdcycle %1\n" +- "rdcycleh %2\n" +- "bne %0, %2, 1b" +- : "=&r" (hi), "=&r" (lo), "=&r" (tmp)); ++ asm volatile ("1:\n" ++ "rdtimeh %0\n" ++ "rdtime %1\n" ++ "rdtimeh %2\n" ++ "bne %0, %2, 1b" ++ : "=&r" (hi), "=&r" (lo), "=&r" (tmp)); + tmr = ((grub_uint64_t)hi << 32) | lo; + #endif + diff --git a/grub-core/kern/riscv/efi/startup.S b/grub-core/kern/riscv/efi/startup.S index f2a7b2b1e..781773136 100644 --- a/grub-core/kern/riscv/efi/startup.S @@ -12847,6 +18758,280 @@ index 73cfa94a2..fbf749e1d 100644 #define FDT_SUPPORTED_VERSION 17 #define FDT_BEGIN_NODE 0x00000001 +diff --git a/grub-core/lib/gnulib/filevercmp.c b/grub-core/lib/gnulib/filevercmp.c +new file mode 100644 +index 000000000..d546e7905 +--- /dev/null ++++ b/grub-core/lib/gnulib/filevercmp.c +@@ -0,0 +1,186 @@ ++/* Compare file names containing version numbers. ++ ++ Copyright (C) 1995 Ian Jackson ++ Copyright (C) 2001 Anthony Towns ++ Copyright (C) 2008-2022 Free Software Foundation, Inc. ++ ++ This file is free software: you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as ++ published by the Free Software Foundation, either version 3 of the ++ License, or (at your option) any later version. ++ ++ This file 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 Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public License ++ along with this program. If not, see . */ ++ ++#include ++#include "filevercmp.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* Return the length of a prefix of S that corresponds to the suffix ++ defined by this extended regular expression in the C locale: ++ (\.[A-Za-z~][A-Za-z0-9~]*)*$ ++ If *LEN is -1, S is a string; set *LEN to S's length. ++ Otherwise, *LEN should be nonnegative, S is a char array, ++ and *LEN does not change. */ ++static idx_t ++file_prefixlen (char const *s, ptrdiff_t *len) ++{ ++ size_t n = *len; /* SIZE_MAX if N == -1. */ ++ ++ for (idx_t i = 0; ; i++) ++ { ++ idx_t prefixlen = i; ++ while (i + 1 < n && s[i] == '.' && (c_isalpha (s[i + 1]) ++ || s[i + 1] == '~')) ++ for (i += 2; i < n && (c_isalnum (s[i]) || s[i] == '~'); i++) ++ continue; ++ ++ if (*len < 0 ? !s[i] : i == n) ++ { ++ *len = i; ++ return prefixlen; ++ } ++ } ++} ++ ++/* Return a version sort comparison value for S's byte at position POS. ++ S has length LEN. If POS == LEN, sort before all non-'~' bytes. */ ++ ++static int ++order (char const *s, idx_t pos, idx_t len) ++{ ++ if (pos == len) ++ return -1; ++ ++ unsigned char c = s[pos]; ++ if (c_isdigit (c)) ++ return 0; ++ else if (c_isalpha (c)) ++ return c; ++ else if (c == '~') ++ return -2; ++ else ++ { ++ verify (UCHAR_MAX <= (INT_MAX - 1 - 2) / 2); ++ return c + UCHAR_MAX + 1; ++ } ++} ++ ++/* slightly modified verrevcmp function from dpkg ++ S1, S2 - compared char array ++ S1_LEN, S2_LEN - length of arrays to be scanned ++ ++ This implements the algorithm for comparison of version strings ++ specified by Debian and now widely adopted. The detailed ++ specification can be found in the Debian Policy Manual in the ++ section on the 'Version' control field. This version of the code ++ implements that from s5.6.12 of Debian Policy v3.8.0.1 ++ https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version */ ++static int _GL_ATTRIBUTE_PURE ++verrevcmp (const char *s1, idx_t s1_len, const char *s2, idx_t s2_len) ++{ ++ idx_t s1_pos = 0; ++ idx_t s2_pos = 0; ++ while (s1_pos < s1_len || s2_pos < s2_len) ++ { ++ int first_diff = 0; ++ while ((s1_pos < s1_len && !c_isdigit (s1[s1_pos])) ++ || (s2_pos < s2_len && !c_isdigit (s2[s2_pos]))) ++ { ++ int s1_c = order (s1, s1_pos, s1_len); ++ int s2_c = order (s2, s2_pos, s2_len); ++ if (s1_c != s2_c) ++ return s1_c - s2_c; ++ s1_pos++; ++ s2_pos++; ++ } ++ while (s1_pos < s1_len && s1[s1_pos] == '0') ++ s1_pos++; ++ while (s2_pos < s2_len && s2[s2_pos] == '0') ++ s2_pos++; ++ while (s1_pos < s1_len && s2_pos < s2_len ++ && c_isdigit (s1[s1_pos]) && c_isdigit (s2[s2_pos])) ++ { ++ if (!first_diff) ++ first_diff = s1[s1_pos] - s2[s2_pos]; ++ s1_pos++; ++ s2_pos++; ++ } ++ if (s1_pos < s1_len && c_isdigit (s1[s1_pos])) ++ return 1; ++ if (s2_pos < s2_len && c_isdigit (s2[s2_pos])) ++ return -1; ++ if (first_diff) ++ return first_diff; ++ } ++ return 0; ++} ++ ++/* Compare version strings S1 and S2. ++ See filevercmp.h for function description. */ ++int ++filevercmp (const char *s1, const char *s2) ++{ ++ return filenvercmp (s1, -1, s2, -1); ++} ++ ++/* Compare versions A (of length ALEN) and B (of length BLEN). ++ See filevercmp.h for function description. */ ++int ++filenvercmp (char const *a, ptrdiff_t alen, char const *b, ptrdiff_t blen) ++{ ++ /* Special case for empty versions. */ ++ bool aempty = alen < 0 ? !a[0] : !alen; ++ bool bempty = blen < 0 ? !b[0] : !blen; ++ if (aempty) ++ return -!bempty; ++ if (bempty) ++ return 1; ++ ++ /* Special cases for leading ".": "." sorts first, then "..", then ++ other names with leading ".", then other names. */ ++ if (a[0] == '.') ++ { ++ if (b[0] != '.') ++ return -1; ++ ++ bool adot = alen < 0 ? !a[1] : alen == 1; ++ bool bdot = blen < 0 ? !b[1] : blen == 1; ++ if (adot) ++ return -!bdot; ++ if (bdot) ++ return 1; ++ ++ bool adotdot = a[1] == '.' && (alen < 0 ? !a[2] : alen == 2); ++ bool bdotdot = b[1] == '.' && (blen < 0 ? !b[2] : blen == 2); ++ if (adotdot) ++ return -!bdotdot; ++ if (bdotdot) ++ return 1; ++ } ++ else if (b[0] == '.') ++ return 1; ++ ++ /* Cut file suffixes. */ ++ idx_t aprefixlen = file_prefixlen (a, &alen); ++ idx_t bprefixlen = file_prefixlen (b, &blen); ++ ++ /* If both suffixes are empty, a second pass would return the same thing. */ ++ bool one_pass_only = aprefixlen == alen && bprefixlen == blen; ++ ++ int result = verrevcmp (a, aprefixlen, b, bprefixlen); ++ ++ /* Return the initial result if nonzero, or if no second pass is needed. ++ Otherwise, restore the suffixes and try again. */ ++ return result || one_pass_only ? result : verrevcmp (a, alen, b, blen); ++} +diff --git a/grub-core/lib/gnulib/filevercmp.h b/grub-core/lib/gnulib/filevercmp.h +new file mode 100644 +index 000000000..5a3367767 +--- /dev/null ++++ b/grub-core/lib/gnulib/filevercmp.h +@@ -0,0 +1,76 @@ ++/* Compare file names containing version numbers. ++ ++ Copyright (C) 1995 Ian Jackson ++ Copyright (C) 2001 Anthony Towns ++ Copyright (C) 2008-2022 Free Software Foundation, Inc. ++ ++ This file is free software: you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as ++ published by the Free Software Foundation, either version 3 of the ++ License, or (at your option) any later version. ++ ++ This file 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 Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public License ++ along with this program. If not, see . */ ++ ++#ifndef FILEVERCMP_H ++#define FILEVERCMP_H ++ ++#include ++ ++/* Compare strings A and B as file names containing version numbers, ++ and return an integer that is negative, zero, or positive depending ++ on whether A compares less than, equal to, or greater than B. ++ ++ Use the following version sort algorithm: ++ ++ 1. Compare the strings' maximal-length non-digit prefixes lexically. ++ If there is a difference return that difference. ++ Otherwise discard the prefixes and continue with the next step. ++ ++ 2. Compare the strings' maximal-length digit prefixes, using ++ numeric comparison of the numbers represented by each prefix. ++ (Treat an empty prefix as zero; this can happen only at string end.) ++ If there is a difference, return that difference. ++ Otherwise discard the prefixes and continue with the next step. ++ ++ 3. If both strings are empty, return 0. Otherwise continue with step 1. ++ ++ In version sort, lexical comparison is left to right, byte by byte, ++ using the byte's numeric value (0-255), except that: ++ ++ 1. ASCII letters sort before other bytes. ++ 2. A tilde sorts before anything, even an empty string. ++ ++ In addition to the version sort rules, the following strings have ++ special priority and sort before all other strings (listed in order): ++ ++ 1. The empty string. ++ 2. ".". ++ 3. "..". ++ 4. Strings starting with "." sort before other strings. ++ ++ Before comparing two strings where both begin with non-".", ++ or where both begin with "." but neither is "." or "..", ++ suffixes matching the C-locale extended regular expression ++ (\.[A-Za-z~][A-Za-z0-9~]*)*$ are removed and the strings compared ++ without them, using version sort without special priority; ++ if they do not compare equal, this comparison result is used and ++ the suffixes are effectively ignored. Otherwise, the entire ++ strings are compared using version sort. ++ ++ This function is intended to be a replacement for strverscmp. */ ++int filevercmp (char const *a, char const *b) _GL_ATTRIBUTE_PURE; ++ ++/* Like filevercmp, except compare the byte arrays A (of length ALEN) ++ and B (of length BLEN) so that A and B can contain '\0', which ++ sorts just before '\1'. But if ALEN is -1 treat A as a string ++ terminated by '\0', and similarly for BLEN. */ ++int filenvercmp (char const *a, ptrdiff_t alen, char const *b, ptrdiff_t blen) ++ _GL_ATTRIBUTE_PURE; ++ ++#endif /* FILEVERCMP_H */ diff --git a/grub-core/lib/i386/backtrace.c b/grub-core/lib/i386/backtrace.c deleted file mode 100644 index c3e03c727..000000000 @@ -22659,6 +28844,126 @@ index 000000000..dbacd563d + grub_free (em); + return ret; +} +diff --git a/grub-core/lib/posix_wrap/c-ctype.h b/grub-core/lib/posix_wrap/c-ctype.h +new file mode 100644 +index 000000000..5f8fc8ce3 +--- /dev/null ++++ b/grub-core/lib/posix_wrap/c-ctype.h +@@ -0,0 +1,114 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2024 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 . ++ */ ++ ++#ifndef GRUB_POSIX_C_CTYPE_H ++#define GRUB_POSIX_C_CTYPE_H 1 ++ ++#include ++ ++static inline bool ++c_isspace (int c) ++{ ++ return !!grub_isspace (c); ++} ++ ++static inline bool ++c_isdigit (int c) ++{ ++ return !!grub_isdigit (c); ++} ++ ++static inline bool ++c_islower (int c) ++{ ++ return !!grub_islower (c); ++} ++ ++static inline bool ++c_isascii (int c) ++{ ++ return !(c & ~0x7f); ++} ++ ++static inline bool ++c_isupper (int c) ++{ ++ return !!grub_isupper (c); ++} ++ ++static inline bool ++c_isxdigit (int c) ++{ ++ return !!grub_isxdigit (c); ++} ++ ++static inline bool ++c_isprint (int c) ++{ ++ return !!grub_isprint (c); ++} ++ ++static inline bool ++c_iscntrl (int c) ++{ ++ return !grub_isprint (c); ++} ++ ++static inline bool ++c_isgraph (int c) ++{ ++ return grub_isprint (c) && !grub_isspace (c); ++} ++ ++static inline bool ++c_isalnum (int c) ++{ ++ return grub_isalpha (c) || grub_isdigit (c); ++} ++ ++static inline bool ++c_ispunct (int c) ++{ ++ return grub_isprint (c) && !grub_isspace (c) && !c_isalnum (c); ++} ++ ++static inline bool ++c_isalpha (int c) ++{ ++ return !!grub_isalpha (c); ++} ++ ++static inline bool ++c_isblank (int c) ++{ ++ return c == ' ' || c == '\t'; ++} ++ ++static inline int ++c_tolower (int c) ++{ ++ return grub_tolower (c); ++} ++ ++static inline int ++c_toupper (int c) ++{ ++ return grub_toupper (c); ++} ++ ++#endif diff --git a/grub-core/lib/posix_wrap/limits.h b/grub-core/lib/posix_wrap/limits.h index 26918c8a0..4be7b4080 100644 --- a/grub-core/lib/posix_wrap/limits.h @@ -22687,6 +28992,38 @@ index f5279756a..14e4efdd0 100644 +#define strtoull grub_strtoull + #endif +diff --git a/grub-core/lib/posix_wrap/string.h b/grub-core/lib/posix_wrap/string.h +index 1adb450b5..d3e400d50 100644 +--- a/grub-core/lib/posix_wrap/string.h ++++ b/grub-core/lib/posix_wrap/string.h +@@ -84,6 +84,27 @@ memchr (const void *s, int c, grub_size_t n) + return grub_memchr (s, c, n); + } + ++static inline char * ++strncat (char *dest, const char *src, grub_size_t n) ++{ ++ const char *end; ++ char *str = dest; ++ grub_size_t src_len; ++ ++ dest += grub_strlen (dest); ++ ++ end = grub_memchr (src, '\0', n); ++ if (end != NULL) ++ src_len = (grub_size_t) (end - src); ++ else ++ src_len = n; ++ ++ dest[src_len] = '\0'; ++ grub_memcpy (dest, src, src_len); ++ ++ return str; ++} ++ + #define memcmp grub_memcmp + #define memcpy grub_memcpy + #define memmove grub_memmove diff --git a/grub-core/lib/posix_wrap/sys/types.h b/grub-core/lib/posix_wrap/sys/types.h index eeda543c4..2f3e86549 100644 --- a/grub-core/lib/posix_wrap/sys/types.h @@ -22735,19 +29072,17 @@ index 562bd2e3e..5fee7f2a1 100644 { grub_size_t ds = (s + SECTOR_SIZE - 1 - i) / SECTOR_SIZE; diff --git a/grub-core/loader/arm64/xen_boot.c b/grub-core/loader/arm64/xen_boot.c -index 26e1472c9..5d7c8603d 100644 +index 26e1472c9..881011ec4 100644 --- a/grub-core/loader/arm64/xen_boot.c +++ b/grub-core/loader/arm64/xen_boot.c -@@ -252,8 +252,10 @@ xen_boot (void) +@@ -252,8 +252,8 @@ xen_boot (void) return err; return grub_arch_efi_linux_boot_image (xen_hypervisor->start, - xen_hypervisor->size, - xen_hypervisor->cmdline); + xen_hypervisor->size, -+ xen_hypervisor->cmdline, -+ 0); -+ ++ xen_hypervisor->cmdline); } static void @@ -22783,7 +29118,7 @@ index a0b61a240..35d53c5f8 100644 grub_unregister_command (cmd); } diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c -index 1de98f783..7652f5a92 100644 +index 1de98f783..a004020eb 100644 --- a/grub-core/loader/efi/chainloader.c +++ b/grub-core/loader/efi/chainloader.c @@ -24,6 +24,7 @@ @@ -23689,7 +30024,7 @@ index 1de98f783..7652f5a92 100644 + grub_free (devname); + + /* if device is loopback, use underlying dev */ -+ if (dev && dev->disk->dev->id == GRUB_DISK_DEVICE_LOOPBACK_ID) ++ if (dev && dev->disk && dev->disk->dev->id == GRUB_DISK_DEVICE_LOOPBACK_ID) + { + struct grub_loopback *d; + orig_dev = dev; @@ -23853,19 +30188,19 @@ index 1de98f783..7652f5a92 100644 - for (i = 1; i < argc; i++) - { - char *p8; -- -- p8 = argv[i]; -- while (*p8) -- *(p16++) = *(p8++); + /* We're finished with the source image buffer and file path now */ + b->free_pages (address, pages); + grub_free (file_path); +- p8 = argv[i]; +- while (*p8) +- *(p16++) = *(p8++); ++ grub_loader_set_ex (grub_chainloader_boot, grub_chainloader_unload, image_handle, 0); + - *(p16++) = ' '; - } - *(--p16) = 0; -+ grub_loader_set_ex (grub_chainloader_boot, grub_chainloader_unload, image_handle, 0); - +- - loaded_image->load_options = cmdline; - loaded_image->load_options_size = len; + return 0; @@ -23891,15 +30226,12 @@ index 1de98f783..7652f5a92 100644 if (dev) grub_device_close (dev); -@@ -419,10 +1191,13 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), +@@ -419,10 +1191,10 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), grub_free (file_path); if (address) - b->free_pages (address, pages); + grub_efi_free_pages (address, pages); -+ -+ if (cmdline) -+ grub_free (cmdline); if (image_handle != NULL) - b->unload_image (image_handle); @@ -23921,40 +30253,45 @@ index 439964b9c..e08d8738a 100644 static void *fdt; diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c -index bfbd95aee..5889e3f36 100644 +index bfbd95aee..fc7935453 100644 --- a/grub-core/loader/efi/linux.c +++ b/grub-core/loader/efi/linux.c -@@ -25,10 +25,14 @@ - #include - #include - #include -+#include - #include -+#include +@@ -29,13 +29,16 @@ #include #include -+#include #include +#include #include #include #include -@@ -39,8 +43,11 @@ GRUB_MOD_LICENSE ("GPLv3+"); ++#include + #include + + GRUB_MOD_LICENSE ("GPLv3+"); + ++#if !defined(__i386__) && !defined(__x86_64__) static grub_dl_t my_mod; static int loaded; -+static void *kernel_alloc_addr; -+static grub_uint32_t kernel_alloc_pages; - static void *kernel_addr; - static grub_uint64_t kernel_size; -+static grub_uint32_t handover_offset; - - static char *linux_args; - static grub_uint32_t cmdline_size; -@@ -87,6 +94,201 @@ static grub_efi_load_file2_t initrd_lf2 = { - grub_efi_initrd_load_file2 +@@ -70,12 +73,6 @@ static initrd_media_device_path_t initrd_lf2_device_path = { + } }; +-extern grub_err_t +-grub_cmd_linux_x86_legacy (grub_command_t cmd, int argc, char *argv[]); +- +-extern grub_err_t +-grub_cmd_initrd_x86_legacy (grub_command_t cmd, int argc, char *argv[]); +- + static grub_efi_status_t __grub_efi_api + grub_efi_initrd_load_file2 (grub_efi_load_file2_t *this, + grub_efi_device_path_t *device_path, +@@ -86,6 +83,279 @@ grub_efi_initrd_load_file2 (grub_efi_load_file2_t *this, + static grub_efi_load_file2_t initrd_lf2 = { + grub_efi_initrd_load_file2 + }; ++#endif ++ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-align" +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" @@ -24063,22 +30400,133 @@ index bfbd95aee..5889e3f36 100644 +typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *); + +grub_err_t -+grub_efi_linux_boot (grub_addr_t k_address, grub_size_t k_size, ++grub_efi_mem_set_att(grub_addr_t k_address, grub_size_t k_size, ++ grub_size_t k_start, int nx_supported) ++{ ++ grub_addr_t k_start_address = k_address + k_start; ++ ++ grub_uint64_t default_set_attrs = GRUB_MEM_ATTR_R | GRUB_MEM_ATTR_W | GRUB_MEM_ATTR_X; ++ grub_uint64_t default_clear_attrs = 0; ++ grub_uint64_t stack_set_attrs = default_set_attrs; ++ grub_uint64_t stack_clear_attrs = default_clear_attrs; ++ grub_uint64_t kernel_set_attrs = default_set_attrs; ++ grub_uint64_t kernel_clear_attrs = default_clear_attrs; ++ grub_uint64_t attrs; ++ ++ struct grub_msdos_image_header *header; ++ struct grub_pe_image_header *pe_image_header; ++ struct grub_pe32_coff_header *coff_header; ++ struct grub_pe32_section_table *section, *sections; ++ grub_uint16_t i; ++ grub_size_t sz; ++ ++ header = (struct grub_msdos_image_header *)k_address; ++ ++ if (grub_add ((grub_addr_t) header, header->pe_image_header_offset, &sz)) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("Error on PE image header address calculation")); ++ ++ pe_image_header = (struct grub_pe_image_header *) (sz); ++ ++ if (pe_image_header > (k_address + k_size)) ++ return grub_error (GRUB_ERR_BAD_OS, N_("PE image header address is invalid")); ++ ++ if (grub_memcmp (pe_image_header->signature, GRUB_PE32_SIGNATURE, ++ GRUB_PE32_SIGNATURE_SIZE) != 0) ++ return grub_error (GRUB_ERR_BAD_OS, N_("kernel PE magic is invalid")); ++ ++ coff_header = &(pe_image_header->coff_header); ++ grub_dprintf ("nx", "coff_header 0x%"PRIxGRUB_ADDR" machine %08x\n", (grub_addr_t)coff_header, coff_header->machine); ++ ++ if (grub_add ((grub_addr_t) coff_header, sizeof (*coff_header), &sz) || ++ grub_add (sz, coff_header->optional_header_size, &sz)) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("Error on PE sections calculation")); ++ ++ sections = (struct grub_pe32_section_table *) (sz); ++ ++ if (sections > (k_address + k_size)) ++ return grub_error (GRUB_ERR_BAD_OS, N_("Section address is invalid")); ++ ++ /* Parse the PE, remove W for code section, remove X for data sections, RO for the rest */ ++ for (i = 0, section = sections; i < coff_header->num_sections; i++, section++) ++ { ++ kernel_set_attrs = default_set_attrs; ++ kernel_clear_attrs = default_clear_attrs; ++ ++ if (nx_supported) ++ { ++ if (section->characteristics & GRUB_PE32_SCN_MEM_EXECUTE) ++ { ++ /* RX section */ ++ kernel_set_attrs &= ~GRUB_MEM_ATTR_W; ++ kernel_clear_attrs |= GRUB_MEM_ATTR_W; ++ } ++ else if (section->characteristics & GRUB_PE32_SCN_MEM_WRITE) ++ { ++ /* RW section */ ++ kernel_set_attrs &= ~GRUB_MEM_ATTR_X; ++ kernel_clear_attrs |= GRUB_MEM_ATTR_X; ++ } ++ else ++ { ++ /* RO section */ ++ kernel_set_attrs &= ~GRUB_MEM_ATTR_W & ~GRUB_MEM_ATTR_X; ++ kernel_clear_attrs |= GRUB_MEM_ATTR_X | GRUB_MEM_ATTR_W ; ++ } ++ } ++ ++ /* Make sure we are inside range */ ++ if (grub_add ((grub_addr_t) k_address, section->raw_data_offset, &sz)) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("Error on PE Executable section calculation")); ++ ++ grub_update_mem_attrs (sz, section->raw_data_size, kernel_set_attrs, kernel_clear_attrs); ++ ++ grub_get_mem_attrs (sz, 4096, &attrs); ++ grub_dprintf ("nx", "permissions for section %s 0x%"PRIxGRUB_ADDR" are %s%s%s\n", ++ section->name, ++ (grub_addr_t)sz, ++ (attrs & GRUB_MEM_ATTR_R) ? "r" : "-", ++ (attrs & GRUB_MEM_ATTR_W) ? "w" : "-", ++ (attrs & GRUB_MEM_ATTR_X) ? "x" : "-"); ++ } ++ ++ if (grub_stack_addr != (grub_addr_t)-1ll) ++ { ++ if (nx_supported) ++ { ++ stack_set_attrs &= ~GRUB_MEM_ATTR_X; ++ stack_clear_attrs |= GRUB_MEM_ATTR_X; ++ } ++ ++ grub_dprintf ("nx", "Setting attributes for stack at 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to rw%c\n", ++ grub_stack_addr, grub_stack_addr + grub_stack_size - 1, ++ (stack_set_attrs & GRUB_MEM_ATTR_X) ? 'x' : '-'); ++ ++ grub_update_mem_attrs (grub_stack_addr, grub_stack_size, ++ stack_set_attrs, stack_clear_attrs); ++ ++ grub_get_mem_attrs (grub_stack_addr, 4096, &attrs); ++ grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n", ++ grub_stack_addr, ++ (attrs & GRUB_MEM_ATTR_R) ? "r" : "-", ++ (attrs & GRUB_MEM_ATTR_W) ? "w" : "-", ++ (attrs & GRUB_MEM_ATTR_X) ? "x" : "-"); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++ ++grub_err_t ++grub_efi_linux_boot (grub_addr_t k_address, grub_size_t k_size, grub_size_t k_start, + grub_off_t h_offset, void *k_params, + int nx_supported) +{ ++ grub_addr_t k_start_address = k_address + k_start; + grub_efi_loaded_image_t *loaded_image = NULL; + handover_func hf; + int offset = 0; -+ grub_uint64_t stack_set_attrs = GRUB_MEM_ATTR_R | -+ GRUB_MEM_ATTR_W | -+ GRUB_MEM_ATTR_X; -+ grub_uint64_t stack_clear_attrs = 0; -+ grub_uint64_t kernel_set_attrs = stack_set_attrs; -+ grub_uint64_t kernel_clear_attrs = stack_clear_attrs; -+ grub_uint64_t attrs; + int nx_required = 0; -+ ++ +#ifdef __x86_64__ + offset = 512; +#endif @@ -24102,58 +30550,23 @@ index bfbd95aee..5889e3f36 100644 + if (nx_required && !nx_supported) + return grub_error (GRUB_ERR_BAD_OS, N_("kernel does not support NX loading required by policy")); + -+ if (nx_supported) -+ { -+ kernel_set_attrs &= ~GRUB_MEM_ATTR_W; -+ kernel_clear_attrs |= GRUB_MEM_ATTR_W; -+ stack_set_attrs &= ~GRUB_MEM_ATTR_X; -+ stack_clear_attrs |= GRUB_MEM_ATTR_X; -+ } -+ -+ grub_dprintf ("nx", "Setting attributes for 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to r%cx\n", -+ k_address, k_address + k_size - 1, -+ (kernel_set_attrs & GRUB_MEM_ATTR_W) ? 'w' : '-'); -+ grub_update_mem_attrs (k_address, k_size, -+ kernel_set_attrs, kernel_clear_attrs); -+ -+ grub_get_mem_attrs (k_address, 4096, &attrs); -+ grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n", -+ (grub_addr_t)k_address, -+ (attrs & GRUB_MEM_ATTR_R) ? "r" : "-", -+ (attrs & GRUB_MEM_ATTR_W) ? "w" : "-", -+ (attrs & GRUB_MEM_ATTR_X) ? "x" : "-"); -+ if (grub_stack_addr != (grub_addr_t)-1ll) -+ { -+ grub_dprintf ("nx", "Setting attributes for stack at 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to rw%c\n", -+ grub_stack_addr, grub_stack_addr + grub_stack_size - 1, -+ (stack_set_attrs & GRUB_MEM_ATTR_X) ? 'x' : '-'); -+ grub_update_mem_attrs (grub_stack_addr, grub_stack_size, -+ stack_set_attrs, stack_clear_attrs); -+ -+ grub_get_mem_attrs (grub_stack_addr, 4096, &attrs); -+ grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n", -+ grub_stack_addr, -+ (attrs & GRUB_MEM_ATTR_R) ? "r" : "-", -+ (attrs & GRUB_MEM_ATTR_W) ? "w" : "-", -+ (attrs & GRUB_MEM_ATTR_X) ? "x" : "-"); -+ } ++ grub_efi_mem_set_att (k_address, k_size, k_start, nx_supported); + +#if defined(__i386__) || defined(__x86_64__) + asm volatile ("cli"); +#endif + -+ hf = (handover_func)((char *)k_address + h_offset + offset); ++ hf = (handover_func)((char *)k_start_address + h_offset + offset); + hf (grub_efi_image_handle, grub_efi_system_table, k_params); + + return GRUB_ERR_BUG; +} + +#pragma GCC diagnostic pop -+ + grub_err_t grub_arch_efi_linux_load_image_header (grub_file_t file, - struct linux_arch_kernel_header * lh) -@@ -95,7 +297,7 @@ grub_arch_efi_linux_load_image_header (grub_file_t file, +@@ -95,7 +365,7 @@ grub_arch_efi_linux_load_image_header (grub_file_t file, if (grub_file_read (file, lh, sizeof (*lh)) < (grub_ssize_t) sizeof (*lh)) return grub_error(GRUB_ERR_FILE_READ_ERROR, "failed to read Linux image header"); @@ -24162,19 +30575,33 @@ index bfbd95aee..5889e3f36 100644 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, N_("plain image kernel not supported - rebuild with CONFIG_(U)EFI_STUB enabled")); -@@ -139,8 +341,9 @@ grub_arch_efi_linux_load_image_header (grub_file_t file, +@@ -120,6 +390,7 @@ grub_arch_efi_linux_load_image_header (grub_file_t file, + if (lh->pe_image_header.optional_header.magic != GRUB_PE32_NATIVE_MAGIC) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "non-native image not supported"); + ++#if !defined(__i386__) && !defined(__x86_64__) + /* + * Linux kernels built for any architecture are guaranteed to support the + * LoadFile2 based initrd loading protocol if the image version is >= 1. +@@ -131,6 +402,7 @@ grub_arch_efi_linux_load_image_header (grub_file_t file, + + grub_dprintf ("linux", "LoadFile2 initrd loading %sabled\n", + initrd_use_loadfile2 ? "en" : "dis"); ++#endif + + return GRUB_ERR_NONE; + } +@@ -139,8 +411,8 @@ grub_arch_efi_linux_load_image_header (grub_file_t file, static grub_err_t finalize_params_linux (void) { -- int node, retval; -- -+ grub_efi_loaded_image_t *loaded_image = NULL; -+ int node, retval, len; + grub_err_t err = GRUB_ERR_NONE; + int node, retval; +- void *fdt; /* Set initrd info */ -@@ -149,14 +352,21 @@ finalize_params_linux (void) +@@ -149,14 +421,21 @@ finalize_params_linux (void) fdt = grub_fdt_load (GRUB_EFI_LINUX_FDT_EXTRA_SPACE); if (!fdt) @@ -24198,7 +30625,7 @@ index bfbd95aee..5889e3f36 100644 grub_dprintf ("linux", "Initrd @ %p-%p\n", (void *) initrd_start, (void *) initrd_end); -@@ -164,89 +374,91 @@ finalize_params_linux (void) +@@ -164,21 +443,32 @@ finalize_params_linux (void) retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-start", initrd_start); if (retval) @@ -24220,39 +30647,6 @@ index bfbd95aee..5889e3f36 100644 - if (grub_fdt_install() != GRUB_ERR_NONE) - goto failure; -- -- return GRUB_ERR_NONE; -- --failure: -- grub_fdt_unload(); -- return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT"); --} --#endif -- --grub_err_t --grub_arch_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args) --{ -- grub_efi_memory_mapped_device_path_t *mempath; -- grub_efi_handle_t image_handle; -- grub_efi_boot_services_t *b; -- grub_efi_status_t status; -- grub_efi_loaded_image_t *loaded_image; -- int len; -- -- mempath = grub_malloc (2 * sizeof (grub_efi_memory_mapped_device_path_t)); -- if (!mempath) -- return grub_errno; -- -- mempath[0].header.type = GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE; -- mempath[0].header.subtype = GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE; -- mempath[0].header.length = grub_cpu_to_le16_compile_time (sizeof (*mempath)); -- mempath[0].memory_type = GRUB_EFI_LOADER_DATA; -- mempath[0].start_address = addr; -- mempath[0].end_address = addr + size; -- -- mempath[1].header.type = GRUB_EFI_END_DEVICE_PATH_TYPE; -- mempath[1].header.subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; -- mempath[1].header.length = sizeof (grub_efi_device_path_t); + retval = grub_fdt_install(); + if (retval != GRUB_ERR_NONE) + { @@ -24260,122 +30654,66 @@ index bfbd95aee..5889e3f36 100644 + goto failure; + } -- b = grub_efi_system_table->boot_services; -- status = b->load_image (0, grub_efi_image_handle, -- (grub_efi_device_path_t *) mempath, -- (void *) addr, size, &image_handle); -- if (status != GRUB_EFI_SUCCESS) -- return grub_error (GRUB_ERR_BAD_OS, "cannot load image"); -- -- grub_dprintf ("linux", "linux command line: '%s'\n", args); -+ grub_dprintf ("linux", "Installed/updated FDT configuration table @ %p\n", -+ fdt); + return GRUB_ERR_NONE; - /* Convert command line to UCS-2 */ -- loaded_image = grub_efi_get_loaded_image (image_handle); -+ loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle); - if (loaded_image == NULL) - { -- grub_error (GRUB_ERR_BAD_FIRMWARE, "missing loaded_image proto"); -- goto unload; -+ err = grub_error(grub_errno, "Failed to install fdt"); -+ goto failure; - } - loaded_image->load_options_size = len = -- (grub_strlen (args) + 1) * sizeof (grub_efi_char16_t); -+ (grub_strlen (linux_args) + 1) * sizeof (grub_efi_char16_t); + failure: + grub_fdt_unload(); +- return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT"); ++ return err; + } + #endif + +@@ -211,6 +501,7 @@ grub_arch_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args) + status = b->load_image (0, grub_efi_image_handle, + (grub_efi_device_path_t *) mempath, + (void *) addr, size, &image_handle); ++ grub_free (mempath); + if (status != GRUB_EFI_SUCCESS) + return grub_error (GRUB_ERR_BAD_OS, "cannot load image"); + +@@ -228,7 +519,7 @@ grub_arch_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args) loaded_image->load_options = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size)); if (!loaded_image->load_options) - return grub_errno; -+ { -+ err = grub_error(GRUB_ERR_BAD_OS, "failed to create kernel parameters"); -+ goto failure; -+ } ++ goto unload; loaded_image->load_options_size = 2 * grub_utf8_to_utf16 (loaded_image->load_options, len, -- (grub_uint8_t *) args, len, NULL); -+ (grub_uint8_t *) linux_args, len, NULL); - -- grub_dprintf ("linux", "starting image %p\n", image_handle); -- status = b->start_image (image_handle, 0, NULL); -+ return GRUB_ERR_NONE; -+ -+failure: -+ grub_fdt_unload(); -+ return err; -+} -+#endif - -- /* When successful, not reached */ -- grub_error (GRUB_ERR_BAD_OS, "start_image() returned 0x%" PRIxGRUB_EFI_UINTN_T, status); -- grub_efi_free_pages ((grub_addr_t) loaded_image->load_options, -- GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size)); --unload: -- b->unload_image (image_handle); -+static void -+free_params (void) -+{ -+ grub_efi_loaded_image_t *loaded_image = NULL; - -- return grub_errno; -+ loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle); -+ if (loaded_image) -+ { -+ if (loaded_image->load_options) -+ grub_efi_free_pages ((grub_efi_physical_address_t)(grub_efi_uintn_t)loaded_image->load_options, -+ GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size)); -+ loaded_image->load_options = NULL; -+ loaded_image->load_options_size = 0; -+ } +@@ -247,13 +538,12 @@ unload: + return grub_errno; } -+grub_err_t -+grub_arch_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args, -+ int nx_supported) -+{ -+ grub_err_t retval; -+ -+ grub_dprintf ("linux", "linux command line: '%s'\n", args); -+ -+ retval = grub_efi_linux_boot (addr, size, handover_offset, -+ (void *)addr, nx_supported); -+ -+ /* Never reached... */ -+ free_params(); -+ return retval; -+ } -+ ++#if !defined(__i386__) && !defined(__x86_64__) static grub_err_t grub_linux_boot (void) { -@@ -255,8 +467,10 @@ grub_linux_boot (void) +-#if !defined(__i386__) && !defined(__x86_64__) + if (finalize_params_linux () != GRUB_ERR_NONE) return grub_errno; - #endif +-#endif -- return grub_arch_efi_linux_boot_image ((grub_addr_t) kernel_addr, -- kernel_size, linux_args); -+ return grub_arch_efi_linux_boot_image((grub_addr_t)kernel_addr, -+ (grub_size_t)kernel_size, -+ linux_args, -+ 0); + return grub_arch_efi_linux_boot_image ((grub_addr_t) kernel_addr, + kernel_size, linux_args); +@@ -274,9 +564,7 @@ grub_linux_unload (void) + if (kernel_addr) + grub_efi_free_pages ((grub_addr_t) kernel_addr, + GRUB_EFI_BYTES_TO_PAGES (kernel_size)); +-#if !defined(__i386__) && !defined(__x86_64__) + grub_fdt_unload (); +-#endif + + if (initrd_lf2_handle != NULL) + { +@@ -292,7 +580,6 @@ grub_linux_unload (void) + return GRUB_ERR_NONE; } - static grub_err_t -@@ -271,9 +485,8 @@ grub_linux_unload (void) - GRUB_EFI_BYTES_TO_PAGES (initrd_end - initrd_start)); - initrd_start = initrd_end = 0; - grub_free (linux_args); -- if (kernel_addr) -- grub_efi_free_pages ((grub_addr_t) kernel_addr, -- GRUB_EFI_BYTES_TO_PAGES (kernel_size)); -+ if (kernel_alloc_addr) -+ grub_efi_free_pages ((grub_addr_t) kernel_alloc_addr, kernel_alloc_pages); - #if !defined(__i386__) && !defined(__x86_64__) - grub_fdt_unload (); - #endif -@@ -317,16 +530,28 @@ grub_linux_unload (void) +-#if !defined(__i386__) && !defined(__x86_64__) + /* + * As per linux/Documentation/arm/Booting + * ARM initrd needs to be covered by kernel linear mapping, +@@ -317,18 +604,29 @@ grub_linux_unload (void) static void * allocate_initrd_mem (int initrd_pages) { @@ -24408,191 +30746,90 @@ index bfbd95aee..5889e3f36 100644 + grub_dprintf ("linux", "got 0x%016llx\n", (unsigned long long)ret); + return ret; } - #endif +-#endif -@@ -452,13 +677,55 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), - return grub_errno; - } + static grub_efi_status_t __grub_efi_api + grub_efi_initrd_load_file2 (grub_efi_load_file2_t *this, +@@ -381,11 +679,6 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } -+#if !defined(__i386__) && !defined(__x86_64__) -+static grub_err_t -+parse_pe_header (void *kernel, grub_uint64_t *total_size, -+ grub_uint32_t *entry_offset, -+ grub_uint32_t *alignment, grub_uint32_t *code_size) -+{ -+ struct linux_arch_kernel_header *lh = kernel; -+ struct grub_armxx_linux_pe_header *pe; -+ grub_uint16_t i; -+ struct grub_pe32_section_table *sections; -+ -+ pe = (void *)((unsigned long)kernel + lh->hdr_offset); -+ -+ if (pe->opt.magic != GRUB_PE32_PEXX_MAGIC) -+ return grub_error(GRUB_ERR_BAD_OS, "Invalid PE optional header magic"); -+ -+ *total_size = pe->opt.image_size; -+ *entry_offset = pe->opt.entry_addr; -+ *alignment = pe->opt.section_alignment; -+ *code_size = pe->opt.section_alignment; -+ -+ sections = (struct grub_pe32_section_table *) ((char *)&pe->opt + -+ pe->coff.optional_header_size); -+ grub_dprintf ("linux", "num_sections : %d\n", pe->coff.num_sections ); -+ for (i = 0 ; i < pe->coff.num_sections; i++) -+ { -+ grub_dprintf ("linux", "raw_size : %lld\n", -+ (long long) sections[i].raw_data_size); -+ grub_dprintf ("linux", "virt_size : %lld\n", -+ (long long) sections[i].virtual_size); -+ *code_size += sections[i].raw_data_size; -+ } -+ -+ return GRUB_ERR_NONE; -+} -+#endif -+ - static grub_err_t - grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - int argc, char *argv[]) - { - grub_file_t file = 0; - struct linux_arch_kernel_header lh; -+ grub_off_t filelen; -+ grub_off_t filereadlen; -+ void *kernel = NULL; - grub_err_t err; -+ int nx_supported = 1; -+ int nx_required = 0; +-#if defined(__i386__) || defined(__x86_64__) +- if (!initrd_use_loadfile2) +- return grub_cmd_initrd_x86_legacy (cmd, argc, argv); +-#endif +- + if (!loaded) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, +@@ -421,7 +714,6 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + return GRUB_ERR_NONE; + } +-#if !defined(__i386__) && !defined(__x86_64__) + initrd_size = grub_get_initrd_size (&initrd_ctx); + grub_dprintf ("linux", "Loading initrd\n"); + +@@ -444,7 +736,6 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + initrd_end = initrd_start + initrd_size; + grub_dprintf ("linux", "[addr=%p, size=0x%x]\n", + (void *) initrd_start, initrd_size); +-#endif + + fail: + grub_initrd_close (&initrd_ctx); +@@ -463,20 +754,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), grub_dl_ref (my_mod); -@@ -488,50 +755,84 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - if (!file) - goto fail; + if (grub_is_shim_lock_enabled () == true) +- { +-#if defined(__i386__) || defined(__x86_64__) +- grub_dprintf ("linux", "shim_lock enabled, falling back to legacy Linux kernel loader\n"); +- +- err = grub_cmd_linux_x86_legacy (cmd, argc, argv); +- +- if (err == GRUB_ERR_NONE) +- return GRUB_ERR_NONE; +- else +- goto fail; +-#else +- grub_dprintf ("linux", "shim_lock enabled, trying Linux kernel EFI stub loader\n"); +-#endif +- } ++ grub_dprintf ("linux", "shim_lock enabled, trying Linux kernel EFI stub loader\n"); -- kernel_size = grub_file_size (file); -+ filelen = grub_file_size (file); -+ kernel = grub_malloc(filelen); -+ if (!kernel) -+ { -+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel load buffer")); -+ goto fail; -+ } -+ -+ filereadlen = grub_file_read (file, kernel, filelen); -+ grub_dprintf ("linux", "filelen : %lld\n", (long long) filelen); -+ grub_dprintf ("linux", "filereadlen : %lld\n", (long long) filereadlen); -+ -+ if (filereadlen < filelen) -+ { -+ grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"), -+ argv[0]); -+ goto fail; -+ } + if (argc == 0) + { +@@ -491,24 +769,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + kernel_size = grub_file_size (file); -- if (grub_arch_efi_linux_load_image_header (file, &lh) != GRUB_ERR_NONE) - #if !defined(__i386__) && !defined(__x86_64__) -+ if (grub_arch_efi_linux_load_image_header (file, &lh) != GRUB_ERR_NONE) + if (grub_arch_efi_linux_load_image_header (file, &lh) != GRUB_ERR_NONE) +-#if !defined(__i386__) && !defined(__x86_64__) goto fail; - #else +-#else - goto fallback; - - if (!initrd_use_loadfile2) -+ if (grub_arch_efi_linux_load_image_header (file, &lh) != GRUB_ERR_NONE || -+ !initrd_use_loadfile2) - { -+ /* We cannot use the legacy loader when NX is required */ -+ if (grub_efi_check_nx_required(&nx_required)) -+ goto fail; -+ - /* - * This is a EFI stub image but it is too old to implement the LoadFile2 - * based initrd loading scheme, and Linux/x86 does not support the DT - * based method either. So fall back to the x86-specific loader that - * enters Linux in EFI mode but without going through its EFI stub. - */ +- { +- /* +- * This is a EFI stub image but it is too old to implement the LoadFile2 +- * based initrd loading scheme, and Linux/x86 does not support the DT +- * based method either. So fall back to the x86-specific loader that +- * enters Linux in EFI mode but without going through its EFI stub. +- */ -fallback: - grub_file_close (file); - return grub_cmd_linux_x86_legacy (cmd, argc, argv); - } - #endif +- grub_file_close (file); +- return grub_cmd_linux_x86_legacy (cmd, argc, argv); +- } +-#endif -+ -+#if !defined(__i386__) && !defined(__x86_64__) -+ grub_uint32_t align; -+ grub_uint32_t code_size; -+ if (parse_pe_header (kernel, &kernel_size, &handover_offset, &align, &code_size) != GRUB_ERR_NONE) -+ goto fail; -+ grub_dprintf ("linux", "kernel mem size : %lld\n", (long long) kernel_size); -+ grub_dprintf ("linux", "kernel entry offset : %d\n", handover_offset); -+ grub_dprintf ("linux", "kernel alignment : 0x%x\n", align); -+ grub_dprintf ("linux", "kernel size : 0x%x\n", code_size); -+ -+ err = grub_efi_check_nx_image_support((grub_addr_t)kernel, filelen, &nx_supported); -+ if (err != GRUB_ERR_NONE) -+ goto fail; -+ grub_loader_unset(); -- grub_dprintf ("linux", "kernel file size: %lld\n", (long long) kernel_size); -- kernel_addr = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (kernel_size)); -- grub_dprintf ("linux", "kernel numpages: %lld\n", -- (long long) GRUB_EFI_BYTES_TO_PAGES (kernel_size)); -- if (!kernel_addr) -+ kernel_alloc_pages = GRUB_EFI_BYTES_TO_PAGES (kernel_size + align - 1); -+ kernel_alloc_addr = grub_efi_allocate_pages_real (GRUB_EFI_MAX_USABLE_ADDRESS, -+ kernel_alloc_pages, -+ GRUB_EFI_ALLOCATE_MAX_ADDRESS, -+ GRUB_EFI_LOADER_CODE); -+ grub_dprintf ("linux", "kernel numpages: %d\n", kernel_alloc_pages); -+ if (!kernel_alloc_addr) - { - grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); - goto fail; - } -- -- grub_file_seek (file, 0); -- if (grub_file_read (file, kernel_addr, kernel_size) -- < (grub_int64_t) kernel_size) -- { -- if (!grub_errno) -- grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), argv[0]); -- goto fail; -- } -+ kernel_addr = (void *)ALIGN_UP((grub_uint64_t)kernel_alloc_addr, align); - - grub_dprintf ("linux", "kernel @ %p\n", kernel_addr); -+ grub_memcpy (kernel_addr, kernel, grub_min(code_size, kernel_size)); -+ if (kernel_size > code_size) -+ grub_memset ((char *)kernel_addr + code_size, 0, kernel_size - code_size); -+ grub_free(kernel); -+ kernel = NULL; -+#endif - - cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE); - linux_args = grub_malloc (cmdline_size); -@@ -555,6 +856,9 @@ fallback: - } - - fail: -+ if (kernel) -+ grub_free (kernel); -+ - if (file) - grub_file_close (file); - -@@ -567,9 +871,8 @@ fail: - if (linux_args && !loaded) - grub_free (linux_args); - -- if (kernel_addr && !loaded) -- grub_efi_free_pages ((grub_addr_t) kernel_addr, -- GRUB_EFI_BYTES_TO_PAGES (kernel_size)); -+ if (kernel_alloc_addr && !loaded) -+ grub_efi_free_pages ((grub_addr_t) kernel_alloc_addr, kernel_alloc_pages); - - return grub_errno; +@@ -591,3 +852,4 @@ GRUB_MOD_FINI (linux) + grub_unregister_command (cmd_linux); + grub_unregister_command (cmd_initrd); } ++#endif diff --git a/grub-core/loader/emu/linux.c b/grub-core/loader/emu/linux.c index 7de3f7f86..6feb0412c 100644 --- a/grub-core/loader/emu/linux.c @@ -24829,7 +31066,7 @@ index 7de3f7f86..6feb0412c 100644 grub_free (initrd_param); diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c -index 1f9128f6f..8075ac9b0 100644 +index 1f9128f6f..50f96ea7a 100644 --- a/grub-core/loader/i386/bsd.c +++ b/grub-core/loader/i386/bsd.c @@ -40,6 +40,7 @@ @@ -24840,7 +31077,42 @@ index 1f9128f6f..8075ac9b0 100644 GRUB_MOD_LICENSE ("GPLv3+"); -@@ -2137,6 +2138,9 @@ static grub_command_t cmd_netbsd_module_elf, cmd_openbsd_ramdisk; +@@ -1340,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; +@@ -1370,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; + +@@ -1431,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); +@@ -2137,6 +2144,9 @@ static grub_command_t cmd_netbsd_module_elf, cmd_openbsd_ramdisk; GRUB_MOD_INIT (bsd) { @@ -24850,7 +31122,7 @@ index 1f9128f6f..8075ac9b0 100644 /* Net and OpenBSD kernels are often compressed. */ grub_dl_load ("gzio"); -@@ -2176,6 +2180,9 @@ GRUB_MOD_INIT (bsd) +@@ -2176,6 +2186,9 @@ GRUB_MOD_INIT (bsd) GRUB_MOD_FINI (bsd) { @@ -24862,10 +31134,10 @@ index 1f9128f6f..8075ac9b0 100644 grub_unregister_extcmd (cmd_netbsd); diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c new file mode 100644 -index 000000000..abbf6b24f +index 000000000..6c310d987 --- /dev/null +++ b/grub-core/loader/i386/efi/linux.c -@@ -0,0 +1,604 @@ +@@ -0,0 +1,607 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2012 Free Software Foundation, Inc. @@ -24909,6 +31181,7 @@ index 000000000..abbf6b24f +struct grub_linuxefi_context { + void *kernel_mem; + grub_uint64_t kernel_size; ++ grub_uint64_t kernel_start; + grub_uint32_t handover_offset; + struct linux_kernel_params *params; + char *cmdline; @@ -25037,6 +31310,7 @@ index 000000000..abbf6b24f + + return grub_efi_linux_boot ((grub_addr_t)context->kernel_mem, + context->kernel_size, ++ context->kernel_start, + context->handover_offset, + context->params, + context->nx_supported); @@ -25395,7 +31669,7 @@ index 000000000..abbf6b24f + LOW_U32(kernel_mem)); + lh->code32_start = LOW_U32(kernel_mem); + -+ grub_memcpy (kernel_mem, (char *)kernel + start, filelen - start); ++ grub_memcpy (kernel_mem, (char *)kernel, filelen); + + lh->type_of_loader = 0x6; + grub_dprintf ("linux", "setting lh->type_of_loader = 0x%02x\n", @@ -25412,6 +31686,7 @@ index 000000000..abbf6b24f + goto fail; + context->kernel_mem = kernel_mem; + context->kernel_size = kernel_size; ++ context->kernel_start = start; + context->handover_offset = handover_offset; + context->params = params; + context->cmdline = cmdline; @@ -25471,7 +31746,7 @@ index 000000000..abbf6b24f + grub_unregister_command (cmd_initrdefi); +} diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c -index 977757f2c..90121e9bc 100644 +index 977757f2c..33a852197 100644 --- a/grub-core/loader/i386/linux.c +++ b/grub-core/loader/i386/linux.c @@ -37,6 +37,7 @@ @@ -25526,7 +31801,7 @@ index 977757f2c..90121e9bc 100644 if (lh.boot_flag != grub_cpu_to_le16_compile_time (0xaa55)) { grub_error (GRUB_ERR_BAD_OS, "invalid magic number"); -@@ -796,15 +810,18 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), +@@ -796,17 +810,20 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), /* We've already read lh so there is no need to read it second time. */ len -= sizeof(lh); @@ -25549,8 +31824,11 @@ index 977757f2c..90121e9bc 100644 + 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 = (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; + @@ -865,7 +882,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), /* The other parameters are filled when booting. */ @@ -26069,10 +32347,10 @@ index 1d367436c..7adeb7447 100644 /* Change operation to REPLY and send packet */ send_ethernet_packet (inf, &nb_reply, target, GRUB_NET_ETHERTYPE_ARP); diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c -index abe45ef7b..9cbdc2264 100644 +index abe45ef7b..bed70c0b2 100644 --- a/grub-core/net/bootp.c +++ b/grub-core/net/bootp.c -@@ -20,10 +20,103 @@ +@@ -20,10 +20,104 @@ #include #include #include @@ -26083,6 +32361,7 @@ index abe45ef7b..9cbdc2264 100644 #include +#include +#include ++#include + +static int +dissect_url (const char *url, char **proto, char **host, char **path) @@ -26176,7 +32455,7 @@ index abe45ef7b..9cbdc2264 100644 struct grub_dhcp_discover_options { -@@ -233,11 +326,10 @@ grub_net_configure_by_dhcp_ack (const char *name, +@@ -233,11 +327,10 @@ grub_net_configure_by_dhcp_ack (const char *name, int is_def, char **device, char **path) { grub_net_network_level_address_t addr; @@ -26189,7 +32468,7 @@ index abe45ef7b..9cbdc2264 100644 grub_uint8_t opt_len, overload = 0; const char *boot_file = 0, *server_name = 0; grub_size_t boot_file_len, server_name_len; -@@ -251,12 +343,8 @@ grub_net_configure_by_dhcp_ack (const char *name, +@@ -251,12 +344,8 @@ grub_net_configure_by_dhcp_ack (const char *name, if (path) *path = 0; @@ -26204,7 +32483,7 @@ index abe45ef7b..9cbdc2264 100644 if (!inter) return 0; -@@ -414,6 +502,60 @@ grub_net_configure_by_dhcp_ack (const char *name, +@@ -414,6 +503,60 @@ grub_net_configure_by_dhcp_ack (const char *name, if (opt && opt_len) grub_env_set_net_property (name, "rootpath", (const char *) opt, opt_len); @@ -26265,7 +32544,7 @@ index abe45ef7b..9cbdc2264 100644 opt = find_dhcp_option (bp, size, GRUB_NET_BOOTP_EXTENSIONS_PATH, &opt_len); if (opt && opt_len) grub_env_set_net_property (name, "extensionspath", (const char *) opt, opt_len); -@@ -568,7 +710,9 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface) +@@ -568,7 +711,9 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface) grub_memset (pack, 0, sizeof (*pack)); pack->opcode = 1; pack->hw_type = 1; @@ -26276,7 +32555,7 @@ index abe45ef7b..9cbdc2264 100644 err = grub_get_datetime (&date); if (err || !grub_datetime2unixtime (&date, &t)) { -@@ -581,7 +725,7 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface) +@@ -581,7 +726,7 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface) else pack->ident = iface->xid; @@ -26285,7 +32564,7 @@ index abe45ef7b..9cbdc2264 100644 err = grub_netbuff_push (nb, sizeof (*udph)); if (err) -@@ -610,6 +754,584 @@ out: +@@ -610,6 +755,584 @@ out: return err; } @@ -26870,7 +33149,7 @@ index abe45ef7b..9cbdc2264 100644 /* * This is called directly from net/ip.c:handle_dgram(), because those * BOOTP/DHCP packets are a bit special due to their improper -@@ -678,6 +1400,77 @@ grub_net_process_dhcp (struct grub_net_buff *nb, +@@ -678,6 +1401,77 @@ grub_net_process_dhcp (struct grub_net_buff *nb, } } @@ -26948,7 +33227,43 @@ index abe45ef7b..9cbdc2264 100644 static grub_err_t grub_cmd_dhcpopt (struct grub_command *cmd __attribute__ ((unused)), int argc, char **args) -@@ -903,7 +1696,174 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)), +@@ -686,6 +1480,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, +@@ -727,7 +1522,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); +@@ -760,7 +1560,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; +@@ -903,7 +1708,174 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)), return err; } @@ -27124,7 +33439,7 @@ index abe45ef7b..9cbdc2264 100644 void grub_bootp_init (void) -@@ -917,11 +1877,15 @@ grub_bootp_init (void) +@@ -917,11 +1889,15 @@ grub_bootp_init (void) cmd_getdhcp = grub_register_command ("net_get_dhcp_option", grub_cmd_dhcpopt, N_("VAR INTERFACE NUMBER DESCRIPTION"), N_("retrieve DHCP option and save it into VAR. If VAR is - then print the value.")); @@ -27140,6 +33455,40 @@ index abe45ef7b..9cbdc2264 100644 grub_unregister_command (cmd_getdhcp); grub_unregister_command (cmd_bootp); grub_unregister_command (cmd_dhcp); +diff --git a/grub-core/net/dns.c b/grub-core/net/dns.c +index fcc09aa65..f20cd6f83 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)) +@@ -463,8 +470,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/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c index 3ea25cf98..4591d0757 100644 --- a/grub-core/net/drivers/efi/efinet.c @@ -27856,10 +34205,25 @@ index db17186ee..816d1d0ee 100644 grub_pxe_card.default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; diff --git a/grub-core/net/drivers/ieee1275/ofnet.c b/grub-core/net/drivers/ieee1275/ofnet.c -index 78f03df8e..c56461ff1 100644 +index 78f03df8e..9b045ce70 100644 --- a/grub-core/net/drivers/ieee1275/ofnet.c +++ b/grub-core/net/drivers/ieee1275/ofnet.c -@@ -160,6 +160,7 @@ grub_ieee1275_parse_bootpath (const char *devpath, char *bootpath, +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -154,12 +155,13 @@ grub_ieee1275_parse_bootpath (const char *devpath, char *bootpath, + char *equal_char = 0; + grub_size_t field_counter = 0; + grub_net_network_level_address_t client_addr = {0, {0}, 0}, gateway_addr = {0, {0}, 0}, subnet_mask = {0, {0}, 0}; +- grub_net_link_level_address_t hw_addr = {0, {{0, 0, 0, 0, 0, 0}}}; ++ grub_net_link_level_address_t hw_addr = {}; + grub_net_interface_flags_t flags = 0; + struct grub_net_network_level_interface *inter = NULL; grub_uint16_t vlantag = 0; hw_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; @@ -27867,7 +34231,44 @@ index 78f03df8e..c56461ff1 100644 args = bootpath + grub_strlen (devpath) + 1; do -@@ -491,6 +492,7 @@ search_net_devices (struct grub_ieee1275_devalias *alias) +@@ -391,6 +393,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; +@@ -448,9 +451,26 @@ 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; ++ } ++ } ++ ++ ofdata->path = grub_malloc(sz); ++ + if (!ofdata->path) + { + grub_print_error (); +@@ -491,6 +511,7 @@ search_net_devices (struct grub_ieee1275_devalias *alias) grub_memcpy (&lla.mac, pprop, 6); lla.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; @@ -31895,20 +38296,32 @@ index 3c3d0be0e..3c475762c 100644 grub_net_process_dhcp (nb, inf); grub_netbuff_free (nb); diff --git a/grub-core/net/net.c b/grub-core/net/net.c -index 8cad4fb6d..fdec64d55 100644 +index 8cad4fb6d..f9a5edcef 100644 --- a/grub-core/net/net.c +++ b/grub-core/net/net.c -@@ -32,6 +32,9 @@ +@@ -32,6 +32,10 @@ #include #include #include ++#include +#ifdef GRUB_MACHINE_EFI +#include +#endif GRUB_MOD_LICENSE ("GPLv3+"); -@@ -133,8 +136,9 @@ grub_net_link_layer_resolve (struct grub_net_network_level_interface *inf, +@@ -87,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; + } +@@ -133,8 +137,9 @@ grub_net_link_layer_resolve (struct grub_net_network_level_interface *inf, << 48) && proto_addr->ipv6[1] == (grub_be_to_cpu64_compile_time (1)))) { @@ -31920,7 +38333,7 @@ index 8cad4fb6d..fdec64d55 100644 return GRUB_ERR_NONE; } -@@ -142,6 +146,7 @@ grub_net_link_layer_resolve (struct grub_net_network_level_interface *inf, +@@ -142,6 +147,7 @@ grub_net_link_layer_resolve (struct grub_net_network_level_interface *inf, && ((grub_be_to_cpu64 (proto_addr->ipv6[0]) >> 56) == 0xff)) { hw_addr->type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; @@ -31928,7 +38341,66 @@ index 8cad4fb6d..fdec64d55 100644 hw_addr->mac[0] = 0x33; hw_addr->mac[1] = 0x33; hw_addr->mac[2] = ((grub_be_to_cpu64 (proto_addr->ipv6[1]) >> 24) & 0xff); -@@ -772,23 +777,23 @@ grub_net_addr_to_str (const grub_net_network_level_address_t *target, char *buf) +@@ -206,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) +@@ -215,9 +222,21 @@ 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); ++ 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) + { +@@ -288,6 +307,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); +@@ -302,9 +322,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; + +@@ -772,23 +797,23 @@ grub_net_addr_to_str (const grub_net_network_level_address_t *target, char *buf) void grub_net_hwaddr_to_str (const grub_net_link_level_address_t *addr, char *str) { @@ -31967,7 +38439,7 @@ index 8cad4fb6d..fdec64d55 100644 } void -@@ -813,13 +818,17 @@ grub_net_hwaddr_cmp (const grub_net_link_level_address_t *a, +@@ -813,13 +838,17 @@ grub_net_hwaddr_cmp (const grub_net_link_level_address_t *a, return -1; if (a->type > b->type) return +1; @@ -31990,7 +38462,7 @@ index 8cad4fb6d..fdec64d55 100644 } int -@@ -984,6 +993,78 @@ grub_net_network_level_interface_register (struct grub_net_network_level_interfa +@@ -984,6 +1013,111 @@ grub_net_network_level_interface_register (struct grub_net_network_level_interfa grub_net_network_level_interfaces = inter; } @@ -32065,11 +38537,110 @@ index 8cad4fb6d..fdec64d55 100644 + grub_net_route_register (route); + + 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, -@@ -2005,7 +2086,7 @@ grub_net_search_config_file (char *config) +@@ -1402,9 +1536,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 addr. */ +- 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; + +@@ -1659,6 +1799,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) +@@ -1666,7 +1807,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); +@@ -1909,14 +2055,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) +@@ -1942,7 +2089,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; + } +@@ -2005,7 +2152,7 @@ grub_net_search_config_file (char *config) /* Remove the remaining minus sign at the end. */ config[config_len] = '\0'; @@ -32078,7 +38649,7 @@ index 8cad4fb6d..fdec64d55 100644 } static struct grub_preboot *fini_hnd; -@@ -2014,8 +2095,49 @@ static grub_command_t cmd_addaddr, cmd_deladdr, cmd_addroute, cmd_delroute; +@@ -2014,8 +2161,49 @@ static grub_command_t cmd_addaddr, cmd_deladdr, cmd_addroute, cmd_delroute; static grub_command_t cmd_setvlan, cmd_lsroutes, cmd_lscards; static grub_command_t cmd_lsaddr, cmd_slaac; @@ -32128,7 +38699,7 @@ index 8cad4fb6d..fdec64d55 100644 grub_register_variable_hook ("net_default_server", defserver_get_env, defserver_set_env); grub_env_export ("net_default_server"); -@@ -2066,10 +2188,37 @@ GRUB_MOD_INIT(net) +@@ -2066,12 +2254,41 @@ GRUB_MOD_INIT(net) grub_net_restore_hw, GRUB_LOADER_PREBOOT_HOOK_PRIO_DISK); grub_net_poll_cards_idle = grub_net_poll_cards_idle_real; @@ -32165,8 +38736,20 @@ index 8cad4fb6d..fdec64d55 100644 + 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); -@@ -2088,4 +2237,7 @@ GRUB_MOD_FINI(net) + grub_bootp_fini (); + grub_dns_fini (); +@@ -2079,6 +2296,7 @@ GRUB_MOD_FINI(net) + grub_unregister_command (cmd_deladdr); + grub_unregister_command (cmd_addroute); + grub_unregister_command (cmd_delroute); ++ grub_unregister_command (cmd_setvlan); + grub_unregister_command (cmd_lsroutes); + grub_unregister_command (cmd_lscards); + grub_unregister_command (cmd_lsaddr); +@@ -2088,4 +2306,7 @@ GRUB_MOD_FINI(net) grub_net_fini_hw (0); grub_loader_unregister_preboot_hook (fini_hnd); grub_net_poll_cards_idle = NULL; @@ -32244,10 +38827,98 @@ index 93dee0caa..902ab7e8a 100644 tcp_socket_register (socket); diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c -index 409b1d09b..f300a9d40 100644 +index 409b1d09b..3d96e50f4 100644 --- a/grub-core/net/tftp.c +++ b/grub-core/net/tftp.c -@@ -359,6 +359,7 @@ tftp_open (struct grub_file *file, const char *filename) +@@ -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; + +@@ -359,6 +369,7 @@ tftp_open (struct grub_file *file, const char *filename) file->not_easily_seekable = 1; file->data = data; @@ -32255,7 +38926,7 @@ index 409b1d09b..f300a9d40 100644 err = grub_net_resolve_address (file->device->net->server, &addr); if (err) { -@@ -369,11 +370,13 @@ tftp_open (struct grub_file *file, const char *filename) +@@ -369,11 +380,13 @@ tftp_open (struct grub_file *file, const char *filename) return err; } @@ -32269,6 +38940,64 @@ index 409b1d09b..f300a9d40 100644 grub_free (data); return grub_errno; } +diff --git a/grub-core/normal/auth.c b/grub-core/normal/auth.c +index 517fc623f..71b361bc0 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) + { +@@ -209,6 +239,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/context.c b/grub-core/normal/context.c index ba185e915..b4baa4392 100644 --- a/grub-core/normal/context.c @@ -32283,7 +39012,7 @@ index ba185e915..b4baa4392 100644 int grub_extractor_level = 0; diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c -index bd4431000..26872ce94 100644 +index bd4431000..189ff9600 100644 --- a/grub-core/normal/main.c +++ b/grub-core/normal/main.c @@ -21,6 +21,7 @@ @@ -32304,7 +39033,7 @@ index bd4431000..26872ce94 100644 GRUB_MOD_LICENSE ("GPLv3+"); -@@ -67,6 +71,11 @@ grub_normal_free_menu (grub_menu_t menu) +@@ -67,6 +71,15 @@ grub_normal_free_menu (grub_menu_t menu) grub_free (entry->args); } @@ -32312,11 +39041,15 @@ index bd4431000..26872ce94 100644 + { + entry->bls->visible = 0; + } ++ if (entry->blsuki) ++ { ++ entry->blsuki->visible = 0; ++ } + grub_free ((void *) entry->id); grub_free ((void *) entry->users); grub_free ((void *) entry->title); -@@ -207,9 +216,10 @@ grub_normal_init_page (struct grub_term_output *term, +@@ -207,9 +220,10 @@ grub_normal_init_page (struct grub_term_output *term, grub_uint32_t *unicode_msg; grub_uint32_t *last_position; @@ -32329,7 +39062,7 @@ index bd4431000..26872ce94 100644 if (!msg_formatted) return; -@@ -276,6 +286,22 @@ grub_normal_execute (const char *config, int nested, int batch) +@@ -276,6 +290,22 @@ grub_normal_execute (const char *config, int nested, int batch) { menu = read_config_file (config); @@ -32352,7 +39085,7 @@ index bd4431000..26872ce94 100644 /* Ignore any error. */ grub_errno = GRUB_ERR_NONE; } -@@ -310,52 +336,127 @@ grub_enter_normal_mode (const char *config) +@@ -310,52 +340,127 @@ grub_enter_normal_mode (const char *config) grub_boot_time ("Exiting normal mode"); } @@ -32389,7 +39122,7 @@ index bd4431000..26872ce94 100644 + 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) @@ -32515,7 +39248,7 @@ index bd4431000..26872ce94 100644 return 0; } -@@ -378,6 +479,9 @@ grub_normal_reader_init (int nested) +@@ -378,6 +483,9 @@ grub_normal_reader_init (int nested) const char *msg_esc = _("ESC at any time exits."); char *msg_formatted; @@ -32525,11 +39258,79 @@ index bd4431000..26872ce94 100644 msg_formatted = grub_xasprintf (_("Minimal BASH-like line editing is supported. For " "the first word, TAB lists possible command completions. Anywhere " "else TAB lists possible device or file completions. To enable " +@@ -453,9 +561,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; + } +@@ -500,14 +612,15 @@ grub_mini_cmd_clear (struct grub_command *cmd __attribute__ ((unused)), + return 0; + } + +-static grub_command_t cmd_clear; ++static grub_command_t cmd_clear, cmd_normal, cmd_normal_exit; + + static void (*grub_xputs_saved) (const char *str); + static const char *features[] = { + "feature_chainloader_bpb", "feature_ntldr", "feature_platform_search_hint", + "feature_default_font_path", "feature_all_video_module", + "feature_menuentry_id", "feature_menuentry_options", "feature_200_final", +- "feature_nativedisk_cmd", "feature_timeout_style" ++ "feature_nativedisk_cmd", "feature_timeout_style", ++ "feature_search_cryptodisk_only" + }; + + GRUB_MOD_INIT(normal) +@@ -542,10 +655,10 @@ GRUB_MOD_INIT(normal) + grub_env_export ("pager"); + + /* Register a command "normal" for the rescue mode. */ +- grub_register_command ("normal", grub_cmd_normal, +- 0, N_("Enter normal mode.")); +- grub_register_command ("normal_exit", grub_cmd_normal_exit, +- 0, N_("Exit from normal mode.")); ++ cmd_normal = grub_register_command ("normal", grub_cmd_normal, ++ 0, N_("Enter normal mode.")); ++ cmd_normal_exit = grub_register_command ("normal_exit", grub_cmd_normal_exit, ++ 0, N_("Exit from normal mode.")); + + /* Reload terminal colors when these variables are written to. */ + grub_register_variable_hook ("color_normal", NULL, grub_env_write_color_normal); +@@ -582,7 +695,11 @@ 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); ++ grub_unregister_command (cmd_normal); ++ grub_unregister_command (cmd_normal_exit); + } diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c -index 6a90e091f..cda10fa8b 100644 +index 6a90e091f..a2703dabb 100644 --- a/grub-core/normal/menu.c +++ b/grub-core/normal/menu.c -@@ -163,12 +163,92 @@ grub_menu_set_timeout (int timeout) +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + + /* Time to delay after displaying an error message about a default/fallback + entry failing to boot. */ +@@ -163,12 +164,92 @@ grub_menu_set_timeout (int timeout) } } @@ -32623,7 +39424,7 @@ index 6a90e091f..cda10fa8b 100644 { const char *val, *tail; int entry; -@@ -179,20 +259,24 @@ get_and_remove_first_entry_number (const char *name) +@@ -179,20 +260,24 @@ get_and_remove_first_entry_number (const char *name) grub_error_push (); @@ -32653,7 +39454,7 @@ index 6a90e091f..cda10fa8b 100644 } grub_error_pop (); -@@ -201,7 +285,7 @@ get_and_remove_first_entry_number (const char *name) +@@ -201,7 +286,7 @@ get_and_remove_first_entry_number (const char *name) } /* Run a menu entry. */ @@ -32662,7 +39463,7 @@ index 6a90e091f..cda10fa8b 100644 grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) { grub_err_t err = GRUB_ERR_NONE; -@@ -218,7 +302,7 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) +@@ -218,7 +303,7 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) { grub_print_error (); grub_errno = GRUB_ERR_NONE; @@ -32671,7 +39472,7 @@ index 6a90e091f..cda10fa8b 100644 } errs_before = grub_err_printed_errors; -@@ -231,7 +315,7 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) +@@ -231,7 +316,7 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) grub_env_context_open (); menu = grub_zalloc (sizeof (*menu)); if (! menu) @@ -32680,25 +39481,30 @@ index 6a90e091f..cda10fa8b 100644 grub_env_set_menu (menu); if (auto_boot) grub_env_set ("timeout", "0"); -@@ -291,8 +375,6 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) +@@ -291,19 +376,17 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) if (ptr && ptr[0] && ptr[1]) grub_env_set ("default", ptr + 1); - else - grub_env_unset ("default"); - grub_script_execute_new_scope (entry->sourcecode, entry->argc, entry->args); +- grub_script_execute_new_scope (entry->sourcecode, entry->argc, entry->args); ++ err = grub_script_execute_new_scope (entry->sourcecode, entry->argc, entry->args); -@@ -303,7 +385,7 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) + if (errs_before != grub_err_printed_errors) + grub_wait_after_message (); - if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ()) + errs_before = grub_err_printed_errors; + +- if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ()) ++ if (err == GRUB_ERR_NONE && grub_loader_is_loaded ()) /* Implicit execution of boot, only if something is loaded. */ - grub_command_execute ("boot", 0, 0); + err = grub_command_execute ("boot", 0, 0); if (errs_before != grub_err_printed_errors) grub_wait_after_message (); -@@ -326,6 +408,8 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) +@@ -326,6 +409,8 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) else grub_env_unset ("default"); grub_env_unset ("timeout"); @@ -32707,7 +39513,7 @@ index 6a90e091f..cda10fa8b 100644 } /* Execute ENTRY from the menu MENU, falling back to entries specified -@@ -340,13 +424,16 @@ grub_menu_execute_with_fallback (grub_menu_t menu, +@@ -340,13 +425,16 @@ grub_menu_execute_with_fallback (grub_menu_t menu, void *callback_data) { int fallback_entry; @@ -32726,7 +39532,7 @@ index 6a90e091f..cda10fa8b 100644 >= 0) { grub_print_error (); -@@ -354,11 +441,9 @@ grub_menu_execute_with_fallback (grub_menu_t menu, +@@ -354,11 +442,9 @@ grub_menu_execute_with_fallback (grub_menu_t menu, entry = grub_menu_get_entry (menu, fallback_entry); callback->notify_fallback (entry, callback_data); @@ -32741,7 +39547,7 @@ index 6a90e091f..cda10fa8b 100644 } if (!autobooted) -@@ -464,35 +549,12 @@ grub_menu_register_viewer (struct grub_menu_viewer *viewer) +@@ -464,35 +550,12 @@ grub_menu_register_viewer (struct grub_menu_viewer *viewer) viewers = viewer; } @@ -32778,7 +39584,7 @@ index 6a90e091f..cda10fa8b 100644 int entry; val = grub_env_get (name); -@@ -500,38 +562,9 @@ get_entry_number (grub_menu_t menu, const char *name) +@@ -500,38 +563,9 @@ get_entry_number (grub_menu_t menu, const char *name) return -1; grub_error_push (); @@ -32820,6 +39626,78 @@ index 6a90e091f..cda10fa8b 100644 grub_error_pop (); return entry; +@@ -751,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/grub-core/normal/menu_entry.c b/grub-core/normal/menu_entry.c +index ade56be2b..8b0d17e3f 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/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c +index b1321eb26..9c383e64a 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/grub-core/osdep/linux/blocklist.c b/grub-core/osdep/linux/blocklist.c index 2efee2c2a..902cfee53 100644 --- a/grub-core/osdep/linux/blocklist.c @@ -32834,7 +39712,7 @@ index 2efee2c2a..902cfee53 100644 + fie1.fm_mapped_extents * sizeof (fie1.fm_extents[1])); diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c -index 7dd775d2a..b32582eb3 100644 +index 7dd775d2a..8bf281c1d 100644 --- a/grub-core/osdep/linux/getroot.c +++ b/grub-core/osdep/linux/getroot.c @@ -103,6 +103,14 @@ struct btrfs_ioctl_search_key @@ -32852,7 +39730,32 @@ index 7dd775d2a..b32582eb3 100644 struct btrfs_ioctl_search_args { struct btrfs_ioctl_search_key key; grub_uint64_t buf[(4096 - sizeof(struct btrfs_ioctl_search_key)) -@@ -225,7 +233,7 @@ grub_find_root_devices_from_btrfs (const char *dir) +@@ -119,7 +127,7 @@ struct btrfs_ioctl_search_args { + struct btrfs_ioctl_fs_info_args) + + static int +-grub_util_is_imsm (const char *os_dev); ++grub_util_is_imsm_or_ddf (const char *os_dev); + + + #define ESCAPED_PATH_MAX (4 * PATH_MAX) +@@ -131,6 +139,7 @@ struct mountinfo_entry + char fstype[ESCAPED_PATH_MAX + 1], device[ESCAPED_PATH_MAX + 1]; + }; + ++#ifdef GRUB_UTIL + static char ** + grub_util_raid_getmembers (const char *name, int bootable) + { +@@ -191,6 +200,7 @@ grub_util_raid_getmembers (const char *name, int bootable) + + return devicelist; + } ++#endif + + /* Statting something on a btrfs filesystem always returns a virtual device + major/minor pair rather than the real underlying device, because btrfs +@@ -225,7 +235,7 @@ grub_find_root_devices_from_btrfs (const char *dir) { int fd; struct btrfs_ioctl_fs_info_args fsi; @@ -32861,7 +39764,7 @@ index 7dd775d2a..b32582eb3 100644 char **ret; fd = open (dir, 0); -@@ -373,6 +381,110 @@ get_btrfs_fs_prefix (const char *mount_path) +@@ -373,6 +383,110 @@ get_btrfs_fs_prefix (const char *mount_path) return NULL; } @@ -32972,7 +39875,17 @@ index 7dd775d2a..b32582eb3 100644 char ** grub_find_root_devices_from_mountinfo (const char *dir, char **relroot) -@@ -515,7 +627,16 @@ again: +@@ -484,6 +598,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--) + { +@@ -515,7 +632,16 @@ again: else if (grub_strcmp (entries[i].fstype, "btrfs") == 0) { ret = grub_find_root_devices_from_btrfs (dir); @@ -32990,10 +39903,94 @@ index 7dd775d2a..b32582eb3 100644 } else if (!retry && grub_strcmp (entries[i].fstype, "autofs") == 0) { -@@ -1140,6 +1261,32 @@ grub_util_get_grub_dev_os (const char *os_dev) - return grub_dev; +@@ -576,6 +702,7 @@ out: + return ret; } ++#ifdef GRUB_UTIL + static char * + get_mdadm_uuid (const char *os_dev) + { +@@ -633,12 +760,13 @@ out: + + return name; + } ++#endif + + static int +-grub_util_is_imsm (const char *os_dev) ++grub_util_is_imsm_or_ddf (const char *os_dev) + { + int retry; +- int is_imsm = 0; ++ int is_imsm_or_ddf = 0; + int container_seen = 0; + const char *dev = os_dev; + +@@ -699,10 +827,17 @@ grub_util_is_imsm (const char *os_dev) + if (strncmp (buf, "MD_METADATA=imsm", + sizeof ("MD_METADATA=imsm") - 1) == 0) + { +- is_imsm = 1; ++ is_imsm_or_ddf = 1; + grub_util_info ("%s is imsm", dev); + break; + } ++ if (strncmp (buf, "MD_METADATA=ddf", ++ sizeof ("MD_METADATA=ddf") - 1) == 0) ++ { ++ is_imsm_or_ddf = 1; ++ grub_util_info ("%s is ddf", dev); ++ break; ++ } + } + + free (buf); +@@ -713,7 +848,7 @@ grub_util_is_imsm (const char *os_dev) + + if (dev != os_dev) + free ((void *) dev); +- return is_imsm; ++ return is_imsm_or_ddf; + } + + char * +@@ -965,6 +1100,7 @@ grub_util_part_to_disk (const char *os_dev, struct stat *st, + return path; + } + ++#ifdef GRUB_UTIL + static char * + grub_util_get_raid_grub_dev (const char *os_dev) + { +@@ -1067,6 +1203,7 @@ grub_util_get_raid_grub_dev (const char *os_dev) + } + return grub_dev; + } ++#endif + + enum grub_dev_abstraction_types + grub_util_get_dev_abstraction_os (const char *os_dev) +@@ -1078,11 +1215,12 @@ grub_util_get_dev_abstraction_os (const char *os_dev) + + /* Check for RAID. */ + if (!strncmp (os_dev, "/dev/md", 7) && ! grub_util_device_is_mapped (os_dev) +- && !grub_util_is_imsm (os_dev)) ++ && !grub_util_is_imsm_or_ddf (os_dev)) + return GRUB_DEV_ABSTRACTION_RAID; + return GRUB_DEV_ABSTRACTION_NONE; + } + ++#ifdef GRUB_UTIL + int + grub_util_pull_device_os (const char *os_dev, + enum grub_dev_abstraction_types ab) +@@ -1139,6 +1277,33 @@ grub_util_get_grub_dev_os (const char *os_dev) + + return grub_dev; + } ++#endif ++ +static void *mp = NULL; +static void +btrfs_mount_path_hook(const char *m) @@ -33019,10 +40016,9 @@ index 7dd775d2a..b32582eb3 100644 + + return get_btrfs_subvol (mp); +} -+ + char * grub_make_system_path_relative_to_its_root_os (const char *path) - { diff --git a/grub-core/osdep/linux/ofpath.c b/grub-core/osdep/linux/ofpath.c index a6153d359..72772c87a 100644 --- a/grub-core/osdep/linux/ofpath.c @@ -33216,6 +40212,36 @@ index 0b1f7618d..0ce0e309a 100644 argv[2] = script; argv[3] = '\0'; +diff --git a/grub-core/osdep/unix/getroot.c b/grub-core/osdep/unix/getroot.c +index ee11b02fb..62581ba60 100644 +--- a/grub-core/osdep/unix/getroot.c ++++ b/grub-core/osdep/unix/getroot.c +@@ -16,8 +16,8 @@ + * along with GRUB. If not, see . + */ + +-#include + #include ++#include + + #include + #include +@@ -567,6 +567,7 @@ grub_guess_root_devices (const char *dir_in) + + #endif + ++#ifdef GRUB_UTIL + void + grub_util_pull_lvm_by_command (const char *os_dev) + { +@@ -663,6 +664,7 @@ out: + free (buf); + free (vgid); + } ++#endif + + /* ZFS has similar problems to those of btrfs (see above). */ + void diff --git a/grub-core/osdep/unix/hostdisk.c b/grub-core/osdep/unix/hostdisk.c index 3a00d7451..e5f4b4d5f 100644 --- a/grub-core/osdep/unix/hostdisk.c @@ -33234,10 +40260,10 @@ index 3a00d7451..e5f4b4d5f 100644 } diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c -index 14ff09094..c19b4bf70 100644 +index 14ff09094..3d26a3fe4 100644 --- a/grub-core/script/execute.c +++ b/grub-core/script/execute.c -@@ -28,6 +28,9 @@ +@@ -28,15 +28,26 @@ #include #include #include @@ -33247,7 +40273,24 @@ index 14ff09094..c19b4bf70 100644 /* Max digits for a char is 3 (0xFF is 255), similarly for an int it is sizeof (int) * 3, and one extra for a possible -ve sign. */ -@@ -53,6 +56,12 @@ static struct grub_script_scope *scope = 0; + #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 +@@ -53,6 +64,12 @@ static struct grub_script_scope *scope = 0; /* Wildcard translator for GRUB script. */ struct grub_script_wildcard_translator *grub_wildcard_translator; @@ -33260,7 +40303,7 @@ index 14ff09094..c19b4bf70 100644 static char* wildcard_escape (const char *s) { -@@ -69,7 +78,15 @@ wildcard_escape (const char *s) +@@ -69,7 +86,15 @@ wildcard_escape (const char *s) i = 0; while ((ch = *s++)) { @@ -33277,7 +40320,7 @@ index 14ff09094..c19b4bf70 100644 p[i++] = '\\'; p[i++] = ch; } -@@ -93,7 +110,14 @@ wildcard_unescape (const char *s) +@@ -93,7 +118,14 @@ wildcard_unescape (const char *s) i = 0; while ((ch = *s++)) { @@ -33293,7 +40336,7 @@ index 14ff09094..c19b4bf70 100644 p[i++] = *s++; else p[i++] = ch; -@@ -395,10 +419,20 @@ parse_string (const char *str, +@@ -395,10 +427,20 @@ parse_string (const char *str, switch (*ptr) { case '\\': @@ -33318,7 +40361,31 @@ index 14ff09094..c19b4bf70 100644 break; case '$': if (escaped) -@@ -883,6 +917,10 @@ grub_script_execute_sourcecode (const char *source) +@@ -752,6 +794,9 @@ cleanup: + } + } + ++ if (result.args == NULL || result.argc == 0) ++ goto fail; ++ + if (! result.args[result.argc - 1]) + result.argc--; + +@@ -816,7 +861,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); +@@ -883,6 +934,10 @@ grub_script_execute_sourcecode (const char *source) grub_err_t ret = 0; struct grub_script *parsed_script; @@ -33329,6 +40396,18 @@ index 14ff09094..c19b4bf70 100644 while (source) { char *line; +@@ -897,7 +952,10 @@ grub_script_execute_sourcecode (const char *source) + break; + } + +- ret = grub_script_execute (parsed_script); ++ /* Don't let trailing blank lines determine the return code. */ ++ if (parsed_script->cmd) ++ ret = grub_script_execute (parsed_script); ++ + grub_script_free (parsed_script); + grub_free (line); + } diff --git a/grub-core/script/script.c b/grub-core/script/script.c index ec4d4337c..844e8343c 100644 --- a/grub-core/script/script.c @@ -33586,6 +40665,22 @@ index f8a129eb7..d2b716b5b 100644 static struct grub_term_input grub_at_keyboard_term = { .name = "at_keyboard", +diff --git a/grub-core/term/ns8250-spcr.c b/grub-core/term/ns8250-spcr.c +index d52b52c26..86f1aa078 100644 +--- a/grub-core/term/ns8250-spcr.c ++++ b/grub-core/term/ns8250-spcr.c +@@ -75,6 +75,11 @@ grub_ns8250_spcr_init (void) + config.speed = 115200; + break; + }; ++ ++ /* if base address is 0, it means redirection is disable, so return it */ ++ if (spcr->base_addr.addr == 0) ++ return NULL; ++ + switch (spcr->base_addr.space_id) + { + case GRUB_ACPI_GENADDR_MEM_SPACE: diff --git a/grub-core/term/terminfo.c b/grub-core/term/terminfo.c index 4e534c683..3dbe88e89 100644 --- a/grub-core/term/terminfo.c @@ -34556,7 +41651,7 @@ index 000000000..2e5ebd7d8 +}; +unsigned int certificate_eku_der_len = 916; diff --git a/grub-core/tests/lib/functional_test.c b/grub-core/tests/lib/functional_test.c -index 96781fb39..403fa5c78 100644 +index 96781fb39..31b6b5dab 100644 --- a/grub-core/tests/lib/functional_test.c +++ b/grub-core/tests/lib/functional_test.c @@ -73,6 +73,7 @@ grub_functional_all_tests (grub_extcmd_context_t ctxt __attribute__ ((unused)), @@ -34567,6 +41662,28 @@ index 96781fb39..403fa5c78 100644 grub_dl_load ("sleep_test"); grub_dl_load ("bswap_test"); grub_dl_load ("ctz_test"); +@@ -89,17 +90,18 @@ grub_functional_all_tests (grub_extcmd_context_t ctxt __attribute__ ((unused)), + return GRUB_ERR_NONE; + } + +-static grub_extcmd_t cmd; ++static grub_extcmd_t cmd, cmd_all; + + GRUB_MOD_INIT (functional_test) + { + cmd = grub_register_extcmd ("functional_test", grub_functional_test, 0, 0, + "Run all loaded functional tests.", 0); +- cmd = grub_register_extcmd ("all_functional_test", grub_functional_all_tests, 0, 0, +- "Run all functional tests.", 0); ++ cmd_all = grub_register_extcmd ("all_functional_test", grub_functional_all_tests, 0, 0, ++ "Run all functional tests.", 0); + } + + GRUB_MOD_FINI (functional_test) + { + grub_unregister_extcmd (cmd); ++ grub_unregister_extcmd (cmd_all); + } diff --git a/grub-core/video/ieee1275.c b/grub-core/video/ieee1275.c index ca3d3c3b2..5592e4bb7 100644 --- a/grub-core/video/ieee1275.c @@ -34587,6 +41704,34 @@ index ca3d3c3b2..5592e4bb7 100644 } GRUB_MOD_FINI(ieee1275_fb) +diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c +index ae634fd41..631a89356 100644 +--- a/grub-core/video/readers/jpeg.c ++++ b/grub-core/video/readers/jpeg.c +@@ -339,6 +339,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/grub-core/video/readers/png.c b/grub-core/video/readers/png.c +index 3163e97bf..aa7524b7d 100644 +--- a/grub-core/video/readers/png.c ++++ b/grub-core/video/readers/png.c +@@ -626,7 +626,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/include/grub/arm/efi/console.h b/include/grub/arm/efi/console.h new file mode 100644 index 000000000..1592f6f76 @@ -34684,6 +41829,17 @@ index bcb4d9ba7..9414dc1b9 100644 /* Used for sending commands to the controller. */ #define KEYBOARD_COMMAND_ISREADY(x) !((x) & 0x02) #define KEYBOARD_COMMAND_READ 0x20 +diff --git a/include/grub/auth.h b/include/grub/auth.h +index 747334451..21d5190f0 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/backtrace.h b/include/grub/backtrace.h index 395519762..275cf85e2 100644 --- a/include/grub/backtrace.h @@ -34728,8 +41884,21 @@ index 0c5519387..441a9eca0 100644 +#define UNUSED __attribute__((__unused__)) + #endif /* ! GRUB_COMPILER_HEADER */ +diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h +index d94df68b6..ef307dfd5 100644 +--- a/include/grub/cryptodisk.h ++++ b/include/grub/cryptodisk.h +@@ -187,4 +187,8 @@ 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); ++void grub_cryptodisk_erasesecrets (void); ++#endif + #endif diff --git a/include/grub/dl.h b/include/grub/dl.h -index cd1f46c8b..1e1262a28 100644 +index cd1f46c8b..055bb564e 100644 --- a/include/grub/dl.h +++ b/include/grub/dl.h @@ -27,6 +27,7 @@ @@ -34765,6 +41934,28 @@ index cd1f46c8b..1e1262a28 100644 #define GRUB_MOD_DEP(name) \ static const char grub_module_depend_##name[] \ __attribute__((section(GRUB_MOD_SECTION(moddeps)), ATTRIBUTE_USED)) = #name +@@ -174,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; +@@ -203,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); + @@ -242,11 +245,22 @@ grub_dl_get (const char *name) return 0; } @@ -34852,7 +42043,7 @@ index cd1f46c8b..1e1262a28 100644 #if defined (_mips) diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h -index d44d00ad7..5047ecf28 100644 +index d44d00ad7..24243eb03 100644 --- a/include/grub/efi/api.h +++ b/include/grub/efi/api.h @@ -369,6 +369,16 @@ @@ -35201,16 +42392,7 @@ index d44d00ad7..5047ecf28 100644 struct grub_efi_pxe_mode *mode; } grub_efi_pxe_t; -@@ -1775,6 +2006,8 @@ struct grub_efi_block_io - }; - typedef struct grub_efi_block_io grub_efi_block_io_t; - -+#define GRUB_MOK_POLICY_NX_REQUIRED 0x1 -+ - struct grub_efi_shim_lock_protocol - { - /* -@@ -1809,6 +2042,173 @@ struct grub_efi_load_file2 +@@ -1809,6 +2040,173 @@ struct grub_efi_load_file2 }; typedef struct grub_efi_load_file2 grub_efi_load_file2_t; @@ -35785,10 +42967,18 @@ index 43c0c4372..ac1b8e2fd 100644 grub_efi_uint32_t *attributes, grub_efi_uintn_t *edidsize, diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h -index a5cd99e5a..7eed1bd79 100644 +index a5cd99e5a..48a757789 100644 --- a/include/grub/efi/efi.h +++ b/include/grub/efi/efi.h -@@ -36,6 +36,39 @@ struct linux_arch_kernel_header { +@@ -20,6 +20,7 @@ + #ifndef GRUB_EFI_EFI_HEADER + #define GRUB_EFI_EFI_HEADER 1 + ++#include + #include + #include + #include +@@ -36,6 +37,37 @@ struct linux_arch_kernel_header { struct grub_pe_image_header pe_image_header; }; @@ -35807,12 +42997,10 @@ index a5cd99e5a..7eed1bd79 100644 +}; + +#if defined(__arm__) -+# define GRUB_PE32_PEXX_MAGIC GRUB_PE32_PE32_MAGIC +# define grub_armxx_linux_pe_header grub_arm_linux_pe_header +#endif + +#if defined(__aarch64__) -+# define GRUB_PE32_PEXX_MAGIC GRUB_PE32_PE64_MAGIC +# define grub_armxx_linux_pe_header grub_arm64_linux_pe_header +#endif + @@ -35828,7 +43016,7 @@ index a5cd99e5a..7eed1bd79 100644 /* Functions. */ void *EXPORT_FUNC(grub_efi_locate_protocol) (grub_guid_t *protocol, void *registration); -@@ -44,6 +77,11 @@ EXPORT_FUNC(grub_efi_locate_handle) (grub_efi_locate_search_type_t search_type, +@@ -44,6 +76,11 @@ EXPORT_FUNC(grub_efi_locate_handle) (grub_efi_locate_search_type_t search_type, grub_guid_t *protocol, void *search_key, grub_efi_uintn_t *num_handles); @@ -35840,7 +43028,7 @@ index a5cd99e5a..7eed1bd79 100644 void *EXPORT_FUNC(grub_efi_open_protocol) (grub_efi_handle_t handle, grub_guid_t *protocol, grub_efi_uint32_t attributes); -@@ -61,6 +99,9 @@ EXPORT_FUNC(grub_efi_allocate_fixed) (grub_efi_physical_address_t address, +@@ -61,6 +98,9 @@ EXPORT_FUNC(grub_efi_allocate_fixed) (grub_efi_physical_address_t address, grub_efi_uintn_t pages); void * EXPORT_FUNC(grub_efi_allocate_any_pages) (grub_efi_uintn_t pages); @@ -35850,7 +43038,7 @@ index a5cd99e5a..7eed1bd79 100644 void EXPORT_FUNC(grub_efi_free_pages) (grub_efi_physical_address_t address, grub_efi_uintn_t pages); grub_efi_uintn_t EXPORT_FUNC(grub_efi_find_mmap_size) (void); -@@ -71,6 +112,33 @@ EXPORT_FUNC(grub_efi_get_memory_map) (grub_efi_uintn_t *memory_map_size, +@@ -71,6 +111,33 @@ EXPORT_FUNC(grub_efi_get_memory_map) (grub_efi_uintn_t *memory_map_size, grub_efi_uintn_t *descriptor_size, grub_efi_uint32_t *descriptor_version); void grub_efi_memory_fini (void); @@ -35884,7 +43072,7 @@ index a5cd99e5a..7eed1bd79 100644 grub_efi_loaded_image_t *EXPORT_FUNC(grub_efi_get_loaded_image) (grub_efi_handle_t image_handle); void EXPORT_FUNC(grub_efi_print_device_path) (grub_efi_device_path_t *dp); char *EXPORT_FUNC(grub_efi_get_filename) (grub_efi_device_path_t *dp); -@@ -122,6 +190,9 @@ extern void (*EXPORT_VAR(grub_efi_net_config)) (grub_efi_handle_t hnd, +@@ -122,6 +189,9 @@ extern void (*EXPORT_VAR(grub_efi_net_config)) (grub_efi_handle_t hnd, void * EXPORT_FUNC (grub_efi_find_configuration_table) (const grub_guid_t *target_guid); @@ -35894,12 +43082,12 @@ index a5cd99e5a..7eed1bd79 100644 #if defined(__arm__) || defined(__aarch64__) || defined(__riscv) || defined(__loongarch__) void *EXPORT_FUNC(grub_efi_get_firmware_fdt)(void); grub_err_t EXPORT_FUNC(grub_efi_get_ram_base)(grub_addr_t *); -@@ -130,7 +201,44 @@ grub_err_t EXPORT_FUNC(grub_efi_get_ram_base)(grub_addr_t *); +@@ -130,7 +200,44 @@ grub_err_t EXPORT_FUNC(grub_efi_get_ram_base)(grub_addr_t *); grub_err_t grub_arch_efi_linux_load_image_header(grub_file_t file, struct linux_arch_kernel_header *lh); grub_err_t grub_arch_efi_linux_boot_image(grub_addr_t addr, grub_size_t size, - char *args); -+ char *args, int nx_enabled); ++ char *args); +grub_efi_status_t +EXPORT_FUNC (grub_efi_load_image) (grub_efi_boolean_t boot_policy, + grub_efi_handle_t parent_image_handle, @@ -35940,7 +43128,7 @@ index a5cd99e5a..7eed1bd79 100644 grub_addr_t grub_efi_section_addr (const char *section); -@@ -140,10 +248,7 @@ void grub_efi_init (void); +@@ -140,10 +247,7 @@ void grub_efi_init (void); void grub_efi_fini (void); void grub_efi_set_prefix (void); @@ -35952,7 +43140,7 @@ index a5cd99e5a..7eed1bd79 100644 extern int EXPORT_VAR(grub_efi_is_finished); struct grub_net_card; -@@ -151,4 +256,6 @@ struct grub_net_card; +@@ -151,4 +255,6 @@ struct grub_net_card; grub_efi_handle_t grub_efinet_get_device_handle (struct grub_net_card *card); @@ -36182,10 +43370,10 @@ index 000000000..242d001b6 +#endif /* !GRUB_EFI_HTTP_HEADER */ diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h new file mode 100644 -index 000000000..5b4e626c3 +index 000000000..cd17be506 --- /dev/null +++ b/include/grub/efi/linux.h -@@ -0,0 +1,41 @@ +@@ -0,0 +1,47 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2014 Free Software Foundation, Inc. @@ -36215,6 +43403,7 @@ index 000000000..5b4e626c3 +grub_err_t +EXPORT_FUNC(grub_efi_linux_boot) (grub_addr_t kernel_address, + grub_size_t kernel_size, ++ grub_size_t kernel_start, + grub_off_t handover_offset, + void *kernel_param, int nx_enabled); + @@ -36226,6 +43415,11 @@ index 000000000..5b4e626c3 +grub_err_t +EXPORT_FUNC(grub_efi_check_nx_required) (int *nx_required); + ++grub_err_t ++EXPORT_FUNC(grub_efi_mem_set_att) (grub_addr_t k_address, ++ grub_size_t k_size, ++ grub_size_t k_start, int nx_supported); ++ +#endif /* ! GRUB_EFI_LINUX_HEADER */ diff --git a/include/grub/efi/pci.h b/include/grub/efi/pci.h index b17245549..a90f61042 100644 @@ -36615,9 +43809,18 @@ index 73fa2d34a..9c642ae3f 100644 void grub_util_pull_devmapper (const char *os_dev); diff --git a/include/grub/emu/misc.h b/include/grub/emu/misc.h -index 01056954b..f3a712a8b 100644 +index 01056954b..59b8038c6 100644 --- a/include/grub/emu/misc.h +++ b/include/grub/emu/misc.h +@@ -39,7 +39,7 @@ void grub_fini_all (void); + void grub_find_zpool_from_dir (const char *dir, + char **poolname, char **poolfs); + +-char *grub_make_system_path_relative_to_its_root (const char *path) ++char *EXPORT_FUNC (grub_make_system_path_relative_to_its_root) (const char *path) + WARN_UNUSED_RESULT; + int + grub_util_device_is_mapped (const char *dev); @@ -59,6 +59,8 @@ void EXPORT_FUNC(grub_util_error) (const char *fmt, ...) __attribute__ ((format void EXPORT_FUNC(grub_util_set_kexecute) (void); @@ -36628,19 +43831,30 @@ index 01056954b..f3a712a8b 100644 grub_uint64_t EXPORT_FUNC (grub_util_get_cpu_time_ms) (void); diff --git a/include/grub/err.h b/include/grub/err.h -index 1c07034cd..3c587b9b8 100644 +index 1c07034cd..6379a6baf 100644 --- a/include/grub/err.h +++ b/include/grub/err.h -@@ -86,8 +86,12 @@ struct grub_error_saved +@@ -73,7 +73,9 @@ typedef enum + GRUB_ERR_NET_NO_DOMAIN, + GRUB_ERR_EOF, + GRUB_ERR_BAD_SIGNATURE, +- GRUB_ERR_BAD_FIRMWARE ++ GRUB_ERR_BAD_FIRMWARE, ++ GRUB_ERR_STILL_REFERENCED, ++ GRUB_ERR_RECURSION_DEPTH + } + grub_err_t; + +@@ -86,8 +88,12 @@ struct grub_error_saved extern grub_err_t EXPORT_VAR(grub_errno); extern char EXPORT_VAR(grub_errmsg)[GRUB_MAX_ERRMSG]; -grub_err_t EXPORT_FUNC(grub_error) (grub_err_t n, const char *fmt, ...) - __attribute__ ((format (GNU_PRINTF, 2, 3))); -+grub_err_t EXPORT_FUNC(grub_error) (grub_err_t n, const char *file, const int line, const char *fmt, ...) -+ __attribute__ ((format (GNU_PRINTF, 4, 5))); ++grub_err_t EXPORT_FUNC(grub_error) (grub_err_t n, const char *file, const char *function, const int line, const char *fmt, ...) ++ __attribute__ ((format (GNU_PRINTF, 5, 6))); + -+#define grub_error(n, fmt, ...) grub_error (n, __FILE__, __LINE__, fmt, ##__VA_ARGS__) ++#define grub_error(n, fmt, ...) grub_error (n, __FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__) + + void EXPORT_FUNC(grub_fatal) (const char *fmt, ...) __attribute__ ((noreturn)); @@ -36681,6 +43895,35 @@ index a5bf3a792..d678de063 100644 /* File of which we intend to print a blocklist to the user. */ GRUB_FILE_TYPE_PRINT_BLOCKLIST, /* File we intend to use for test loading or testing speed. */ +diff --git a/include/grub/fs.h b/include/grub/fs.h +index 026bc3bb8..89e4d2b9b 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); +@@ -128,4 +132,6 @@ grub_fs_unregister (grub_fs_t fs) + + grub_fs_t EXPORT_FUNC(grub_fs_probe) (grub_device_t device); + ++#define GRUB_ENV_BTRFS_OFFSET (256 * 1024) ++ + #endif /* ! GRUB_FS_HEADER */ diff --git a/include/grub/gcrypt/.gitignore b/include/grub/gcrypt/.gitignore new file mode 100644 index 000000000..8fbf56462 @@ -36818,10 +44061,10 @@ index 2f69e3f19..0074d55ee 100644 + #endif /* ! GRUB_INIT_HEADER */ diff --git a/include/grub/kernel.h b/include/grub/kernel.h -index abbca5ea3..98edc0863 100644 +index abbca5ea3..f98a780da 100644 --- a/include/grub/kernel.h +++ b/include/grub/kernel.h -@@ -30,7 +30,9 @@ enum +@@ -30,7 +30,10 @@ enum OBJ_TYPE_PREFIX, OBJ_TYPE_PUBKEY, OBJ_TYPE_DTB, @@ -36829,10 +44072,11 @@ index abbca5ea3..98edc0863 100644 + OBJ_TYPE_DISABLE_SHIM_LOCK, + OBJ_TYPE_GPG_PUBKEY, + OBJ_TYPE_X509_PUBKEY, ++ OBJ_TYPE_DISABLE_CLI }; /* The module header. */ -@@ -111,6 +113,11 @@ grub_addr_t grub_modules_get_end (void); +@@ -111,6 +114,11 @@ grub_addr_t grub_modules_get_end (void); #endif @@ -37476,10 +44720,10 @@ index 40531fa82..ebfee4bf0 100644 extern int diff --git a/include/grub/loopback.h b/include/grub/loopback.h new file mode 100644 -index 000000000..3b9a9e32e +index 000000000..915ef65fc --- /dev/null +++ b/include/grub/loopback.h -@@ -0,0 +1,30 @@ +@@ -0,0 +1,31 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2019 Free Software Foundation, Inc. @@ -37507,17 +44751,19 @@ index 000000000..3b9a9e32e + grub_file_t file; + struct grub_loopback *next; + unsigned long id; ++ grub_uint64_t refcnt; +}; + +#endif /* ! GRUB_LOOPBACK_HEADER */ diff --git a/include/grub/menu.h b/include/grub/menu.h -index ee2b5e910..0acdc2aa6 100644 +index ee2b5e910..0e4978dc3 100644 --- a/include/grub/menu.h +++ b/include/grub/menu.h -@@ -20,6 +20,16 @@ +@@ -20,6 +20,31 @@ #ifndef GRUB_MENU_HEADER #define GRUB_MENU_HEADER 1 ++ +struct bls_entry +{ + struct bls_entry *next; @@ -37527,17 +44773,32 @@ index ee2b5e910..0acdc2aa6 100644 + char *filename; + int visible; +}; ++ ++struct grub_blsuki_entry ++{ ++ struct grub_blsuki_entry *next; ++ struct grub_blsuki_entry **prev; ++ struct keyval **keyvals; ++ grub_size_t keyvals_size; ++ int nkeyvals; ++ char *filename; ++ char *dirname; ++ char *devid; ++ bool visible; ++}; ++typedef struct grub_blsuki_entry grub_blsuki_entry_t; + struct grub_menu_entry_class { char *name; -@@ -60,6 +70,9 @@ struct grub_menu_entry +@@ -60,6 +85,10 @@ struct grub_menu_entry /* The next element. */ struct grub_menu_entry *next; + + /* BLS used to populate the entry */ + struct bls_entry *bls; ++ grub_blsuki_entry_t *blsuki; }; typedef struct grub_menu_entry *grub_menu_entry_t; @@ -37545,13 +44806,14 @@ diff --git a/include/grub/mips/linux.h b/include/grub/mips/linux.h new file mode 100644 index 000000000..e69de29bb diff --git a/include/grub/misc.h b/include/grub/misc.h -index 1b35a167f..db517acd5 100644 +index 1b35a167f..4ec42e228 100644 --- a/include/grub/misc.h +++ b/include/grub/misc.h -@@ -35,6 +35,14 @@ +@@ -35,7 +35,15 @@ #define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0])) #define COMPILE_TIME_ASSERT(cond) switch (0) { case 1: case !(cond): ; } +-#define grub_dprintf(condition, ...) grub_real_dprintf(GRUB_FILE, __LINE__, condition, __VA_ARGS__) +#ifndef CONCAT_ +#define CONCAT_(a, b) a ## b +#endif @@ -37560,10 +44822,67 @@ index 1b35a167f..db517acd5 100644 +#define CONCAT(a, b) CONCAT_(a, b) +#endif + - #define grub_dprintf(condition, ...) grub_real_dprintf(GRUB_FILE, __LINE__, condition, __VA_ARGS__) ++#define grub_dprintf(condition, ...) grub_real_dprintf(GRUB_FILE, __FUNCTION__, __LINE__, condition, __VA_ARGS__) void *EXPORT_FUNC(grub_memmove) (void *dest, const void *src, grub_size_t n); -@@ -335,6 +343,7 @@ char *EXPORT_FUNC(grub_strdup) (const char *s) WARN_UNUSED_RESULT; + char *EXPORT_FUNC(grub_strcpy) (char *dest, const char *src); +@@ -64,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) +@@ -87,6 +134,9 @@ char *EXPORT_FUNC(grub_strchr) (const char *s, int c); + char *EXPORT_FUNC(grub_strrchr) (const char *s, int c); + int EXPORT_FUNC(grub_strword) (const char *s, const char *w); + ++char *EXPORT_FUNC(grub_strtok_r) (char *s, const char *delim, char **save_ptr); ++char *EXPORT_FUNC(grub_strtok) (char *s, const char *delim); ++ + /* Copied from gnulib. + Written by Bruno Haible , 2005. */ + static inline char * +@@ -335,6 +385,7 @@ char *EXPORT_FUNC(grub_strdup) (const char *s) WARN_UNUSED_RESULT; char *EXPORT_FUNC(grub_strndup) (const char *s, grub_size_t n) WARN_UNUSED_RESULT; void *EXPORT_FUNC(grub_memset) (void *s, int c, grub_size_t n); grub_size_t EXPORT_FUNC(grub_strlen) (const char *s) WARN_UNUSED_RESULT; @@ -37571,16 +44890,18 @@ index 1b35a167f..db517acd5 100644 /* Replace all `ch' characters of `input' with `with' and copy the result into `output'; return EOS address of `output'. */ -@@ -369,6 +378,7 @@ grub_puts (const char *s) +@@ -369,13 +420,17 @@ grub_puts (const char *s) } int EXPORT_FUNC(grub_puts_) (const char *s); +int EXPORT_FUNC(grub_debug_is_enabled) (void); int EXPORT_FUNC(grub_debug_enabled) (const char *condition); void EXPORT_FUNC(grub_real_dprintf) (const char *file, ++ const char *function, const int line, -@@ -376,6 +386,8 @@ void EXPORT_FUNC(grub_real_dprintf) (const char *file, - const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 4, 5))); + const char *condition, +- const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 4, 5))); ++ const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 5, 6))); int EXPORT_FUNC(grub_printf) (const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 1, 2))); int EXPORT_FUNC(grub_printf_) (const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 1, 2))); +void EXPORT_FUNC(grub_qdprintf) (const char *condition, @@ -37588,7 +44909,7 @@ index 1b35a167f..db517acd5 100644 int EXPORT_FUNC(grub_vprintf) (const char *fmt, va_list args); int EXPORT_FUNC(grub_snprintf) (char *str, grub_size_t n, const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 3, 4))); -@@ -385,7 +397,7 @@ char *EXPORT_FUNC(grub_xasprintf) (const char *fmt, ...) +@@ -385,12 +440,16 @@ char *EXPORT_FUNC(grub_xasprintf) (const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 1, 2))) WARN_UNUSED_RESULT; char *EXPORT_FUNC(grub_xvasprintf) (const char *fmt, va_list args) WARN_UNUSED_RESULT; @@ -37597,7 +44918,16 @@ index 1b35a167f..db517acd5 100644 void EXPORT_FUNC(grub_abort) (void) __attribute__ ((noreturn)); grub_uint64_t EXPORT_FUNC(grub_divmod64) (grub_uint64_t n, grub_uint64_t d, -@@ -521,11 +533,24 @@ void EXPORT_FUNC(grub_real_boot_time) (const char *file, + 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__) || \ + (defined(__riscv) && (__riscv_xlen == 32))) +@@ -521,11 +580,24 @@ void EXPORT_FUNC(grub_real_boot_time) (const char *file, const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 3, 4))); #define grub_boot_time(...) grub_real_boot_time(GRUB_FILE, __LINE__, __VA_ARGS__) #else @@ -37706,7 +45036,7 @@ index 96c2d816b..2481ee1fa 100644 - #endif diff --git a/include/grub/net.h b/include/grub/net.h -index 844e501c1..868c9a2ef 100644 +index 844e501c1..d280acd72 100644 --- a/include/grub/net.h +++ b/include/grub/net.h @@ -29,7 +29,8 @@ @@ -37865,6 +45195,33 @@ index 844e501c1..868c9a2ef 100644 /* Max VLAN id = 4094 */ #define GRUB_NET_MAX_STR_VLAN_LEN (sizeof ("vlanXXXX")) +@@ -540,16 +625,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); +@@ -579,7 +655,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/include/grub/net/efi.h b/include/grub/net/efi.h new file mode 100644 index 000000000..de90d223e @@ -38016,7 +45373,7 @@ index 000000000..de90d223e + +#endif /* ! GRUB_NET_EFI_HEADER */ diff --git a/include/grub/normal.h b/include/grub/normal.h -index 218cbabcc..8839ad85a 100644 +index 218cbabcc..6d2b59db8 100644 --- a/include/grub/normal.h +++ b/include/grub/normal.h @@ -145,7 +145,7 @@ grub_normal_add_menu_entry (int argc, const char **args, char **classes, @@ -38024,10 +45381,53 @@ index 218cbabcc..8839ad85a 100644 const char *users, const char *hotkey, const char *prefix, const char *sourcecode, - int submenu); -+ int submenu, int *index, struct bls_entry *bls); ++ int submenu, int *index, struct bls_entry *bls, grub_blsuki_entry_t *blsuki); grub_err_t grub_normal_set_password (const char *user, const char *password); +diff --git a/include/grub/ntfs.h b/include/grub/ntfs.h +index d1a6af696..77b182acf 100644 +--- a/include/grub/ntfs.h ++++ b/include/grub/ntfs.h +@@ -89,6 +89,30 @@ 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 ++ ++/* ++ * 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, +@@ -134,6 +158,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/include/grub/offsets.h b/include/grub/offsets.h index 871e1cd4c..69211aa79 100644 --- a/include/grub/offsets.h @@ -38089,16 +45489,21 @@ index c6cb32417..acb61dca4 100644 #endif /* ! GRUB_MEMORY_CPU_HEADER */ diff --git a/include/grub/search.h b/include/grub/search.h -index ffd2411ca..9343c66b1 100644 +index ffd2411ca..b6b5c8be1 100644 --- a/include/grub/search.h +++ b/include/grub/search.h -@@ -23,7 +23,8 @@ enum search_flags +@@ -21,9 +21,11 @@ + + enum search_flags { - SEARCH_FLAGS_NONE = 0, - SEARCH_FLAGS_NO_FLOPPY = 1, +- SEARCH_FLAGS_NONE = 0, +- SEARCH_FLAGS_NO_FLOPPY = 1, - SEARCH_FLAGS_EFIDISK_ONLY = 2 -+ SEARCH_FLAGS_EFIDISK_ONLY = 2, -+ SEARCH_FLAGS_ROOTDEV_ONLY = 4 ++ SEARCH_FLAGS_NONE = 0, ++ SEARCH_FLAGS_NO_FLOPPY = 1, ++ SEARCH_FLAGS_EFIDISK_ONLY = 2, ++ SEARCH_FLAGS_ROOTDEV_ONLY = 4, ++ SEARCH_FLAGS_CRYPTODISK_ONLY = 8 }; void grub_search_fs_file (const char *key, const char *var, @@ -38118,10 +45523,10 @@ index 064066e2e..59e030268 100644 #ifdef GRUB_BUILD # define GRUB_CPU_SIZEOF_VOID_P BUILD_SIZEOF_VOID_P diff --git a/include/grub/util/install.h b/include/grub/util/install.h -index 35cf17a8d..59eabb9bb 100644 +index 35cf17a8d..dbf3c216d 100644 --- a/include/grub/util/install.h +++ b/include/grub/util/install.h -@@ -67,6 +67,11 @@ +@@ -67,6 +67,13 @@ N_("SBAT metadata"), 0 }, \ { "disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, \ N_("disable shim_lock verifier"), 0 }, \ @@ -38130,20 +45535,23 @@ index 35cf17a8d..59eabb9bb 100644 + { "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 } -@@ -129,7 +134,8 @@ enum grub_install_options { +@@ -129,7 +136,9 @@ enum grub_install_options { GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS, GRUB_INSTALL_OPTIONS_DTB, GRUB_INSTALL_OPTIONS_SBAT, - GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK + 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; -@@ -185,11 +191,12 @@ void +@@ -185,13 +194,15 @@ void grub_install_generate_image (const char *dir, const char *prefix, FILE *out, const char *outname, char *mods[], @@ -38157,10 +45565,27 @@ index 35cf17a8d..59eabb9bb 100644 - int note, + 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 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/include/grub/util/misc.h b/include/grub/util/misc.h +index e9e0a6724..bfce06558 100644 +--- a/include/grub/util/misc.h ++++ b/include/grub/util/misc.h +@@ -36,7 +36,7 @@ char *grub_util_read_image (const char *path); + void grub_util_load_image (const char *path, char *buf); + void grub_util_write_image (const char *img, size_t size, FILE *out, + const char *name); +-void grub_util_write_image_at (const void *img, size_t size, off_t offset, ++void grub_util_write_image_at (const void *img, size_t size, grub_off_t offset, + FILE *out, const char *name); + + char *make_system_path_relative_to_its_root (const char *path); diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h -index 3819a6744..6f1da89b9 100644 +index 3819a6744..881e3031f 100644 --- a/include/grub/util/mkimage.h +++ b/include/grub/util/mkimage.h @@ -51,12 +51,12 @@ grub_mkimage_load_image64 (const char *kernel_path, @@ -38168,13 +45593,13 @@ index 3819a6744..6f1da89b9 100644 void grub_mkimage_generate_elf32 (const struct grub_install_image_target_desc *image_target, - int note, char **core_img, size_t *core_size, -+ int note, size_t appsig_size, char **core_img, size_t *core_size, ++ int note, size_t appsig_size, char *sbat, char **core_img, size_t *core_size, Elf32_Addr target_addr, struct grub_mkimage_layout *layout); void grub_mkimage_generate_elf64 (const struct grub_install_image_target_desc *image_target, - int note, char **core_img, size_t *core_size, -+ int note, size_t appsig_size, char **core_img, size_t *core_size, ++ int note, size_t appsig_size, char *sbat, char **core_img, size_t *core_size, Elf64_Addr target_addr, struct grub_mkimage_layout *layout); @@ -38236,6 +45661,53 @@ index 000000000..f507e7741 +/grub.pot +/remove-potcdate.sed +/stamp-po +diff --git a/tests/grub_script_eval.in b/tests/grub_script_eval.in +index c97b78d77..9c6211042 100644 +--- a/tests/grub_script_eval.in ++++ b/tests/grub_script_eval.in +@@ -3,4 +3,12 @@ + eval echo "Hello world" + valname=tst + eval $valname=hi +-echo $tst +\ No newline at end of file ++echo $tst ++ ++if eval " ++false ++"; then ++ echo should have failed ++else ++ echo failed as expected ++fi +diff --git a/tests/printf_unit_test.c b/tests/printf_unit_test.c +index 098c29fd9..f2de187b0 100644 +--- a/tests/printf_unit_test.c ++++ b/tests/printf_unit_test.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + + #define MSG "printf test failed: %s, %s", real, expected + +@@ -73,6 +74,15 @@ printf_test (void) + grub_snprintf (real, sizeof (real), "%%0%dd ", 1); + snprintf (expected, sizeof (expected), "%%0%dd ", 1); + grub_test_assert (strcmp (real, expected) == 0, MSG); ++ grub_snprintf (real, sizeof (real), "%zd %zd %zd", (ssize_t) -1, (ssize_t) (SIZE_MAX >> 1), (ssize_t) 42); ++ snprintf (expected, sizeof (expected), "%zd %zd %zd", (ssize_t) -1, (ssize_t) (SIZE_MAX >> 1), (ssize_t) 42); ++ grub_test_assert (strcmp (real, expected) == 0, MSG); ++ grub_snprintf (real, sizeof (real), "%zu %zu %zu", (size_t) 0, (size_t) SIZE_MAX, (size_t) 42); ++ snprintf (expected, sizeof (expected), "%zu %zu %zu", (size_t) 0, (size_t) SIZE_MAX, (size_t) 42); ++ grub_test_assert (strcmp (real, expected) == 0, MSG); ++ grub_snprintf (real, sizeof (real), "%zx %zx %zx", (ssize_t) (SIZE_MAX >> 1), (size_t) SIZE_MAX, (size_t) 0xdeadbeefU); ++ snprintf (expected, sizeof (expected), "%zx %zx %zx", (ssize_t) (SIZE_MAX >> 1), (size_t) SIZE_MAX, (size_t) 0xdeadbeefU); ++ grub_test_assert (strcmp (real, expected) == 0, MSG); + } + + GRUB_UNIT_TEST ("printf_unit_test", printf_test); diff --git a/tests/test_asn1.in b/tests/test_asn1.in new file mode 100644 index 000000000..8173c5c27 @@ -38355,10 +45827,23 @@ index ebcdd8f5e..f044a880a 100644 sizeof ("GRUB_DISTRIBUTOR=") - 1) == 0) { diff --git a/util/grub-editenv.c b/util/grub-editenv.c -index db6f187cc..948eec8a1 100644 +index db6f187cc..48611e4e1 100644 --- a/util/grub-editenv.c +++ b/util/grub-editenv.c -@@ -53,6 +53,9 @@ static struct argp_option options[] = { +@@ -23,8 +23,11 @@ + #include + #include + #include +-#include ++#include + #include ++#include ++#include ++#include + + #include + #include +@@ -53,6 +56,9 @@ static struct argp_option options[] = { /* TRANSLATORS: "unset" is a keyword. It's a summary of "unset" subcommand. */ {N_("unset [NAME ...]"), 0, 0, OPTION_DOC|OPTION_NO_USAGE, N_("Delete variables."), 0}, @@ -38368,10 +45853,367 @@ index db6f187cc..948eec8a1 100644 {0, 0, 0, OPTION_DOC, N_("Options:"), -1}, {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, -@@ -253,6 +256,51 @@ unset_variables (const char *name, int argc, char *argv[]) +@@ -120,6 +126,186 @@ block, use `rm %s'."), + NULL, help_filter, NULL + }; + ++struct fs_envblk_spec { ++ const char *fs_name; ++ off_t offset; ++ size_t size; ++}; ++typedef struct fs_envblk_spec fs_envblk_spec_t; ++ ++static grub_envblk_t fs_envblk_open (grub_envblk_t envblk); ++static void fs_envblk_write (grub_envblk_t envblk); ++ ++struct fs_envblk_ops { ++ grub_envblk_t (*open) (grub_envblk_t); ++ void (*write) (grub_envblk_t); ++}; ++typedef struct fs_envblk_ops fs_envblk_ops_t; ++ ++struct fs_envblk { ++ fs_envblk_spec_t *spec; ++ fs_envblk_ops_t *ops; ++ const char *dev; ++}; ++typedef struct fs_envblk *fs_envblk_t; ++ ++static fs_envblk_ops_t fs_envblk_ops = { ++ .open = fs_envblk_open, ++ .write = fs_envblk_write ++}; ++ ++/* ++ * fs_envblk_spec describes the file-system specific layout of reserved raw ++ * blocks used as environment blocks. At present only Btrfs is supported. Other ++ * file-systems may be added if they provide a similar facility and avoid the ++ * limitation of writing to COW. ++ * ++ * Note: If this table is modified, also update ++ * grub-core/fs/btrfs.c::btrfs_head, which defines the layout in the Btrfs ++ * header and exports GRUB_ENV_BTRFS_OFFSET, so that both stay consistent. ++ */ ++static fs_envblk_spec_t fs_envblk_spec[] = { ++ { "btrfs", GRUB_ENV_BTRFS_OFFSET, GRUB_DISK_SECTOR_SIZE }, ++ { NULL, 0, 0 } ++}; ++ ++static fs_envblk_t fs_envblk = NULL; ++ ++static void ++fs_envblk_init (const char *fs_name, const char *dev) ++{ ++ fs_envblk_spec_t *p; ++ ++ if (fs_name == NULL || dev == NULL) ++ return; ++ ++ for (p = fs_envblk_spec; p->fs_name != NULL; p++) ++ { ++ if (strcmp (fs_name, p->fs_name) == 0) ++ { ++ if (fs_envblk == NULL) ++ fs_envblk = xmalloc (sizeof (*fs_envblk)); ++ fs_envblk->spec = p; ++ fs_envblk->dev = xstrdup (dev); ++ fs_envblk->ops = &fs_envblk_ops; ++ break; ++ } ++ } ++} ++ ++static int ++read_env_block_var (const char *varname, const char *value, void *hook_data) ++{ ++ grub_envblk_t *p_envblk = (grub_envblk_t *) hook_data; ++ off_t off; ++ size_t sz; ++ char *p, *buf; ++ FILE *fp; ++ ++ if (p_envblk == NULL || fs_envblk == NULL) ++ return 1; ++ ++ if (strcmp (varname, "env_block") != 0) ++ return 0; ++ ++ off = strtol (value, &p, 10); ++ if (*p == '+') ++ sz = strtol (p + 1, &p, 10); ++ else ++ return 0; ++ ++ if (*p != '\0' || sz == 0) ++ return 0; ++ ++ off <<= GRUB_DISK_SECTOR_BITS; ++ sz <<= GRUB_DISK_SECTOR_BITS; ++ ++ fp = grub_util_fopen (fs_envblk->dev, "rb"); ++ if (fp == NULL) ++ grub_util_error (_("cannot open `%s': %s"), fs_envblk->dev, strerror (errno)); ++ ++ if (fseek (fp, off, SEEK_SET) < 0) ++ grub_util_error (_("cannot seek `%s': %s"), fs_envblk->dev, strerror (errno)); ++ ++ buf = xmalloc (sz); ++ if ((fread (buf, 1, sz, fp)) != sz) ++ grub_util_error (_("cannot read `%s': %s"), fs_envblk->dev, strerror (errno)); ++ ++ fclose (fp); ++ ++ *p_envblk = grub_envblk_open (buf, sz); ++ ++ return 1; ++} ++ ++static void ++create_env_on_block (void) ++{ ++ FILE *fp; ++ char *buf; ++ const char *device; ++ off_t offset; ++ size_t size; ++ ++ if (fs_envblk == NULL) ++ return; ++ ++ device = fs_envblk->dev; ++ offset = fs_envblk->spec->offset; ++ size = fs_envblk->spec->size; ++ ++ fp = grub_util_fopen (device, "r+b"); ++ if (fp == NULL) ++ grub_util_error (_("cannot open `%s': %s"), device, strerror (errno)); ++ ++ buf = xmalloc (size); ++ memcpy (buf, GRUB_ENVBLK_SIGNATURE, sizeof (GRUB_ENVBLK_SIGNATURE) - 1); ++ memset (buf + sizeof (GRUB_ENVBLK_SIGNATURE) - 1, '#', size - sizeof (GRUB_ENVBLK_SIGNATURE) + 1); ++ ++ if (fseek (fp, offset, SEEK_SET) < 0) ++ grub_util_error (_("cannot seek `%s': %s"), device, strerror (errno)); ++ ++ if (fwrite (buf, 1, size, fp) != size) ++ grub_util_error (_("cannot write to `%s': %s"), device, strerror (errno)); ++ ++ grub_util_file_sync (fp); ++ free (buf); ++ fclose (fp); ++} ++ ++static grub_envblk_t ++fs_envblk_open (grub_envblk_t envblk) ++{ ++ grub_envblk_t envblk_on_block = NULL; ++ char *val; ++ off_t offset; ++ size_t size; ++ ++ if (envblk == NULL) ++ return NULL; ++ ++ offset = fs_envblk->spec->offset; ++ size = fs_envblk->spec->size; ++ ++ grub_envblk_iterate (envblk, &envblk_on_block, read_env_block_var); ++ ++ if (envblk_on_block != NULL && grub_envblk_size (envblk_on_block) == size) ++ return envblk_on_block; ++ ++ create_env_on_block (); ++ ++ offset = offset >> GRUB_DISK_SECTOR_BITS; ++ size = (size + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS; ++ ++ val = xasprintf ("%lld+%zu", (long long) offset, size); ++ if (grub_envblk_set (envblk, "env_block", val) == 0) ++ grub_util_error ("%s", _("environment block too small")); ++ grub_envblk_iterate (envblk, &envblk_on_block, read_env_block_var); ++ free (val); ++ ++ return envblk_on_block; ++} ++ + static grub_envblk_t + open_envblk_file (const char *name) + { +@@ -182,10 +368,17 @@ static void + list_variables (const char *name) + { + grub_envblk_t envblk; ++ grub_envblk_t envblk_on_block = NULL; + + envblk = open_envblk_file (name); ++ grub_envblk_iterate (envblk, &envblk_on_block, read_env_block_var); + grub_envblk_iterate (envblk, NULL, print_var); grub_envblk_close (envblk); ++ if (envblk_on_block != NULL) ++ { ++ grub_envblk_iterate (envblk_on_block, NULL, print_var); ++ grub_envblk_close (envblk_on_block); ++ } } + static void +@@ -208,12 +401,68 @@ write_envblk (const char *name, grub_envblk_t envblk) + fclose (fp); + } + ++static void ++fs_envblk_write (grub_envblk_t envblk) ++{ ++ FILE *fp; ++ const char *device; ++ off_t offset; ++ size_t size; ++ ++ if (envblk == NULL) ++ return; ++ ++ device = fs_envblk->dev; ++ offset = fs_envblk->spec->offset; ++ size = fs_envblk->spec->size; ++ ++ if (grub_envblk_size (envblk) > size) ++ grub_util_error ("%s", _("environment block too small")); ++ ++ fp = grub_util_fopen (device, "r+b"); ++ ++ if (fp == NULL) ++ grub_util_error (_("cannot open `%s': %s"), device, strerror (errno)); ++ ++ if (fseek (fp, offset, SEEK_SET) < 0) ++ grub_util_error (_("cannot seek `%s': %s"), device, strerror (errno)); ++ ++ if (fwrite (grub_envblk_buffer (envblk), 1, grub_envblk_size (envblk), fp) != grub_envblk_size (envblk)) ++ grub_util_error (_("cannot write to `%s': %s"), device, strerror (errno)); ++ ++ grub_util_file_sync (fp); ++ fclose (fp); ++} ++ ++struct var_lookup_ctx { ++ const char *varname; ++ bool found; ++}; ++typedef struct var_lookup_ctx var_lookup_ctx_t; ++ ++static int ++var_lookup_iter (const char *varname, const char *value __attribute__ ((unused)), void *hook_data) ++{ ++ var_lookup_ctx_t *ctx = (var_lookup_ctx_t *) hook_data; ++ ++ if (grub_strcmp (ctx->varname, varname) == 0) ++ { ++ ctx->found = true; ++ return 1; ++ } ++ return 0; ++} ++ + static void + set_variables (const char *name, int argc, char *argv[]) + { + grub_envblk_t envblk; ++ grub_envblk_t envblk_on_block = NULL; + + envblk = open_envblk_file (name); ++ if (fs_envblk != NULL) ++ envblk_on_block = fs_envblk->ops->open (envblk); ++ + while (argc) + { + char *p; +@@ -224,27 +473,123 @@ set_variables (const char *name, int argc, char *argv[]) + + *(p++) = 0; + +- if (! grub_envblk_set (envblk, argv[0], p)) +- grub_util_error ("%s", _("environment block too small")); +- ++ if (((strcmp (argv[0], "next_entry") == 0) || ++ (strcmp (argv[0], "boot_counter") == 0) || ++ (strcmp (argv[0], "boot_indeterminate") == 0) || ++ (strcmp (argv[0], "boot_success") == 0) || ++ (strcmp (argv[0], "menu_show_once") == 0) || ++ (strcmp (argv[0], "menu_show_once_timeout") == 0)) ++ && envblk_on_block != NULL) ++ { ++ if (grub_envblk_set (envblk_on_block, argv[0], p) == 0) ++ grub_util_error ("%s", _("environment block too small")); ++ goto next; ++ } ++ ++ if (strcmp (argv[0], "env_block") == 0) ++ { ++ grub_util_warn (_("can't set env_block as it's read-only")); ++ goto next; ++ } ++ ++ if (grub_envblk_set (envblk, argv[0], p) == 0) ++ grub_util_error ("%s", _("environment block too small")); ++ ++ if (envblk_on_block != NULL) ++ { ++ var_lookup_ctx_t ctx = { ++ .varname = argv[0], ++ .found = false ++ }; ++ ++ grub_envblk_iterate (envblk_on_block, &ctx, var_lookup_iter); ++ if (ctx.found == true) ++ grub_envblk_delete (envblk_on_block, argv[0]); ++ } ++ next: + argc--; + argv++; + } + + write_envblk (name, envblk); + grub_envblk_close (envblk); ++ ++ if (envblk_on_block != NULL) ++ { ++ fs_envblk->ops->write (envblk_on_block); ++ grub_envblk_close (envblk_on_block); ++ } + } + + static void + unset_variables (const char *name, int argc, char *argv[]) + { + grub_envblk_t envblk; ++ grub_envblk_t envblk_on_block = NULL; + + envblk = open_envblk_file (name); ++ ++ if (fs_envblk != NULL) ++ envblk_on_block = fs_envblk->ops->open (envblk); ++ + while (argc) + { + grub_envblk_delete (envblk, argv[0]); + ++ if (envblk_on_block != NULL) ++ grub_envblk_delete (envblk_on_block, argv[0]); ++ ++ argc--; ++ argv++; ++ } ++ ++ write_envblk (name, envblk); ++ grub_envblk_close (envblk); ++ ++ if (envblk_on_block != NULL) ++ { ++ fs_envblk->ops->write (envblk_on_block); ++ grub_envblk_close (envblk_on_block); ++ } ++} ++ +struct get_int_value_params { + char *varname; + int value; @@ -38409,18 +46251,132 @@ index db6f187cc..948eec8a1 100644 + if (! grub_envblk_set (envblk, argv[0], buf)) + grub_util_error ("%s", _("environment block too small")); + -+ argc--; -+ argv++; + argc--; + argv++; + } +@@ -253,6 +598,111 @@ unset_variables (const char *name, int argc, char *argv[]) + grub_envblk_close (envblk); + } + ++static bool ++is_abstraction (grub_device_t dev) ++{ ++ if (dev == NULL || dev->disk == NULL) ++ return false; ++ ++ if (dev->disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID || ++ dev->disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID) ++ return true; ++ ++ return false; ++} ++ ++static void ++probe_fs_envblk (fs_envblk_spec_t *spec) ++{ ++ char **grub_devices = NULL; ++ char **curdev, **curdrive; ++ size_t ndev = 0; ++ char **grub_drives = NULL; ++ grub_device_t grub_dev = NULL; ++ grub_fs_t grub_fs = NULL; ++ bool have_abstraction = false; ++ ++ grub_util_biosdisk_init (DEFAULT_DEVICE_MAP); ++ grub_init_all (); ++ grub_gcry_init_all (); ++ ++ grub_lvm_fini (); ++ grub_mdraid09_fini (); ++ grub_mdraid1x_fini (); ++ grub_diskfilter_fini (); ++ grub_diskfilter_init (); ++ grub_mdraid09_init (); ++ grub_mdraid1x_init (); ++ grub_lvm_init (); ++ ++ grub_devices = grub_guess_root_devices (DEFAULT_DIRECTORY); ++ ++ if (grub_devices == NULL || grub_devices[0] == NULL) ++ { ++ grub_util_warn (_("cannot find a device for %s (is /dev mounted?)"), DEFAULT_DIRECTORY); ++ goto cleanup; + } + -+ write_envblk (name, envblk); -+ grub_envblk_close (envblk); ++ for (curdev = grub_devices; *curdev != NULL; curdev++, ndev++) ++ grub_util_pull_device (*curdev); ++ ++ grub_drives = xcalloc ((ndev + 1), sizeof (grub_drives[0])); ++ ++ for (curdev = grub_devices, curdrive = grub_drives; *curdev != NULL; curdev++, ++ curdrive++) ++ { ++ *curdrive = grub_util_get_grub_dev (*curdev); ++ if (*curdrive == NULL) ++ { ++ grub_util_warn (_("cannot find a GRUB drive for %s. Check your device.map"), ++ *curdev); ++ goto cleanup; ++ } ++ } ++ *curdrive = NULL; ++ ++ grub_dev = grub_device_open (grub_drives[0]); ++ if (grub_dev == NULL) ++ { ++ grub_util_warn (_("cannot open device %s: %s"), grub_drives[0], grub_errmsg); ++ grub_errno = GRUB_ERR_NONE; ++ goto cleanup; ++ } ++ ++ grub_fs = grub_fs_probe (grub_dev); ++ if (grub_fs == NULL) ++ { ++ grub_util_warn (_("cannot probe fs for %s: %s"), grub_drives[0], grub_errmsg); ++ grub_errno = GRUB_ERR_NONE; ++ goto cleanup; ++ } ++ ++ have_abstraction = is_abstraction (grub_dev); ++ for (curdrive = grub_drives + 1; *curdrive != NULL && have_abstraction == false; curdrive++) ++ { ++ grub_device_t dev = grub_device_open (*curdrive); ++ ++ if (dev == NULL) ++ continue; ++ have_abstraction = is_abstraction (dev); ++ grub_device_close (dev); ++ } ++ ++ if (have_abstraction == false) ++ fs_envblk_init (grub_fs->name, grub_devices[0]); ++ ++ cleanup: ++ if (grub_devices != NULL) ++ for (curdev = grub_devices; *curdev != NULL; curdev++) ++ free (*curdev); ++ free (grub_devices); ++ free (grub_drives); ++ grub_device_close (grub_dev); ++ grub_gcry_fini_all (); ++ grub_fini_all (); ++ grub_util_biosdisk_fini (); +} + int main (int argc, char *argv[]) { -@@ -292,6 +340,8 @@ main (int argc, char *argv[]) +@@ -284,6 +734,9 @@ main (int argc, char *argv[]) + command = argv[curindex++]; + } + ++ if (strcmp (filename, DEFAULT_ENVBLK_PATH) == 0) ++ probe_fs_envblk (fs_envblk_spec); ++ + if (strcmp (command, "create") == 0) + grub_util_create_envblk_file (filename); + else if (strcmp (command, "list") == 0) +@@ -292,6 +745,8 @@ main (int argc, char *argv[]) set_variables (filename, argc - curindex, argv + curindex); else if (strcmp (command, "unset") == 0) unset_variables (filename, argc - curindex, argv + curindex); @@ -38545,7 +46501,7 @@ index 000000000..f71bc6436 + echo export GRUB_UPDATE_DEFAULT_KERNEL +fi diff --git a/util/grub-install-common.c b/util/grub-install-common.c -index ce854d86f..67afc2eed 100644 +index ce854d86f..42aec141e 100644 --- a/util/grub-install-common.c +++ b/util/grub-install-common.c @@ -368,7 +368,7 @@ char *grub_install_themes_directory = NULL; @@ -38557,7 +46513,7 @@ index ce854d86f..67afc2eed 100644 static const char *whitelist[] = { "part_msdos", "biosdisk", "affs", "afs", "bfs", "archelp", -@@ -465,11 +465,15 @@ static char **pubkeys; +@@ -465,11 +465,16 @@ static char **pubkeys; static size_t npubkeys; static char *sbat; static int disable_shim_lock; @@ -38565,6 +46521,7 @@ index ce854d86f..67afc2eed 100644 +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) @@ -38573,7 +46530,7 @@ index ce854d86f..67afc2eed 100644 switch (key) { case GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS: -@@ -504,6 +508,12 @@ grub_install_parse (int key, char *arg) +@@ -504,6 +509,15 @@ grub_install_parse (int key, char *arg) case GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK: disable_shim_lock = 1; return 1; @@ -38582,11 +46539,14 @@ index ce854d86f..67afc2eed 100644 + sizeof (x509keys[0]) + * (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++; -@@ -567,6 +577,12 @@ grub_install_parse (int key, char *arg) +@@ -567,6 +581,12 @@ grub_install_parse (int key, char *arg) grub_util_error (_("Unrecognized compression `%s'"), arg); case GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE: return 1; @@ -38599,7 +46559,7 @@ index ce854d86f..67afc2eed 100644 default: return 0; } -@@ -628,6 +644,9 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, +@@ -628,6 +648,9 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, for (pk = pubkeys; pk < pubkeys + npubkeys; pk++) slen += sizeof (" --pubkey ''") + grub_strlen (*pk); @@ -38609,7 +46569,7 @@ index ce854d86f..67afc2eed 100644 for (md = modules.entries; *md; md++) slen += sizeof (" ''") + grub_strlen (*md); -@@ -668,6 +687,14 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, +@@ -668,6 +691,14 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, *p++ = '\''; } @@ -38624,32 +46584,39 @@ index ce854d86f..67afc2eed 100644 for (md = modules.entries; *md; md++) { *p++ = ' '; -@@ -679,9 +706,11 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, +@@ -679,11 +710,15 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, *p = '\0'; grub_util_info ("grub-mkimage --directory '%s' --prefix '%s' --output '%s'" - " --format '%s' --compression '%s'%s%s%s\n", + " --format '%s' --compression '%s'" + " --appended-signture-size %zu %s%s%s\n", ++ " --format '%s' --compression '%s'%s%s%s%s\n", dir, prefix, outname, mkimage_target, compnames[compression], + appsig_size, note ? " --note" : "", - disable_shim_lock ? " --disable-shim-lock" : "", s); +- disable_shim_lock ? " --disable-shim-lock" : "", s); ++ disable_shim_lock ? " --disable-shim-lock" : "", ++ disable_cli ? " --disable-cli" : "", s); free (s); -@@ -692,8 +721,10 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, + + tgt = grub_install_get_image_target (mkimage_target); +@@ -692,9 +727,11 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, grub_install_generate_image (dir, prefix, fp, outname, modules.entries, memdisk_path, - pubkeys, npubkeys, config_path, tgt, - note, compression, dtb, sbat, +- disable_shim_lock); + pubkeys, npubkeys, + 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-install.c b/util/grub-install.c index 7dc5657bb..314b6143b 100644 --- a/util/grub-install.c @@ -39084,7 +47051,7 @@ index 7624d7808..e8a914021 100644 add_pixel (&data, &mask, glyph->bitmap.buffer[i / 8 + j * glyph->bitmap.pitch] & diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c -index c0d559937..e1f111278 100644 +index c0d559937..13bdc6cf0 100644 --- a/util/grub-mkimage.c +++ b/util/grub-mkimage.c @@ -75,7 +75,8 @@ static struct argp_option options[] = { @@ -39097,15 +47064,17 @@ index c0d559937..e1f111278 100644 /* TRANSLATORS: NOTE is a name of segment. */ {"note", 'n', 0, 0, N_("add NOTE segment for CHRP IEEE1275"), 0}, {"output", 'o', N_("FILE"), 0, N_("output a generated image to FILE [default=stdout]"), 0}, -@@ -84,6 +85,7 @@ static struct argp_option options[] = { +@@ -83,7 +84,9 @@ 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 } }; -@@ -123,11 +125,14 @@ struct arguments +@@ -123,11 +126,15 @@ struct arguments char *dtb; char **pubkeys; size_t npubkeys; @@ -39117,10 +47086,11 @@ index c0d559937..e1f111278 100644 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; }; -@@ -138,6 +143,7 @@ argp_parser (int key, char *arg, struct argp_state *state) +@@ -138,6 +145,7 @@ argp_parser (int key, char *arg, struct argp_state *state) /* Get the input argument from argp_parse, which we know is a pointer to our arguments structure. */ struct arguments *arguments = state->input; @@ -39128,7 +47098,7 @@ index c0d559937..e1f111278 100644 switch (key) { -@@ -170,6 +176,13 @@ argp_parser (int key, char *arg, struct argp_state *state) +@@ -170,6 +178,13 @@ argp_parser (int key, char *arg, struct argp_state *state) arguments->note = 1; break; @@ -39142,7 +47112,7 @@ index c0d559937..e1f111278 100644 case 'm': if (arguments->memdisk) free (arguments->memdisk); -@@ -196,6 +209,13 @@ argp_parser (int key, char *arg, struct argp_state *state) +@@ -196,6 +211,13 @@ argp_parser (int key, char *arg, struct argp_state *state) arguments->pubkeys[arguments->npubkeys++] = xstrdup (arg); break; @@ -39156,7 +47126,18 @@ index c0d559937..e1f111278 100644 case 'c': if (arguments->config) free (arguments->config); -@@ -322,10 +342,12 @@ main (int argc, char *argv[]) +@@ -239,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; +@@ -322,10 +348,13 @@ main (int argc, char *argv[]) grub_install_generate_image (arguments.dir, arguments.prefix, fp, arguments.output, arguments.modules, arguments.memdisk, arguments.pubkeys, @@ -39168,12 +47149,13 @@ index c0d559937..e1f111278 100644 - arguments.sbat, arguments.disable_shim_lock); + 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/grub-mkimagexx.c b/util/grub-mkimagexx.c -index e50b29533..9488f0525 100644 +index e50b29533..b99305448 100644 --- a/util/grub-mkimagexx.c +++ b/util/grub-mkimagexx.c @@ -85,6 +85,15 @@ struct grub_ieee1275_note @@ -39192,30 +47174,109 @@ index e50b29533..9488f0525 100644 #define GRUB_XEN_NOTE_NAME "Xen" struct fixup_block_list -@@ -208,7 +217,7 @@ grub_arm_reloc_jump24 (grub_uint32_t *target, Elf32_Addr sym_addr) +@@ -107,6 +116,14 @@ struct section_metadata + const char *strtab; + }; + ++#define GRUB_SBAT_NOTE_NAME ".sbat" ++#define GRUB_SBAT_NOTE_TYPE 0x53424154 /* "SBAT" */ ++ ++struct grub_sbat_note { ++ Elf32_Nhdr header; ++ char name[ALIGN_UP(sizeof(GRUB_SBAT_NOTE_NAME), 4)]; ++}; ++ + static int + is_relocatable (const struct grub_install_image_target_desc *image_target) + { +@@ -208,7 +225,7 @@ grub_arm_reloc_jump24 (grub_uint32_t *target, Elf32_Addr sym_addr) void SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc *image_target, - int note, char **core_img, size_t *core_size, -+ int note, size_t appsig_size, char **core_img, size_t *core_size, ++ int note, size_t appsig_size, char *sbat, char **core_img, size_t *core_size, Elf_Addr target_addr, struct grub_mkimage_layout *layout) { -@@ -222,6 +231,12 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc +@@ -217,10 +234,23 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc + Elf_Ehdr *ehdr; + Elf_Phdr *phdr; + Elf_Shdr *shdr; +- int header_size, footer_size = 0; ++ int header_size, footer_size = 0, footer_offset = 0; + int phnum = 1; int shnum = 4; int string_size = sizeof (".text") + sizeof ("mods") + 1; - ++ char *footer; ++ ++ if (sbat) ++ { ++ phnum++; ++ footer_size += ALIGN_UP (sizeof (struct grub_sbat_note) + layout->sbat_size, 4); ++ } ++ + if (appsig_size) + { + phnum++; + footer_size += ALIGN_UP(sizeof (struct grub_appended_signature_note) + appsig_size, 4); + } -+ + if (image_target->id != IMAGE_LOONGSON_ELF) phnum += 2; - -@@ -485,6 +500,28 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc +@@ -248,6 +278,7 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc + ehdr = (void *) elf_img; + phdr = (void *) (elf_img + sizeof (*ehdr)); + shdr = (void *) (elf_img + sizeof (*ehdr) + phnum * sizeof (*phdr)); ++ footer = elf_img + program_size + header_size; + memcpy (ehdr->e_ident, ELFMAG, SELFMAG); + ehdr->e_ident[EI_CLASS] = ELFCLASSXX; + if (!image_target->bigendian) +@@ -420,6 +451,8 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc + phdr->p_filesz = grub_host_to_target32 (XEN_NOTE_SIZE); + phdr->p_memsz = 0; phdr->p_offset = grub_host_to_target32 (header_size + program_size); ++ footer = ptr; ++ footer_offset = XEN_NOTE_SIZE; + } + + if (image_target->id == IMAGE_XEN_PVH) +@@ -453,6 +486,8 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc + phdr->p_filesz = grub_host_to_target32 (XEN_PVH_NOTE_SIZE); + phdr->p_memsz = 0; + phdr->p_offset = grub_host_to_target32 (header_size + program_size); ++ footer = ptr; ++ footer_offset = XEN_PVH_NOTE_SIZE; + } + + if (note) +@@ -483,8 +518,54 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc + phdr->p_filesz = grub_host_to_target32 (note_size); + phdr->p_memsz = 0; + phdr->p_offset = grub_host_to_target32 (header_size + program_size); ++ footer = (elf_img + program_size + header_size + note_size); ++ footer_offset += note_size; ++ } ++ ++ if (sbat) ++ { ++ int note_size = ALIGN_UP (sizeof (struct grub_sbat_note) + layout->sbat_size, 4); ++ struct grub_sbat_note *note_ptr = (struct grub_sbat_note *) footer; ++ ++ note_ptr->header.n_namesz = grub_host_to_target32 (sizeof (GRUB_SBAT_NOTE_NAME)); ++ note_ptr->header.n_descsz = grub_host_to_target32 (ALIGN_UP(layout->sbat_size, 4)); ++ note_ptr->header.n_type = grub_host_to_target32 (GRUB_SBAT_NOTE_TYPE); ++ memcpy (note_ptr->name, GRUB_SBAT_NOTE_NAME, sizeof (GRUB_SBAT_NOTE_NAME)); ++ memcpy ((char *)(note_ptr + 1), sbat, layout->sbat_size); ++ ++ phdr++; ++ phdr->p_type = grub_host_to_target32 (PT_NOTE); ++ phdr->p_flags = grub_host_to_target32 (PF_R); ++ phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof); ++ phdr->p_vaddr = 0; ++ phdr->p_paddr = 0; ++ phdr->p_filesz = grub_host_to_target32 (note_size); ++ phdr->p_memsz = 0; ++ phdr->p_offset = grub_host_to_target32 (header_size + program_size + footer_offset); } + if (appsig_size) { @@ -39843,7 +47904,7 @@ index 000000000..d8005e5a1 +fi diff --git a/util/grub-switch-to-blscfg.in b/util/grub-switch-to-blscfg.in new file mode 100644 -index 000000000..a851424be +index 000000000..1bdf7e331 --- /dev/null +++ b/util/grub-switch-to-blscfg.in @@ -0,0 +1,317 @@ @@ -39913,7 +47974,7 @@ index 000000000..a851424be +# Print the usage. +usage () { + gettext_printf "Usage: %s\n" "$self" -+ gettext "Switch to BLS config files.\n"; echo ++ gettext "Switch to BLS config files."; echo + echo + print_option_help "-h, --help" "$(gettext "print this message and exit")" + print_option_help "-V, --version" "$(gettext "print the version information and exit")" @@ -40165,7 +48226,7 @@ index 000000000..a851424be +# Bye. +exit 0 diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in -index 6a316a5ba..3e1b77265 100644 +index 6a316a5ba..01f1f4144 100644 --- a/util/grub.d/00_header.in +++ b/util/grub.d/00_header.in @@ -27,6 +27,14 @@ export TEXTDOMAINDIR="@localedir@" @@ -40183,7 +48244,7 @@ index 6a316a5ba..3e1b77265 100644 # Do this as early as possible, since other commands might depend on it. # (e.g. the `loadfont' command might need lvm or raid modules) for i in ${GRUB_PRELOAD_MODULES} ; do -@@ -43,7 +51,11 @@ if [ "x${GRUB_DEFAULT_BUTTON}" = "xsaved" ] ; then GRUB_DEFAULT_BUTTON='${saved_ +@@ -43,9 +51,24 @@ if [ "x${GRUB_DEFAULT_BUTTON}" = "xsaved" ] ; then GRUB_DEFAULT_BUTTON='${saved_ if [ "x${GRUB_TIMEOUT_BUTTON}" = "x" ] ; then GRUB_TIMEOUT_BUTTON="$GRUB_TIMEOUT" ; fi cat << EOF @@ -40195,8 +48256,61 @@ index 6a316a5ba..3e1b77265 100644 +elif [ -s \$prefix/grubenv ]; then load_env fi ++ ++if [ "\${env_block}" ] ; then ++ if [ "\${dev}" ]; then ++ set env_block="(\${dev})\${env_block}" ++ else ++ set env_block="(\${root})\${env_block}" ++ fi ++ export env_block ++ load_env -f "\${env_block}" ++fi ++ EOF -@@ -354,3 +366,16 @@ fi + if [ "x$GRUB_BUTTON_CMOS_ADDRESS" != "x" ]; then + cat </dev/null || true` -@@ -79,6 +84,255 @@ case x"$GRUB_FS" in +@@ -79,6 +84,258 @@ case x"$GRUB_FS" in ;; esac @@ -40394,6 +48512,9 @@ index cc393be7e..11c19304f 100644 + options="${options} ${GRUB_CMDLINE_LINUX_DEBUG}" + fi + options="$(echo "${options}" | sed -e 's/\//\\\//g')" ++ options="$(echo "${options}" | sed -e 's/\;/\\\;/g')" ++ options="$(echo "${options}" | sed -e 's/\\&/\\\\&/g')" ++ options="$(echo "${options}" | sed -e 's/\$/\\\$/g')" + sed -i -e "s/^options.*/options ${options}/" "${blsdir}/${bls}.conf" + done +} @@ -40552,7 +48673,7 @@ index cc393be7e..11c19304f 100644 title_correction_code= linux_entry () -@@ -86,23 +340,22 @@ linux_entry () +@@ -86,23 +343,22 @@ linux_entry () os="$1" version="$2" type="$3" @@ -40583,7 +48704,7 @@ index cc393be7e..11c19304f 100644 fi echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/" else -@@ -155,6 +408,13 @@ EOF +@@ -155,6 +411,13 @@ EOF sed "s/^/$submenu_indentation/" << EOF echo '$(echo "$message" | grub_quote)' initrd $(echo $initrd_path) @@ -40597,7 +48718,7 @@ index cc393be7e..11c19304f 100644 EOF fi sed "s/^/$submenu_indentation/" << EOF -@@ -207,6 +467,7 @@ fi +@@ -207,6 +470,7 @@ fi is_top_level=true for linux in ${reverse_sorted_list}; do gettext_printf "Found linux image: %s\n" "$linux" >&2 @@ -40605,7 +48726,7 @@ index cc393be7e..11c19304f 100644 basename=`basename $linux` dirname=`dirname $linux` rel_dirname=`make_system_path_relative_to_its_root $dirname` -@@ -247,9 +508,19 @@ for linux in ${reverse_sorted_list}; do +@@ -247,9 +511,19 @@ for linux in ${reverse_sorted_list}; do for i in ${initrd}; do initrd_display="${initrd_display} ${dirname}/${i}" done @@ -40626,7 +48747,7 @@ index cc393be7e..11c19304f 100644 config= for i in "${dirname}/config-${version}" "${dirname}/config-${alt_version}" "/etc/kernels/kernel-config-${version}" ; do if test -e "${i}" ; then -@@ -284,11 +555,15 @@ for linux in ${reverse_sorted_list}; do +@@ -284,11 +558,15 @@ for linux in ${reverse_sorted_list}; do fi if [ "x$is_top_level" = xtrue ] && [ "x${GRUB_DISABLE_SUBMENU}" != xtrue ]; then @@ -40644,7 +48765,7 @@ index cc393be7e..11c19304f 100644 if [ -z "$boot_device_id" ]; then boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" fi -@@ -297,10 +572,15 @@ for linux in ${reverse_sorted_list}; do +@@ -297,10 +575,15 @@ for linux in ${reverse_sorted_list}; do is_top_level=false fi @@ -40664,10 +48785,10 @@ index cc393be7e..11c19304f 100644 done diff --git a/util/grub.d/10_reset_boot_success.in b/util/grub.d/10_reset_boot_success.in new file mode 100644 -index 000000000..e73f4137b +index 000000000..ca04f9b69 --- /dev/null +++ b/util/grub.d/10_reset_boot_success.in -@@ -0,0 +1,25 @@ +@@ -0,0 +1,29 @@ +#! /bin/sh -e +# Reset Boot Success +# @@ -40691,14 +48812,18 @@ index 000000000..e73f4137b +fi +# Reset boot_success for current boot +set boot_success=0 -+save_env boot_success boot_indeterminate ++if [ "\${env_block}" ]; then ++ save_env -f "\${env_block}" boot_success boot_indeterminate ++else ++ save_env boot_success boot_indeterminate ++fi +EOF diff --git a/util/grub.d/12_menu_auto_hide.in b/util/grub.d/12_menu_auto_hide.in new file mode 100644 -index 000000000..6a7c0fa0d +index 000000000..c2c207232 --- /dev/null +++ b/util/grub.d/12_menu_auto_hide.in -@@ -0,0 +1,35 @@ +@@ -0,0 +1,39 @@ +#! /bin/sh +# Menu Auto Hide +# @@ -40717,7 +48842,11 @@ index 000000000..6a7c0fa0d +if [ x\$feature_timeout_style = xy ] ; then + if [ "\${menu_show_once}" ]; then + unset menu_show_once -+ save_env menu_show_once ++ if [ "\${env_block}" ]; then ++ save_env -f "\${env_block}" menu_show_once ++ else ++ save_env menu_show_once ++ fi + set timeout_style=menu + set timeout=60 + elif [ "\${menu_auto_hide}" -a "\${menu_hide_ok}" = "1" ]; then @@ -40736,10 +48865,10 @@ index 000000000..6a7c0fa0d +EOF diff --git a/util/grub.d/14_menu_show_once.in b/util/grub.d/14_menu_show_once.in new file mode 100755 -index 000000000..1cd7f3614 +index 000000000..41b37b5ec --- /dev/null +++ b/util/grub.d/14_menu_show_once.in -@@ -0,0 +1,13 @@ +@@ -0,0 +1,17 @@ +#! /bin/sh +# Force the menu to be shown once, with a timeout of ${menu_show_once_timeout} +# if requested by ${menu_show_once_timeout} being set in the env. @@ -40749,7 +48878,11 @@ index 000000000..1cd7f3614 + set timeout_style=menu + set timeout="\${menu_show_once_timeout}" + unset menu_show_once_timeout -+ save_env menu_show_once_timeout ++ if [ "\${env_block}" ]; then ++ save_env -f "\${env_block}" menu_show_once_timeout ++ else ++ save_env menu_show_once_timeout ++ fi + fi +fi +EOF @@ -41137,8 +49270,38 @@ index 1c2365ddb..1ef31e08f 100644 menuentry '$LABEL' \$menuentry_id_option 'uefi-firmware' { fwsetup } +diff --git a/util/misc.c b/util/misc.c +index d545212d9..6e16a68d9 100644 +--- a/util/misc.c ++++ b/util/misc.c +@@ -101,7 +101,7 @@ grub_util_read_image (const char *path) + } + + void +-grub_util_write_image_at (const void *img, size_t size, off_t offset, FILE *out, ++grub_util_write_image_at (const void *img, size_t size, grub_off_t offset, FILE *out, + const char *name) + { + grub_util_info ("writing 0x%" GRUB_HOST_PRIxLONG_LONG " bytes at offset 0x%" +@@ -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/util/mkimage.c b/util/mkimage.c -index 4237383ac..425d920ff 100644 +index 4237383ac..f92949d1d 100644 --- a/util/mkimage.c +++ b/util/mkimage.c @@ -883,10 +883,12 @@ void @@ -41153,7 +49316,7 @@ index 4237383ac..425d920ff 100644 - const char *sbat_path, int disable_shim_lock) + 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; @@ -41177,7 +49340,25 @@ index 4237383ac..425d920ff 100644 if (memdisk_path) { memdisk_size = ALIGN_UP(grub_util_get_image_size (memdisk_path), 512); -@@ -1049,7 +1064,7 @@ grub_install_generate_image (const char *dir, const char *prefix, +@@ -942,12 +957,15 @@ grub_install_generate_image (const char *dir, const char *prefix, + total_module_size += dtb_size + sizeof (struct grub_module_header); + } + +- if (sbat_path != NULL && image_target->id != IMAGE_EFI) +- grub_util_error (_(".sbat section can be embedded into EFI images only")); ++ if (sbat_path != NULL && (image_target->id != IMAGE_EFI && image_target->id != IMAGE_PPC)) ++ grub_util_error (_("SBAT data can be added only to EFI or powerpc-ieee1275 images")); + + if (disable_shim_lock) + total_module_size += sizeof (struct grub_module_header); + ++ 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); +@@ -1049,7 +1067,7 @@ grub_install_generate_image (const char *dir, const char *prefix, curs = grub_util_get_image_size (pubkey_paths[i]); header = (struct grub_module_header *) (kernel_img + offset); @@ -41186,7 +49367,7 @@ index 4237383ac..425d920ff 100644 header->size = grub_host_to_target32 (curs + sizeof (*header)); offset += sizeof (*header); -@@ -1058,6 +1073,26 @@ grub_install_generate_image (const char *dir, const char *prefix, +@@ -1058,6 +1076,26 @@ grub_install_generate_image (const char *dir, const char *prefix, } } @@ -41213,7 +49394,24 @@ index 4237383ac..425d920ff 100644 if (memdisk_path) { struct grub_module_header *header; -@@ -1403,6 +1438,7 @@ grub_install_generate_image (const char *dir, const char *prefix, +@@ -1094,6 +1132,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; +@@ -1403,6 +1451,7 @@ grub_install_generate_image (const char *dir, const char *prefix, #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdangling-pointer" #endif @@ -41221,18 +49419,33 @@ index 4237383ac..425d920ff 100644 PE_OHDR (o32, o64, header_size) = grub_host_to_target32 (header_size); PE_OHDR (o32, o64, entry_addr) = grub_host_to_target32 (layout.start_address); PE_OHDR (o32, o64, image_base) = 0; -@@ -1810,11 +1846,11 @@ grub_install_generate_image (const char *dir, const char *prefix, +@@ -1799,6 +1848,14 @@ grub_install_generate_image (const char *dir, const char *prefix, + case IMAGE_I386_IEEE1275: + { + grub_uint64_t target_addr; ++ char *sbat = NULL; ++ if (sbat_path != NULL) ++ { ++ sbat_size = grub_util_get_image_size (sbat_path); ++ sbat = xmalloc (sbat_size); ++ grub_util_load_image (sbat_path, sbat); ++ layout.sbat_size = sbat_size; ++ } + if (image_target->id == IMAGE_LOONGSON_ELF) + { + if (comp == GRUB_COMPRESSION_NONE) +@@ -1810,11 +1867,11 @@ grub_install_generate_image (const char *dir, const char *prefix, else target_addr = image_target->link_addr; if (image_target->voidp_sizeof == 4) - grub_mkimage_generate_elf32 (image_target, note, &core_img, &core_size, - target_addr, &layout); -+ grub_mkimage_generate_elf32 (image_target, note, appsig_size, &core_img, ++ grub_mkimage_generate_elf32 (image_target, note, appsig_size, sbat, &core_img, + &core_size, target_addr, &layout); else - grub_mkimage_generate_elf64 (image_target, note, &core_img, &core_size, - target_addr, &layout); -+ grub_mkimage_generate_elf64 (image_target, note, appsig_size, &core_img, ++ grub_mkimage_generate_elf64 (image_target, note, appsig_size, sbat, &core_img, + &core_size, target_addr, &layout); } break; diff --git a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-boot/grub/grub-2.12-01-execute-return-code.patch b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-boot/grub/grub-2.12-01-execute-return-code.patch deleted file mode 100644 index fe8bfef6dd..0000000000 --- a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-boot/grub/grub-2.12-01-execute-return-code.patch +++ /dev/null @@ -1,112 +0,0 @@ -From 442b676110c35caedb57408c4a27a6ef74f4c7db Mon Sep 17 00:00:00 2001 -From: James Le Cuirot -Date: Thu, 24 Oct 2024 14:42:46 +0100 -Subject: [PATCH 1/2] script/execute: Don't let trailing blank lines determine - the return code - -grub_script_execute_sourcecode() parses and executes code one line at a -time, updating the return code each time because only the last line -determines the final status. However, trailing new lines were also -executed, masking any failure on the previous line. Fix this by only -trying to execute the command when there is actually one present. - -This has presumably never been noticed because this code is not used by -regular functions, only in special cases like eval and menu entries. The -latter generally don't return at all, having booted an OS. When failing -to boot, upstream GRUB triggers the fallback mechanism regardless of the -return code. - -We noticed the problem while using Red Hat's patches, which change this -behaviour to take account of the return code. In that case, a failure -takes you back to the menu rather than triggering a fallback. - -Signed-off-by: James Le Cuirot ---- - grub-core/script/execute.c | 5 ++++- - tests/grub_script_eval.in | 10 +++++++++- - 2 files changed, 13 insertions(+), 2 deletions(-) - -diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c -index c19b4bf70..e369e8318 100644 ---- a/grub-core/script/execute.c -+++ b/grub-core/script/execute.c -@@ -935,7 +935,10 @@ grub_script_execute_sourcecode (const char *source) - break; - } - -- ret = grub_script_execute (parsed_script); -+ /* Don't let trailing blank lines determine the return code. */ -+ if (parsed_script->cmd) -+ ret = grub_script_execute (parsed_script); -+ - grub_script_free (parsed_script); - grub_free (line); - } -diff --git a/tests/grub_script_eval.in b/tests/grub_script_eval.in -index c97b78d77..9c6211042 100644 ---- a/tests/grub_script_eval.in -+++ b/tests/grub_script_eval.in -@@ -3,4 +3,12 @@ - eval echo "Hello world" - valname=tst - eval $valname=hi --echo $tst -\ No newline at end of file -+echo $tst -+ -+if eval " -+false -+"; then -+ echo should have failed -+else -+ echo failed as expected -+fi --- -2.46.1 - - -From 93eedb6cebe758db09066e084ddd2fb659ebc4fb Mon Sep 17 00:00:00 2001 -From: James Le Cuirot -Date: Thu, 24 Oct 2024 15:00:26 +0100 -Subject: [PATCH 2/2] normal/menu: Check return code of the script when - executing a menu entry - -Don't rely on grub_errno here because grub_script_execute_new_scope() -calls grub_print_error(), which always resets grub_errno back to -GRUB_ERR_NONE. It may also get reset by grub_wait_after_message(). - -This problem was observed when a "bad signature" error resulted in the -menu being redisplayed rather than the fallback mechanism being -triggered, although another change was also needed to fix it. This only -happens with Red Hat's patches because upstream GRUB triggers the -fallback mechanism regardless of the return code. - -Signed-off-by: James Le Cuirot ---- - grub-core/normal/menu.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c -index cda10fa8b..fd9b8c6d8 100644 ---- a/grub-core/normal/menu.c -+++ b/grub-core/normal/menu.c -@@ -376,14 +376,14 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) - if (ptr && ptr[0] && ptr[1]) - grub_env_set ("default", ptr + 1); - -- grub_script_execute_new_scope (entry->sourcecode, entry->argc, entry->args); -+ err = grub_script_execute_new_scope (entry->sourcecode, entry->argc, entry->args); - - if (errs_before != grub_err_printed_errors) - grub_wait_after_message (); - - errs_before = grub_err_printed_errors; - -- if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ()) -+ if (err == GRUB_ERR_NONE && grub_loader_is_loaded ()) - /* Implicit execution of boot, only if something is loaded. */ - err = grub_command_execute ("boot", 0, 0); - --- -2.46.1 -