Compare commits

...
Sign in to create a new pull request.

33 commits

Author SHA1 Message Date
Joel Capitao
85de859da1
Do not include EFI dir in common subpackage
This fixes [1] which is part of [2]. We cannot ship
/usr/lib/efi/* in -common subpackage as bootupd does not expect this
directory for ppc64le arch.
We are moving the creation and configuration of the directory into
specific EFI macros only.

[1] e02b6e88c7
[2] https://fedoraproject.org/wiki/Changes/BootLoaderUpdatesPhase1

Signed-off-by: Joel Capitao <jcapitao@redhat.com>
2025-12-11 08:35:43 +01:00
Leo Sandoval
16cb5b303d Increase EFI max allocation to max usable address
Resolves: #2263643

Signed-off-by: Nicolas Frayer <nfrayer@redhat.com>
Signed-off-by: Leo Sandoval <lsandova@redhat.com>
2025-12-10 12:20:17 -06:00
Leo Sandoval
70c5e62950 Add support for external environment block on Btrfs
Signed-off-by: Leo Sandoval <lsandova@redhat.com>
Tested-by: Neal Gompa <ngompa@fedoraproject.org>
2025-11-26 11:22:14 -06:00
Leo Sandoval
a4ec822e7e blsuki: do not register blscfg command
Otherwise the blsuki.c blscfg cmd version replaces the one defined on
blscfg.c and the latter is the version we want to use.

Signed-off-by: Leo Sandoval <lsandova@redhat.com>
2025-11-13 12:09:21 -06:00
Tom spot Callaway
6467d85178 rebuild for new fuse3 2025-11-04 16:20:54 -05:00
Leo Sandoval
f4663b0ddc Fix blsuki patch enumeration
Signed-off-by: Leo Sandoval <lsandova@redhat.com>
2025-10-27 11:38:18 -06:00
Leo Sandoval
4614a09b9f Include upstream blsuki related patches
Signed-off-by: Leo Sandoval <lsandova@redhat.com>
2025-10-15 15:26:32 -06:00
Leo Sandoval
b9b1d1e384 Include function name on debug and error print functions
With the following change, we see standard (grub_dprintf) and
error (grub_error) logs with the function name embedded (see below)
into the log which is particular useful when debugging

    commands/efi/tpm.c:grub_tpm_measure:281:tpm: log_event, pcr = 8, size = 0xb,

Including one more field on the print log impacts the binary sizes
and in turn their respective packages, the latter with an increase of
20k approximately (compared to 2.12-43) for most the the
packages.

Signed-off-by: Leo Sandoval <lsandova@redhat.com>
2025-09-23 13:17:44 -06:00
Nicolas Frayer
730ce27747 gen_grub_cfgstub: Removed output messages
Signed-off-by: Nicolas Frayer <nfrayer@redhat.com>
2025-08-29 13:19:37 +02:00
Jan Stancek
f6bc25c3e7 55-set-boot-entry.install: move to 95
When KERNEL_INSTALL_STAGING_AREA is used (for example with
initrd_generator=mkosi-initrd), initrd gets installed to /boot
only later at 90-loaderentry.install.

Move the plugin to 95 so it runs after.

Related: #2389020
Signed-off-by: Jan Stancek <jstancek@redhat.com>
2025-08-20 22:03:31 +02:00
Marta Lewandowska
e02b6e88c7 Phase 1 of the bootloader updates proposal implementation
https://fedoraproject.org/wiki/Changes/BootLoaderUpdatesPhase1

Signed-off-by: Marta Lewandoska <mlewando@redhat.com>
Signed-off-by: Nicolas Frayer <nfrayer@redhat.com>
Signed-off-by: Leo Sandoval <lsandova@redhat.com>
2025-08-18 11:18:42 -06:00
Jan Stancek
354c77b195 55-set-boot-entry.install: fix initrd check
Fix where to look for initrd file, as /boot may not be a separate
partition, in which case adding /boot unconditionally leads to
a duplicate "/boot/boot/...".

Fix initrd line parsing to take only first word - it can contain
extra parameters, e.g. "$tuned_initrd", which are not part
of initrd filename.

Resolves: #2386118
Reported-by: Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com>
Tested-by: Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com>
Signed-off-by: Jan Stancek <jstancek@redhat.com>
2025-08-07 18:23:29 +02:00
FeRD (Frank Dana)
8f6e9e55c1 Suppress warnings about missing /etc/default/grub
Signed-off-by: FeRD (Frank Dana) <ferdnyc@gmail.com>
2025-08-01 18:48:37 +00:00
Yuxin Sun
06e458e5eb 20-grub.install: Skip BLS removal when entry type is type2
UKI(package is kernel-uki-virt) is a single, bootable file that bundles everything needed to start a Linux system.
It contains its own bootable stub and bypasses GRUB2 completely.
The kernel-core and kernel-uki-virt can coexist in one machine. And both of them call kernel-install remove <kversion> upon package
removal and this leads to the complete removal of both the traditional kernel & its artifacts(initramfs, BLS entry file,...).
For example, if the customer remove kernel-uki-virt, currently it also removes BLS entry which causes the regular kernel fails to boot up.
In https://github.com/systemd/systemd/pull/37897 it added --entry-type=type1|type2 option to kernel-install. type1 stands for normal kernel,
type2 stands for uki. When kernel-install is invoked with --entry-type=type2 which is for UKI, we should not remove the BLS entry.

Signed-off-by: Yuxin Sun <yuxisun@redhat.com>
2025-07-31 10:52:12 +08:00
Leo Sandoval
8f843cc6ef Set correctly the memory attributes for the kernel PE sections
Signed-off-by: Leo Sandoval <lsandova@redhat.com>
2025-07-29 16:50:34 -06:00
Jan Stancek
42ca1a56a1 more robust kernel updates
Set boot entry only after sucessful ramdisk creation to prevent
booting into broken environments in cases where ramdisk is corrupt
or missing.

Signed-off-by: Jan Stancek <jstancek@redhat.com>
2025-07-16 09:11:52 +02:00
Nicolas Frayer
01b4205642 spec: fix grub stub cfg creation script
Signed-off-by: Nicolas Frayer <nfrayer@redhat.com>
2025-07-08 12:40:07 +02:00
Yaakov Selkowitz
159b7b546a Remove package.cfg
This did not consistently work as intended, and the ELN automation can now
build this properly.

Signed-off-by: Yaakov Selkowitz <yselkowi@redhat.com>
2025-06-20 16:16:33 -04:00
Nicolas Frayer
828e1c5448 spec/posttrans: move grub config stub creation out of spec
Signed-off-by: Nicolas Frayer <nfrayer@redhat.com>
2025-06-12 21:12:40 +02:00
Nicolas Frayer
0e28d5ff18 osdep/linux/getroot: Detect DDF container similar to IMSM
Signed-off-by: Nicolas Frayer <nfrayer@redhat.com>
2025-06-05 10:56:47 +02:00
Nicolas Frayer
9400ee8e83 Some fixes addressing memory freeing and dereferencing
Resolves: #2368939
Resolves: #2368945
Signed-off-by: Nicolas Frayer <nfrayer@redhat.com>
2025-05-28 18:23:00 +02:00
Nicolas Frayer
9089407121 sbat: bump grub sbat
Signed-off-by: Nicolas Frayer <nfrayer@redhat.com>
2025-05-16 12:34:14 +02:00
Leo Sandoval
9fa1c31cb2 Fix cryptodisk vulnerabilities
Resolves: CVE-2025-4382
Signed-off-by: Leo Sandoval <lsandova@redhat.com>
2025-05-13 09:10:41 -06:00
Leo Sandoval
ffc692d90e Handle special kernel parameter characters properly
Resolves: #2362821
Signed-off-by: Leo Sandoval <lsandova@redhat.com>
2025-05-07 14:36:48 -06:00
Nicolas Frayer
5c361bf706 ppc/mkimage: SBAT support on powerpc
Signed-off-by: Nicolas Frayer <nfrayer@redhat.com>
2025-04-18 16:42:30 +02:00
Leo Sandoval
439310c622 do-sync: helper script to sync dist-git and git branches
The bootloader team manually synchronizes several git branches on the
rhboot/grub (git) repository based on dist-git (dist-git) repository. Although
this task is simple, it is a maintenance burden, usually done much after the
dist-git repository is updated, having out-of-sync git branches most of the
time.

The goal of the included script is to create a temporal branch based on
latest git branch then include those possible missing dist-git patches and
finally push it.

Signed-off-by: Leo Sandoval <lsandova@redhat.com>
2025-04-08 16:00:08 +00:00
Nicolas Frayer
cbf45b1f24 ieee1275/ofnet: Fix grub_malloc() removed after added safe
Signed-off-by: Nicolas Frayer <nfrayer@redhat.com>
2025-03-25 19:17:46 +01:00
James Le Cuirot
42b2a048bf Fix the fallback mechanism when menu entries fail to boot
Patch 0098 accidentally broke the fallback mechanism, although it also
exposed another bug in upstream GRUB. The first of these new patches
fixes the upstream bug. It has already been merged there. The second
patch deals with the main issue.

Signed-off-by: James Le Cuirot <jlecuirot@microsoft.com>
2025-03-25 15:16:32 +01:00
Nils Kattenbeck
c48d4f6719 Drop 'which' requirement
Since 28a7e597de0d5584f65e36f9588ff9041936e617, occurrences of 'which' were replaced by 'command -v'

Signed-off-by: Nils Kattenbeck <nilskemail+fedora@gmail.com>
2025-03-19 17:45:42 +00:00
Nicolas Frayer
50b73378ce powerpc: increase MIN RMA size for CAS negotiation
Signed-off-by: Nicolas Frayer <nfrayer@redhat.com>
2025-03-19 17:59:28 +01:00
Leo Sandoval
b04ed232e2 Remove NTFS attribute verification patch
The removed patch was part of the CVE patches ported recently into Fedora but
unfortunately this is causing segfaults when generating the grub configuration
file. At some point the same patch will come back with the corresponding fix but
for the time being, it is removed. Note that patch numeration did not change on
purpose: patch will be introduced again so need to mess with the numeration.

Resolves: #2350327

Signed-off-by: Leo Sandoval <lsandova@redhat.com>
2025-03-10 13:16:08 -06:00
Nicolas Frayer
0c53016c97 fs/ext2: Rework out-of-bounds read for inline and external extents
Resolves: #2346804
Signed-off-by: Nicolas Frayer <nfrayer@redhat.com>
2025-02-26 11:32:30 +01:00
Leo Sandoval
5427c36328 Add Several CVE fixes
Resolves: CVE-2024-45781 CVE-2024-45783 CVE-2024-45778
Resolves: CVE-2024-45775 CVE-2024-45780 CVE-2024-45774
Resolves: CVE-2025-0690 CVE-2025-1118 CVE-2024-45782
Resolves: CVE-2025-0624 CVE-2024-45779 CVE-2024-45776
Resolves: CVE-2025-0622 CVE-2025-0677

Signed-off-by: Leo Sandoval <lsandova@redhat.com>
2025-02-19 10:10:45 -06:00
128 changed files with 13134 additions and 34 deletions

View file

@ -0,0 +1,65 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Sat, 15 Jun 2024 02:33:08 +0100
Subject: [PATCH] misc: Implement grub_strlcpy()
grub_strlcpy() acts the same way as strlcpy() does on most *NIX,
returning the length of src and ensuring dest is always NUL
terminated except when size is 0.
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
include/grub/misc.h | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/include/grub/misc.h b/include/grub/misc.h
index db517acd5..6b1e084af 100644
--- a/include/grub/misc.h
+++ b/include/grub/misc.h
@@ -72,6 +72,45 @@ grub_stpcpy (char *dest, const char *src)
return d - 1;
}
+static inline grub_size_t
+grub_strlcpy (char *dest, const char *src, grub_size_t size)
+{
+ char *d = dest;
+ grub_size_t res = 0;
+ /*
+ * We do not subtract one from size here to avoid dealing with underflowing
+ * the value, which is why to_copy is always checked to be greater than one
+ * throughout this function.
+ */
+ grub_size_t to_copy = size;
+
+ /* Copy size - 1 bytes to dest. */
+ if (to_copy > 1)
+ while ((*d++ = *src++) != '\0' && ++res && --to_copy > 1)
+ ;
+
+ /*
+ * NUL terminate if size != 0. The previous step may have copied a NUL byte
+ * if it reached the end of the string, but we know dest[size - 1] must always
+ * be a NUL byte.
+ */
+ if (size != 0)
+ dest[size - 1] = '\0';
+
+ /* If there is still space in dest, but are here, we reached the end of src. */
+ if (to_copy > 1)
+ return res;
+
+ /*
+ * If we haven't reached the end of the string, iterate through to determine
+ * the strings total length.
+ */
+ while (*src++ != '\0' && ++res)
+ ;
+
+ return res;
+}
+
/* XXX: If grub_memmove is too slow, we must implement grub_memcpy. */
static inline void *
grub_memcpy (void *dest, const void *src, grub_size_t n)

View file

@ -0,0 +1,31 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Sun, 12 May 2024 02:03:33 +0100
Subject: [PATCH] fs/ufs: Fix a heap OOB write
grub_strcpy() was used to copy a symlink name from the filesystem
image to a heap allocated buffer. This led to a OOB write to adjacent
heap allocations. Fix by using grub_strlcpy().
Fixes: CVE-2024-45781
Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/ufs.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/grub-core/fs/ufs.c b/grub-core/fs/ufs.c
index a354c92d9..01235101b 100644
--- a/grub-core/fs/ufs.c
+++ b/grub-core/fs/ufs.c
@@ -463,7 +463,7 @@ grub_ufs_lookup_symlink (struct grub_ufs_data *data, int ino)
/* Check against zero is paylindromic, no need to swap. */
if (data->inode.nblocks == 0
&& INODE_SIZE (data) <= sizeof (data->inode.symlink))
- grub_strcpy (symlink, (char *) data->inode.symlink);
+ grub_strlcpy (symlink, (char *) data->inode.symlink, sz);
else
{
if (grub_ufs_read_file (data, 0, 0, 0, sz, symlink) < 0)

View file

@ -0,0 +1,31 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Sun, 12 May 2024 02:48:33 +0100
Subject: [PATCH] fs/hfs: Fix stack OOB write with grub_strcpy()
Replaced with grub_strlcpy().
Fixes: CVE-2024-45782
Fixes: CVE-2024-56737
Fixes: https://savannah.gnu.org/bugs/?66599
Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/hfs.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/grub-core/fs/hfs.c b/grub-core/fs/hfs.c
index 91dc0e69c..920112b03 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)

View file

@ -0,0 +1,40 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Sun, 12 May 2024 02:47:54 +0100
Subject: [PATCH] fs/tar: Initialize name in grub_cpio_find_file()
It was possible to iterate through grub_cpio_find_file() without
allocating name and not setting mode to GRUB_ARCHELP_ATTR_END, which
would cause the uninitialized value for name to be used as an argument
for canonicalize() in grub_archelp_dir().
Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/tar.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/grub-core/fs/tar.c b/grub-core/fs/tar.c
index c551ed6b5..646bce5eb 100644
--- a/grub-core/fs/tar.c
+++ b/grub-core/fs/tar.c
@@ -78,6 +78,7 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name,
int reread = 0, have_longname = 0, have_longlink = 0;
data->hofs = data->next_hofs;
+ *name = NULL;
for (reread = 0; reread < 3; reread++)
{
@@ -202,6 +203,10 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name,
}
return GRUB_ERR_NONE;
}
+
+ if (*name == NULL)
+ return grub_error (GRUB_ERR_BAD_FS, "invalid tar archive");
+
return GRUB_ERR_NONE;
}

View file

@ -0,0 +1,89 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lidong Chen <lidong.chen@oracle.com>
Date: Fri, 22 Nov 2024 06:27:58 +0000
Subject: [PATCH] fs/tar: Integer overflow leads to heap OOB write
Both namesize and linksize are derived from hd.size, a 12-digit octal
number parsed by read_number(). Later direct arithmetic calculation like
"namesize + 1" and "linksize + 1" may exceed the maximum value of
grub_size_t leading to heap OOB write. This patch fixes the issue by
using grub_add() and checking for an overflow.
Fixes: CVE-2024-45780
Reported-by: Nils Langius <nils@langius.de>
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Reviewed-by: Alec Brown <alec.r.brown@oracle.com>
---
grub-core/fs/tar.c | 23 ++++++++++++++++++-----
1 file changed, 18 insertions(+), 5 deletions(-)
diff --git a/grub-core/fs/tar.c b/grub-core/fs/tar.c
index 646bce5eb..386c09022 100644
--- a/grub-core/fs/tar.c
+++ b/grub-core/fs/tar.c
@@ -25,6 +25,7 @@
#include <grub/mm.h>
#include <grub/dl.h>
#include <grub/i18n.h>
+#include <grub/safemath.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -76,6 +77,7 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name,
{
struct head hd;
int reread = 0, have_longname = 0, have_longlink = 0;
+ grub_size_t sz;
data->hofs = data->next_hofs;
*name = NULL;
@@ -98,7 +100,11 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name,
{
grub_err_t err;
grub_size_t namesize = read_number (hd.size, sizeof (hd.size));
- *name = grub_malloc (namesize + 1);
+
+ if (grub_add (namesize, 1, &sz))
+ return grub_error (GRUB_ERR_BAD_FS, N_("name size overflow"));
+
+ *name = grub_malloc (sz);
if (*name == NULL)
return grub_errno;
err = grub_disk_read (data->disk, 0,
@@ -118,15 +124,19 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name,
{
grub_err_t err;
grub_size_t linksize = read_number (hd.size, sizeof (hd.size));
- if (data->linkname_alloc < linksize + 1)
+
+ if (grub_add (linksize, 1, &sz))
+ return grub_error (GRUB_ERR_BAD_FS, N_("link size overflow"));
+
+ if (data->linkname_alloc < sz)
{
char *n;
- n = grub_calloc (2, linksize + 1);
+ n = grub_calloc (2, sz);
if (!n)
return grub_errno;
grub_free (data->linkname);
data->linkname = n;
- data->linkname_alloc = 2 * (linksize + 1);
+ data->linkname_alloc = 2 * (sz);
}
err = grub_disk_read (data->disk, 0,
@@ -149,7 +159,10 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name,
while (extra_size < sizeof (hd.prefix)
&& hd.prefix[extra_size])
extra_size++;
- *name = grub_malloc (sizeof (hd.name) + extra_size + 2);
+
+ if (grub_add (sizeof (hd.name) + 2, extra_size, &sz))
+ return grub_error (GRUB_ERR_BAD_FS, N_("long name size overflow"));
+ *name = grub_malloc (sz);
if (*name == NULL)
return grub_errno;
if (hd.prefix[0])

View file

@ -0,0 +1,31 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Sun, 12 May 2024 06:15:03 +0100
Subject: [PATCH] fs/f2fs: Set a grub_errno if mount fails
It was previously possible for grub_errno to not be set when
grub_f2fs_mount() failed if nat_bitmap_ptr() returned NULL.
This issue is solved by ensuring a grub_errno is set in the fail case.
Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/f2fs.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c
index 855e24618..db8a65f8d 100644
--- a/grub-core/fs/f2fs.c
+++ b/grub-core/fs/f2fs.c
@@ -872,6 +872,9 @@ grub_f2fs_mount (grub_disk_t disk)
return data;
fail:
+ if (grub_errno == GRUB_ERR_NONE)
+ grub_error (GRUB_ERR_BAD_FS, "not a F2FS filesystem");
+
grub_free (data);
return NULL;

View file

@ -0,0 +1,35 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Sun, 12 May 2024 06:22:51 +0100
Subject: [PATCH] fs/hfsplus: Set a grub_errno if mount fails
It was possible for mount to fail but not set grub_errno. This led to
a possible double decrement of the module reference count if the NULL
page was mapped.
Fixing in general as a similar bug was fixed in commit 61b13c187
(fs/hfsplus: Set grub_errno to prevent NULL pointer access) and there
are likely more variants around.
Fixes: CVE-2024-45783
Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/hfsplus.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/grub-core/fs/hfsplus.c b/grub-core/fs/hfsplus.c
index 295822f69..de71fd486 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);

View file

@ -0,0 +1,33 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Sun, 12 May 2024 06:37:08 +0100
Subject: [PATCH] fs/iso9660: Set a grub_errno if mount fails
It was possible for a grub_errno to not be set if mount of an ISO 9660
filesystem failed when set_rockridge() returned 0.
This isn't known to be exploitable as the other filesystems due to
filesystem helper checking the requested file type. Though fixing
as a precaution.
Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/iso9660.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/grub-core/fs/iso9660.c b/grub-core/fs/iso9660.c
index 8c348b59a..8d480e602 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;
}

View file

@ -0,0 +1,50 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Fri, 31 May 2024 15:14:42 +0800
Subject: [PATCH] fs/iso9660: Fix invalid free
The ctx->filename can point to either a string literal or a dynamically
allocated string. The ctx->filename_alloc field is used to indicate the
type of allocation.
An issue has been identified where ctx->filename is reassigned to
a string literal in susp_iterate_dir() but ctx->filename_alloc is not
correctly handled. This oversight causes a memory leak and an invalid
free operation later.
The fix involves checking ctx->filename_alloc, freeing the allocated
string if necessary and clearing ctx->filename_alloc for string literals.
Reported-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Michael Chang <mchang@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/iso9660.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/grub-core/fs/iso9660.c b/grub-core/fs/iso9660.c
index 8d480e602..8e3c95c4f 100644
--- a/grub-core/fs/iso9660.c
+++ b/grub-core/fs/iso9660.c
@@ -628,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;

View file

@ -0,0 +1,63 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lidong Chen <lidong.chen@oracle.com>
Date: Fri, 22 Nov 2024 06:27:59 +0000
Subject: [PATCH] fs/jfs: Fix OOB read in jfs_getent()
The JFS fuzzing revealed an OOB read in grub_jfs_getent(). The crash
was caused by an invalid leaf nodes count, diro->dirpage->header.count,
which was larger than the maximum number of leaf nodes allowed in an
inode. This fix is to ensure that the leaf nodes count is validated in
grub_jfs_opendir() before calling grub_jfs_getent().
On the occasion replace existing raw numbers with newly defined constant.
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Reviewed-by: Alec Brown <alec.r.brown@oracle.com>
---
grub-core/fs/jfs.c | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/grub-core/fs/jfs.c b/grub-core/fs/jfs.c
index 6f7c43904..32dec7fb7 100644
--- a/grub-core/fs/jfs.c
+++ b/grub-core/fs/jfs.c
@@ -41,6 +41,12 @@ GRUB_MOD_LICENSE ("GPLv3+");
#define GRUB_JFS_TREE_LEAF 2
+/*
+ * Define max entries stored in-line in an inode.
+ * https://jfs.sourceforge.net/project/pub/jfslayout.pdf
+ */
+#define GRUB_JFS_INODE_INLINE_ENTRIES 8
+
struct grub_jfs_sblock
{
/* The magic for JFS. It should contain the string "JFS1". */
@@ -203,9 +209,9 @@ struct grub_jfs_inode
grub_uint8_t freecnt;
grub_uint8_t freelist;
grub_uint32_t idotdot;
- grub_uint8_t sorted[8];
+ grub_uint8_t sorted[GRUB_JFS_INODE_INLINE_ENTRIES];
} header;
- struct grub_jfs_leaf_dirent dirents[8];
+ struct grub_jfs_leaf_dirent dirents[GRUB_JFS_INODE_INLINE_ENTRIES];
} GRUB_PACKED dir;
/* Fast symlink. */
struct
@@ -453,6 +459,13 @@ grub_jfs_opendir (struct grub_jfs_data *data, struct grub_jfs_inode *inode)
/* Check if the entire tree is contained within the inode. */
if (inode->file.tree.flags & GRUB_JFS_TREE_LEAF)
{
+ if (inode->dir.header.count > GRUB_JFS_INODE_INLINE_ENTRIES)
+ {
+ grub_free (diro);
+ grub_error (GRUB_ERR_BAD_FS, N_("invalid JFS inode"));
+ return 0;
+ }
+
diro->leaf = inode->dir.dirents;
diro->next_leaf = (struct grub_jfs_leaf_next_dirent *) de;
diro->sorted = inode->dir.header.sorted;

View file

@ -0,0 +1,64 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lidong Chen <lidong.chen@oracle.com>
Date: Fri, 22 Nov 2024 06:28:00 +0000
Subject: [PATCH] fs/jfs: Fix OOB read caused by invalid dir slot index
While fuzz testing JFS with ASAN enabled an OOB read was detected in
grub_jfs_opendir(). The issue occurred due to an invalid directory slot
index in the first entry of the sorted directory slot array in the inode
directory header. The fix ensures the slot index is validated before
accessing it. Given that an internal or a leaf node in a directory B+
tree is a 4 KiB in size and each directory slot is always 32 bytes, the
max number of slots in a node is 128. The validation ensures that the
slot index doesn't exceed this limit.
[1] https://jfs.sourceforge.net/project/pub/jfslayout.pdf
JFS will allocate 4K of disk space for an internal node of the B+ tree.
An internal node looks the same as a leaf node.
- page 10
Fixed number of Directory Slots depending on the size of the node. These are
the slots to be used for storing the directory slot array and the directory
entries or router entries. A directory slot is always 32 bytes.
...
A Directory Slot Array which is a sorted array of indices to the directory
slots that are currently in use.
...
An internal or a leaf node in the directory B+ tree is a 4K page.
- page 25
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Reviewed-by: Alec Brown <alec.r.brown@oracle.com>
---
grub-core/fs/jfs.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/grub-core/fs/jfs.c b/grub-core/fs/jfs.c
index 32dec7fb7..88fb884df 100644
--- a/grub-core/fs/jfs.c
+++ b/grub-core/fs/jfs.c
@@ -46,6 +46,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
* https://jfs.sourceforge.net/project/pub/jfslayout.pdf
*/
#define GRUB_JFS_INODE_INLINE_ENTRIES 8
+#define GRUB_JFS_DIR_MAX_SLOTS 128
struct grub_jfs_sblock
{
@@ -481,6 +482,14 @@ grub_jfs_opendir (struct grub_jfs_data *data, struct grub_jfs_inode *inode)
return 0;
}
+ if (inode->dir.header.sorted[0] >= GRUB_JFS_DIR_MAX_SLOTS)
+ {
+ grub_error (GRUB_ERR_BAD_FS, N_("invalid directory slot index"));
+ grub_free (diro->dirpage);
+ grub_free (diro);
+ return 0;
+ }
+
blk = grub_le_to_cpu32 (de[inode->dir.header.sorted[0]].ex.blk2);
blk <<= (grub_le_to_cpu16 (data->sblock.log2_blksz) - GRUB_DISK_SECTOR_BITS);

View file

@ -0,0 +1,128 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lidong Chen <lidong.chen@oracle.com>
Date: Mon, 16 Dec 2024 20:22:39 +0000
Subject: [PATCH] fs/jfs: Use full 40 bits offset and address for a data extent
An extent's logical offset and address are represented as a 40-bit value
split into two parts: the most significant 8 bits and the least
significant 32 bits. Currently the JFS code uses only the least
significant 32 bits value for offsets and addresses assuming the data
size will never exceed the 32-bit range. This approach ignores the most
significant 8 bits potentially leading to incorrect offsets and
addresses for larger values. The patch fixes it by incorporating the
most significant 8 bits into the calculation to get the full 40-bits
value for offsets and addresses.
https://jfs.sourceforge.net/project/pub/jfslayout.pdf
"off1,off2 is a 40-bit field, containing the logical offset of the first
block in the extent.
...
addr1,addr2 is a 40-bit field, containing the address of the extent."
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Ross Philipson <ross.philipson@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/jfs.c | 41 +++++++++++++++++++++++++++++------------
1 file changed, 29 insertions(+), 12 deletions(-)
diff --git a/grub-core/fs/jfs.c b/grub-core/fs/jfs.c
index 88fb884df..2bde48d45 100644
--- a/grub-core/fs/jfs.c
+++ b/grub-core/fs/jfs.c
@@ -265,6 +265,20 @@ static grub_dl_t my_mod;
static grub_err_t grub_jfs_lookup_symlink (struct grub_jfs_data *data, grub_uint32_t ino);
+/*
+ * An extent's offset, physical and logical, is represented as a 40-bit value.
+ * This 40-bit value is split into two parts:
+ * - offset1: the most signficant 8 bits of the offset,
+ * - offset2: the least significant 32 bits of the offset.
+ *
+ * This function calculates and returns the 64-bit offset of an extent.
+ */
+static grub_uint64_t
+get_ext_offset (grub_uint8_t offset1, grub_uint32_t offset2)
+{
+ return (((grub_uint64_t) offset1 << 32) | grub_le_to_cpu32 (offset2));
+}
+
static grub_int64_t
getblk (struct grub_jfs_treehead *treehead,
struct grub_jfs_tree_extent *extents,
@@ -274,22 +288,25 @@ getblk (struct grub_jfs_treehead *treehead,
{
int found = -1;
int i;
+ grub_uint64_t ext_offset, ext_blk;
for (i = 0; i < grub_le_to_cpu16 (treehead->count) - 2 &&
i < max_extents; i++)
{
+ ext_offset = get_ext_offset (extents[i].offset1, extents[i].offset2);
+ ext_blk = get_ext_offset (extents[i].extent.blk1, extents[i].extent.blk2);
+
if (treehead->flags & GRUB_JFS_TREE_LEAF)
{
/* Read the leafnode. */
- if (grub_le_to_cpu32 (extents[i].offset2) <= blk
+ if (ext_offset <= blk
&& ((grub_le_to_cpu16 (extents[i].extent.length))
+ (extents[i].extent.length2 << 16)
- + grub_le_to_cpu32 (extents[i].offset2)) > blk)
- return (blk - grub_le_to_cpu32 (extents[i].offset2)
- + grub_le_to_cpu32 (extents[i].extent.blk2));
+ + ext_offset) > blk)
+ return (blk - ext_offset + ext_blk);
}
else
- if (blk >= grub_le_to_cpu32 (extents[i].offset2))
+ if (blk >= ext_offset)
found = i;
}
@@ -307,10 +324,9 @@ getblk (struct grub_jfs_treehead *treehead,
return -1;
if (!grub_disk_read (data->disk,
- ((grub_disk_addr_t) grub_le_to_cpu32 (extents[found].extent.blk2))
- << (grub_le_to_cpu16 (data->sblock.log2_blksz)
- - GRUB_DISK_SECTOR_BITS), 0,
- sizeof (*tree), (char *) tree))
+ (grub_disk_addr_t) ext_blk
+ << (grub_le_to_cpu16 (data->sblock.log2_blksz) - GRUB_DISK_SECTOR_BITS),
+ 0, sizeof (*tree), (char *) tree))
{
if (grub_memcmp (&tree->treehead, treehead, sizeof (struct grub_jfs_treehead)) ||
grub_memcmp (&tree->extents, extents, 254 * sizeof (struct grub_jfs_tree_extent)))
@@ -361,7 +377,7 @@ grub_jfs_read_inode (struct grub_jfs_data *data, grub_uint32_t ino,
sizeof (iag_inodes), &iag_inodes))
return grub_errno;
- inoblk = grub_le_to_cpu32 (iag_inodes[inoext].blk2);
+ inoblk = get_ext_offset (iag_inodes[inoext].blk1, iag_inodes[inoext].blk2);
inoblk <<= (grub_le_to_cpu16 (data->sblock.log2_blksz)
- GRUB_DISK_SECTOR_BITS);
inoblk += inonum;
@@ -490,7 +506,8 @@ grub_jfs_opendir (struct grub_jfs_data *data, struct grub_jfs_inode *inode)
return 0;
}
- blk = grub_le_to_cpu32 (de[inode->dir.header.sorted[0]].ex.blk2);
+ blk = get_ext_offset (de[inode->dir.header.sorted[0]].ex.blk1,
+ de[inode->dir.header.sorted[0]].ex.blk2);
blk <<= (grub_le_to_cpu16 (data->sblock.log2_blksz) - GRUB_DISK_SECTOR_BITS);
/* Read in the nodes until we are on the leaf node level. */
@@ -508,7 +525,7 @@ grub_jfs_opendir (struct grub_jfs_data *data, struct grub_jfs_inode *inode)
de = (struct grub_jfs_internal_dirent *) diro->dirpage->dirent;
index = diro->dirpage->sorted[diro->dirpage->header.sindex * 32];
- blk = (grub_le_to_cpu32 (de[index].ex.blk2)
+ blk = (get_ext_offset (de[index].ex.blk1, de[index].ex.blk2)
<< (grub_le_to_cpu16 (data->sblock.log2_blksz)
- GRUB_DISK_SECTOR_BITS));
} while (!(diro->dirpage->header.flags & GRUB_JFS_TREE_LEAF));

View file

@ -0,0 +1,85 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lidong Chen <lidong.chen@oracle.com>
Date: Mon, 16 Dec 2024 20:22:40 +0000
Subject: [PATCH] fs/jfs: Inconsistent signed/unsigned types usage in return
values
The getblk() returns a value of type grub_int64_t which is assigned to
iagblk and inoblk, both of type grub_uint64_t, in grub_jfs_read_inode()
via grub_jfs_blkno(). This patch fixes the type mismatch in the
functions. Additionally, the getblk() will return 0 instead of -1 on
failure cases. This change is safe because grub_errno is always set in
getblk() to indicate errors and it is later checked in the callers.
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Ross Philipson <ross.philipson@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/jfs.c | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/grub-core/fs/jfs.c b/grub-core/fs/jfs.c
index 2bde48d45..70a2f4947 100644
--- a/grub-core/fs/jfs.c
+++ b/grub-core/fs/jfs.c
@@ -279,7 +279,7 @@ get_ext_offset (grub_uint8_t offset1, grub_uint32_t offset2)
return (((grub_uint64_t) offset1 << 32) | grub_le_to_cpu32 (offset2));
}
-static grub_int64_t
+static grub_uint64_t
getblk (struct grub_jfs_treehead *treehead,
struct grub_jfs_tree_extent *extents,
int max_extents,
@@ -290,6 +290,8 @@ getblk (struct grub_jfs_treehead *treehead,
int i;
grub_uint64_t ext_offset, ext_blk;
+ grub_errno = GRUB_ERR_NONE;
+
for (i = 0; i < grub_le_to_cpu16 (treehead->count) - 2 &&
i < max_extents; i++)
{
@@ -312,7 +314,7 @@ getblk (struct grub_jfs_treehead *treehead,
if (found != -1)
{
- grub_int64_t ret = -1;
+ grub_uint64_t ret = 0;
struct
{
struct grub_jfs_treehead treehead;
@@ -321,7 +323,7 @@ getblk (struct grub_jfs_treehead *treehead,
tree = grub_zalloc (sizeof (*tree));
if (!tree)
- return -1;
+ return 0;
if (!grub_disk_read (data->disk,
(grub_disk_addr_t) ext_blk
@@ -334,19 +336,20 @@ getblk (struct grub_jfs_treehead *treehead,
else
{
grub_error (GRUB_ERR_BAD_FS, "jfs: infinite recursion detected");
- ret = -1;
+ ret = 0;
}
}
grub_free (tree);
return ret;
}
- return -1;
+ grub_error (GRUB_ERR_READ_ERROR, "jfs: block %" PRIuGRUB_UINT64_T " not found", blk);
+ return 0;
}
/* Get the block number for the block BLK in the node INODE in the
mounted filesystem DATA. */
-static grub_int64_t
+static grub_uint64_t
grub_jfs_blkno (struct grub_jfs_data *data, struct grub_jfs_inode *inode,
grub_uint64_t blk)
{

View file

@ -0,0 +1,46 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Fri, 31 May 2024 15:14:23 +0800
Subject: [PATCH] fs/ext2: Fix out-of-bounds read for inline extents
When inline extents are used, i.e. the extent tree depth equals zero,
a maximum of four entries can fit into the inode's data block. If the
extent header states a number of entries greater than four the current
ext2 implementation causes an out-of-bounds read. Fix this issue by
capping the number of extents to four when reading inline extents.
Reported-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Michael Chang <mchang@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/ext2.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/grub-core/fs/ext2.c b/grub-core/fs/ext2.c
index e1cc5e62a..3f9f6b208 100644
--- a/grub-core/fs/ext2.c
+++ b/grub-core/fs/ext2.c
@@ -495,6 +495,8 @@ grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
struct grub_ext4_extent *ext;
int i;
grub_disk_addr_t ret;
+ grub_uint16_t nent;
+ const grub_uint16_t max_inline_ext = sizeof (inode->blocks) / sizeof (*ext) - 1; /* Minus 1 extent header. */
if (grub_ext4_find_leaf (data, (struct grub_ext4_extent_header *) inode->blocks.dir_blocks,
fileblock, &leaf) != GRUB_ERR_NONE)
@@ -508,7 +510,13 @@ 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);
+
+ if (leaf->depth == 0)
+ nent = grub_min (nent, max_inline_ext);
+
+ for (i = 0; i < nent; i++)
{
if (fileblock < grub_le_to_cpu32 (ext[i].block))
break;

View file

@ -0,0 +1,47 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Mon, 3 Jun 2024 12:12:06 +0800
Subject: [PATCH] fs/ntfs: Fix out-of-bounds read
When parsing NTFS file records the presence of the 0xFF marker indicates
the end of the attribute list. This value signifies that there are no
more attributes to process.
However, when the end marker is missing due to corrupted metadata the
loop continues to read beyond the attribute list resulting in out-of-bounds
reads and potentially entering an infinite loop.
This patch adds a check to provide a stop condition for the loop ensuring
it stops at the end of the attribute list or at the end of the Master File
Table. This guards against out-of-bounds reads and prevents infinite loops.
Reported-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Michael Chang <mchang@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/ntfs.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c
index de435aa14..8a5384247 100644
--- a/grub-core/fs/ntfs.c
+++ b/grub-core/fs/ntfs.c
@@ -139,6 +139,8 @@ free_attr (struct grub_ntfs_attr *at)
static grub_uint8_t *
find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr)
{
+ grub_uint8_t *mft_end;
+
if (at->flags & GRUB_NTFS_AF_ALST)
{
retry:
@@ -191,7 +193,8 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr)
return NULL;
}
at->attr_cur = at->attr_nxt;
- while (*at->attr_cur != 0xFF)
+ mft_end = at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR);
+ while (at->attr_cur < mft_end && *at->attr_cur != 0xFF)
{
at->attr_nxt += u16at (at->attr_cur, 4);
if (*at->attr_cur == GRUB_NTFS_AT_ATTRIBUTE_LIST)

View file

@ -0,0 +1,141 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Tue, 7 Jan 2025 11:38:34 +0000
Subject: [PATCH] fs/ntfs: Track the end of the MFT attribute buffer
The end of the attribute buffer should be stored alongside the rest of
the attribute struct as right now it is not possible to implement bounds
checking when accessing attributes sequentially.
This is done via:
- updating init_attr() to set at->end and check is is not initially out of bounds,
- implementing checks as init_attr() had its type change in its callers,
- updating the value of at->end when needed.
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/ntfs.c | 34 ++++++++++++++++++++++++++++------
include/grub/ntfs.h | 1 +
2 files changed, 29 insertions(+), 6 deletions(-)
diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c
index 8a5384247..dbda720e1 100644
--- a/grub-core/fs/ntfs.c
+++ b/grub-core/fs/ntfs.c
@@ -119,13 +119,20 @@ static grub_err_t read_data (struct grub_ntfs_attr *at, grub_uint8_t *pa,
grub_disk_read_hook_t read_hook,
void *read_hook_data);
-static void
+static grub_err_t
init_attr (struct grub_ntfs_attr *at, struct grub_ntfs_file *mft)
{
at->mft = mft;
at->flags = (mft == &mft->data->mmft) ? GRUB_NTFS_AF_MMFT : 0;
at->attr_nxt = mft->buf + first_attr_off (mft->buf);
+ at->end = mft->buf + (mft->data->mft_size << GRUB_NTFS_BLK_SHR);
+
+ if (at->attr_nxt > at->end)
+ return grub_error (GRUB_ERR_BAD_FS, "attributes start outside the MFT");
+
at->attr_end = at->emft_buf = at->edat_buf = at->sbuf = NULL;
+
+ return GRUB_ERR_NONE;
}
static void
@@ -239,6 +246,10 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr)
pa_end = at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR);
}
at->flags |= GRUB_NTFS_AF_ALST;
+
+ /* From this point on pa_end is the end of the buffer */
+ at->end = pa_end;
+
while (at->attr_nxt < at->attr_end)
{
if ((*at->attr_nxt == attr) || (attr == 0))
@@ -298,7 +309,9 @@ locate_attr (struct grub_ntfs_attr *at, struct grub_ntfs_file *mft,
{
grub_uint8_t *pa;
- init_attr (at, mft);
+ if (init_attr (at, mft) != GRUB_ERR_NONE)
+ return NULL;
+
pa = find_attr (at, attr);
if (pa == NULL)
return NULL;
@@ -314,7 +327,8 @@ locate_attr (struct grub_ntfs_attr *at, struct grub_ntfs_file *mft,
}
grub_errno = GRUB_ERR_NONE;
free_attr (at);
- init_attr (at, mft);
+ if (init_attr (at, mft) != GRUB_ERR_NONE)
+ return NULL;
pa = find_attr (at, attr);
}
return pa;
@@ -585,7 +599,7 @@ init_file (struct grub_ntfs_file *mft, grub_uint64_t mftno)
mft->attr.attr_end = 0; /* Don't jump to attribute list */
}
else
- init_attr (&mft->attr, mft);
+ return init_attr (&mft->attr, mft);
return 0;
}
@@ -811,7 +825,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);
@@ -842,7 +858,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;
@@ -1207,6 +1225,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);
@@ -1232,7 +1251,10 @@ grub_ntfs_label (grub_device_t device, char **label)
goto fail;
}
- init_attr (&mft->attr, mft);
+ err = init_attr (&mft->attr, mft);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
pa = find_attr (&mft->attr, GRUB_NTFS_AT_VOLUME_NAME);
if (pa >= mft->buf + (mft->data->mft_size << GRUB_NTFS_BLK_SHR))
diff --git a/include/grub/ntfs.h b/include/grub/ntfs.h
index d1a6af696..ec1c4db38 100644
--- a/include/grub/ntfs.h
+++ b/include/grub/ntfs.h
@@ -134,6 +134,7 @@ struct grub_ntfs_attr
grub_uint8_t *attr_cur, *attr_nxt, *attr_end;
grub_uint32_t save_pos;
grub_uint8_t *sbuf;
+ grub_uint8_t *end;
struct grub_ntfs_file *mft;
};

View file

@ -0,0 +1,183 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Tue, 14 May 2024 12:39:56 +0100
Subject: [PATCH] fs/ntfs: Use a helper function to access attributes
Right now to access the next attribute the code reads the length of the
current attribute and adds that to the current pointer. This is error
prone as bounds checking needs to be performed all over the place. So,
implement a helper and ensure its used across find_attr() and read_attr().
This commit does *not* implement full bounds checking. It is just the
preparation work for this to be added into the helper.
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/ntfs.c | 69 +++++++++++++++++++++++++++++++++++++++++++----------
include/grub/ntfs.h | 2 ++
2 files changed, 58 insertions(+), 13 deletions(-)
diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c
index dbda720e1..1c678f3d0 100644
--- a/grub-core/fs/ntfs.c
+++ b/grub-core/fs/ntfs.c
@@ -70,6 +70,25 @@ res_attr_data_len (void *res_attr_ptr)
return u32at (res_attr_ptr, 0x10);
}
+/* Return the next attribute if it exists, otherwise return NULL. */
+static grub_uint8_t *
+next_attribute (grub_uint8_t *curr_attribute, void *end)
+{
+ grub_uint8_t *next = curr_attribute;
+
+ /*
+ * Need to verify we aren't exceeding the end of the buffer by reading the
+ * header for the current attribute
+ */
+ if (curr_attribute + GRUB_NTFS_ATTRIBUTE_HEADER_SIZE >= (grub_uint8_t *) end)
+ return NULL;
+
+ next += u16at (curr_attribute, 4);
+
+ return next;
+}
+
+
grub_ntfscomp_func_t grub_ntfscomp_func;
static grub_err_t
@@ -151,13 +170,13 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr)
if (at->flags & GRUB_NTFS_AF_ALST)
{
retry:
- while (at->attr_nxt < at->attr_end)
+ while (at->attr_nxt)
{
at->attr_cur = at->attr_nxt;
- at->attr_nxt += u16at (at->attr_cur, 4);
+ at->attr_nxt = next_attribute (at->attr_cur, at->attr_end);
if ((*at->attr_cur == attr) || (attr == 0))
{
- grub_uint8_t *new_pos;
+ grub_uint8_t *new_pos, *end;
if (at->flags & GRUB_NTFS_AF_MMFT)
{
@@ -181,15 +200,36 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr)
return NULL;
}
+ /*
+ * Only time emft_bufs is defined is in this function, with this
+ * size.
+ */
+ grub_size_t emft_buf_size =
+ at->mft->data->mft_size << GRUB_NTFS_BLK_SHR;
+
+ /*
+ * Needs to be enough space for the successful case to even
+ * bother.
+ */
+ if (first_attr_off (at->emft_buf) >= (emft_buf_size - 0x18 - 2))
+ {
+ grub_error (GRUB_ERR_BAD_FS,
+ "can\'t find 0x%X in attribute list",
+ (unsigned char) *at->attr_cur);
+ return NULL;
+ }
+
new_pos = &at->emft_buf[first_attr_off (at->emft_buf)];
- while (*new_pos != 0xFF)
+ end = &at->emft_buf[emft_buf_size];
+
+ while (new_pos && *new_pos != 0xFF)
{
if ((*new_pos == *at->attr_cur)
&& (u16at (new_pos, 0xE) == u16at (at->attr_cur, 0x18)))
{
return new_pos;
}
- new_pos += u16at (new_pos, 4);
+ new_pos = next_attribute (new_pos, end);
}
grub_error (GRUB_ERR_BAD_FS,
"can\'t find 0x%X in attribute list",
@@ -203,7 +243,7 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr)
mft_end = at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR);
while (at->attr_cur < mft_end && *at->attr_cur != 0xFF)
{
- at->attr_nxt += u16at (at->attr_cur, 4);
+ at->attr_nxt = next_attribute (at->attr_cur, at->end);
if (*at->attr_cur == GRUB_NTFS_AT_ATTRIBUTE_LIST)
at->attr_end = at->attr_cur;
if ((*at->attr_cur == attr) || (attr == 0))
@@ -250,13 +290,14 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr)
/* From this point on pa_end is the end of the buffer */
at->end = pa_end;
- while (at->attr_nxt < at->attr_end)
+ while (at->attr_nxt)
{
if ((*at->attr_nxt == attr) || (attr == 0))
break;
- at->attr_nxt += u16at (at->attr_nxt, 4);
+ at->attr_nxt = next_attribute (at->attr_nxt, pa_end);
}
- if (at->attr_nxt >= at->attr_end)
+
+ if (at->attr_nxt >= at->attr_end || at->attr_nxt == NULL)
return NULL;
if ((at->flags & GRUB_NTFS_AF_MMFT) && (attr == GRUB_NTFS_AT_DATA))
@@ -277,7 +318,8 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr)
grub_cpu_to_le32 (at->mft->data->mft_start
+ 1));
pa = at->attr_nxt + u16at (pa, 4);
- while (pa < at->attr_end)
+
+ while (pa)
{
if (*pa != attr)
break;
@@ -293,7 +335,7 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr)
u32at (pa, 0x10) * (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR),
at->mft->data->mft_size << GRUB_NTFS_BLK_SHR, 0, 0, 0))
return NULL;
- pa += u16at (pa, 4);
+ pa = next_attribute (pa, pa_end);
}
at->attr_nxt = at->attr_cur;
at->flags &= ~GRUB_NTFS_AF_GPOS;
@@ -530,14 +572,15 @@ read_attr (struct grub_ntfs_attr *at, grub_uint8_t *dest, grub_disk_addr_t ofs,
else
vcn = ofs >> (at->mft->data->log_spc + GRUB_NTFS_BLK_SHR);
pa = at->attr_nxt + u16at (at->attr_nxt, 4);
- while (pa < at->attr_end)
+
+ while (pa)
{
if (*pa != attr)
break;
if (u32at (pa, 8) > vcn)
break;
at->attr_nxt = pa;
- pa += u16at (pa, 4);
+ pa = next_attribute (pa, at->attr_end);
}
}
pp = find_attr (at, attr);
diff --git a/include/grub/ntfs.h b/include/grub/ntfs.h
index ec1c4db38..2c8078403 100644
--- a/include/grub/ntfs.h
+++ b/include/grub/ntfs.h
@@ -89,6 +89,8 @@ enum
#define GRUB_NTFS_COM_SEC (GRUB_NTFS_COM_LEN >> GRUB_NTFS_BLK_SHR)
#define GRUB_NTFS_LOG_COM_SEC (GRUB_NTFS_COM_LOG_LEN - GRUB_NTFS_BLK_SHR)
+#define GRUB_NTFS_ATTRIBUTE_HEADER_SIZE 16
+
enum
{
GRUB_NTFS_AF_ALST = 1,

View file

@ -0,0 +1,43 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Fri, 31 May 2024 15:14:57 +0800
Subject: [PATCH] fs/xfs: Fix out-of-bounds read
The number of records in the root key array read from disk was not being
validated against the size of the root node. This could lead to an
out-of-bounds read.
This patch adds a check to ensure that the number of records in the root
key array does not exceed the expected size of a root node read from
disk. If this check detects an out-of-bounds condition the operation is
aborted to prevent random errors due to metadata corruption.
Reported-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Michael Chang <mchang@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/xfs.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c
index 92046f9bd..96f62c5a4 100644
--- a/grub-core/fs/xfs.c
+++ b/grub-core/fs/xfs.c
@@ -595,6 +595,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++)
{

View file

@ -0,0 +1,42 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Sun, 12 May 2024 06:03:58 +0100
Subject: [PATCH] fs/xfs: Ensuring failing to mount sets a grub_errno
It was previously possible for grub_xfs_mount() to return NULL without
setting grub_errno if the XFS version was invalid. This resulted in it
being possible for grub_dl_unref() to be called twice allowing the XFS
module to be unloaded while there were still references to it.
Fixing this problem in general by ensuring a grub_errno is set if the
fail label is reached.
Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/xfs.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c
index 96f62c5a4..a837f9824 100644
--- a/grub-core/fs/xfs.c
+++ b/grub-core/fs/xfs.c
@@ -327,6 +327,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;
}
@@ -1068,7 +1070,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);

View file

@ -0,0 +1,32 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Sun, 12 May 2024 03:01:40 +0100
Subject: [PATCH] kern/file: Ensure file->data is set
This is to avoid a generic issue were some filesystems would not set
data and also not set a grub_errno. This meant it was possible for many
filesystems to grub_dl_unref() themselves multiple times resulting in
it being possible to unload the filesystems while there were still
references to them, e.g., via a loopback.
Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/kern/file.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c
index 75510df7c..85e832bd8 100644
--- a/grub-core/kern/file.c
+++ b/grub-core/kern/file.c
@@ -124,6 +124,9 @@ grub_file_open (const char *name, enum grub_file_type type)
if ((file->fs->fs_open) (file, file_name) != GRUB_ERR_NONE)
goto fail;
+ if (file->data == NULL)
+ goto fail;
+
file->name = grub_strdup (name);
grub_errno = GRUB_ERR_NONE;

View file

@ -0,0 +1,440 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Tue, 11 Feb 2025 13:44:25 -0600
Subject: [PATCH] kern/file: Implement filesystem reference counting
The grub_file_open() and grub_file_close() should be the only places
that allow a reference to a filesystem to stay open. So, add grub_dl_t
to grub_fs_t and set this in the GRUB_MOD_INIT() for each filesystem to
avoid issues when filesystems forget to do it themselves or do not track
their own references, e.g. squash4.
The fs_label(), fs_uuid(), fs_mtime() and fs_read() should all ref and
unref in the same function but it is essentially redundant in GRUB
single threaded model.
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/affs.c | 1 +
grub-core/fs/bfs.c | 1 +
grub-core/fs/btrfs.c | 1 +
grub-core/fs/cbfs.c | 1 +
grub-core/fs/cpio.c | 1 +
grub-core/fs/cpio_be.c | 1 +
grub-core/fs/ext2.c | 1 +
grub-core/fs/f2fs.c | 1 +
grub-core/fs/fat.c | 1 +
grub-core/fs/hfs.c | 1 +
grub-core/fs/hfsplus.c | 1 +
grub-core/fs/iso9660.c | 1 +
grub-core/fs/jfs.c | 1 +
grub-core/fs/minix.c | 1 +
grub-core/fs/newc.c | 1 +
grub-core/fs/nilfs2.c | 1 +
grub-core/fs/ntfs.c | 1 +
grub-core/fs/odc.c | 1 +
grub-core/fs/proc.c | 1 +
grub-core/fs/reiserfs.c | 1 +
grub-core/fs/romfs.c | 1 +
grub-core/fs/sfs.c | 1 +
grub-core/fs/squash4.c | 1 +
grub-core/fs/tar.c | 1 +
grub-core/fs/udf.c | 1 +
grub-core/fs/ufs.c | 1 +
grub-core/fs/xfs.c | 1 +
grub-core/fs/zfs/zfs.c | 1 +
grub-core/kern/file.c | 7 +++++++
include/grub/fs.h | 4 ++++
30 files changed, 39 insertions(+)
diff --git a/grub-core/fs/affs.c b/grub-core/fs/affs.c
index ed606b3f1..9b0afb954 100644
--- a/grub-core/fs/affs.c
+++ b/grub-core/fs/affs.c
@@ -703,6 +703,7 @@ static struct grub_fs grub_affs_fs =
GRUB_MOD_INIT(affs)
{
+ grub_affs_fs.mod = mod;
grub_fs_register (&grub_affs_fs);
my_mod = mod;
}
diff --git a/grub-core/fs/bfs.c b/grub-core/fs/bfs.c
index 07cb3e3ac..f37b16895 100644
--- a/grub-core/fs/bfs.c
+++ b/grub-core/fs/bfs.c
@@ -1106,6 +1106,7 @@ GRUB_MOD_INIT (bfs)
{
COMPILE_TIME_ASSERT (1 << LOG_EXTENT_SIZE ==
sizeof (struct grub_bfs_extent));
+ grub_bfs_fs.mod = mod;
grub_fs_register (&grub_bfs_fs);
}
diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
index ad35e7575..6593f5175 100644
--- a/grub-core/fs/btrfs.c
+++ b/grub-core/fs/btrfs.c
@@ -3402,6 +3402,7 @@ subvol_get_env (struct grub_env_var *var __attribute__ ((unused)),
GRUB_MOD_INIT (btrfs)
{
+ grub_btrfs_fs.mod = mod;
grub_fs_register (&grub_btrfs_fs);
cmd_info = grub_register_command("btrfs-info", grub_cmd_btrfs_info,
"DEVICE",
diff --git a/grub-core/fs/cbfs.c b/grub-core/fs/cbfs.c
index 8ab7106af..2332745fe 100644
--- a/grub-core/fs/cbfs.c
+++ b/grub-core/fs/cbfs.c
@@ -390,6 +390,7 @@ GRUB_MOD_INIT (cbfs)
#if (defined (__i386__) || defined (__x86_64__)) && !defined (GRUB_UTIL) && !defined (GRUB_MACHINE_EMU) && !defined (GRUB_MACHINE_XEN)
init_cbfsdisk ();
#endif
+ grub_cbfs_fs.mod = mod;
grub_fs_register (&grub_cbfs_fs);
}
diff --git a/grub-core/fs/cpio.c b/grub-core/fs/cpio.c
index dab5f9898..1799f7ff5 100644
--- a/grub-core/fs/cpio.c
+++ b/grub-core/fs/cpio.c
@@ -52,6 +52,7 @@ read_number (const grub_uint16_t *arr, grub_size_t size)
GRUB_MOD_INIT (cpio)
{
+ grub_cpio_fs.mod = mod;
grub_fs_register (&grub_cpio_fs);
}
diff --git a/grub-core/fs/cpio_be.c b/grub-core/fs/cpio_be.c
index 846548892..7bed1b848 100644
--- a/grub-core/fs/cpio_be.c
+++ b/grub-core/fs/cpio_be.c
@@ -52,6 +52,7 @@ read_number (const grub_uint16_t *arr, grub_size_t size)
GRUB_MOD_INIT (cpio_be)
{
+ grub_cpio_fs.mod = mod;
grub_fs_register (&grub_cpio_fs);
}
diff --git a/grub-core/fs/ext2.c b/grub-core/fs/ext2.c
index 3f9f6b208..c3058f7e7 100644
--- a/grub-core/fs/ext2.c
+++ b/grub-core/fs/ext2.c
@@ -1131,6 +1131,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 db8a65f8d..f6d6beaa5 100644
--- a/grub-core/fs/f2fs.c
+++ b/grub-core/fs/f2fs.c
@@ -1353,6 +1353,7 @@ static struct grub_fs grub_f2fs_fs = {
GRUB_MOD_INIT (f2fs)
{
+ grub_f2fs_fs.mod = mod;
grub_fs_register (&grub_f2fs_fs);
my_mod = mod;
}
diff --git a/grub-core/fs/fat.c b/grub-core/fs/fat.c
index 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 920112b03..ce7581dd5 100644
--- a/grub-core/fs/hfs.c
+++ b/grub-core/fs/hfs.c
@@ -1434,6 +1434,7 @@ static struct grub_fs grub_hfs_fs =
GRUB_MOD_INIT(hfs)
{
+ grub_hfs_fs.mod = mod;
if (!grub_is_lockdown ())
grub_fs_register (&grub_hfs_fs);
my_mod = mod;
diff --git a/grub-core/fs/hfsplus.c b/grub-core/fs/hfsplus.c
index de71fd486..3f203abcc 100644
--- a/grub-core/fs/hfsplus.c
+++ b/grub-core/fs/hfsplus.c
@@ -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/iso9660.c b/grub-core/fs/iso9660.c
index 8e3c95c4f..c73cb9ce0 100644
--- a/grub-core/fs/iso9660.c
+++ b/grub-core/fs/iso9660.c
@@ -1260,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 70a2f4947..b0283ac00 100644
--- a/grub-core/fs/jfs.c
+++ b/grub-core/fs/jfs.c
@@ -1005,6 +1005,7 @@ static struct grub_fs grub_jfs_fs =
GRUB_MOD_INIT(jfs)
{
+ grub_jfs_fs.mod = mod;
grub_fs_register (&grub_jfs_fs);
my_mod = mod;
}
diff --git a/grub-core/fs/minix.c b/grub-core/fs/minix.c
index 5354951d1..b7679c3e2 100644
--- a/grub-core/fs/minix.c
+++ b/grub-core/fs/minix.c
@@ -734,6 +734,7 @@ GRUB_MOD_INIT(minix)
#endif
#endif
{
+ grub_minix_fs.mod = mod;
grub_fs_register (&grub_minix_fs);
my_mod = mod;
}
diff --git a/grub-core/fs/newc.c b/grub-core/fs/newc.c
index 4fb8b2e3d..43b7f8b64 100644
--- a/grub-core/fs/newc.c
+++ b/grub-core/fs/newc.c
@@ -64,6 +64,7 @@ read_number (const char *str, grub_size_t size)
GRUB_MOD_INIT (newc)
{
+ grub_cpio_fs.mod = mod;
grub_fs_register (&grub_cpio_fs);
}
diff --git a/grub-core/fs/nilfs2.c b/grub-core/fs/nilfs2.c
index fc7374ead..4e1e71738 100644
--- a/grub-core/fs/nilfs2.c
+++ b/grub-core/fs/nilfs2.c
@@ -1231,6 +1231,7 @@ GRUB_MOD_INIT (nilfs2)
grub_nilfs2_dat_entry));
COMPILE_TIME_ASSERT (1 << LOG_INODE_SIZE
== sizeof (struct grub_nilfs2_inode));
+ grub_nilfs2_fs.mod = mod;
grub_fs_register (&grub_nilfs2_fs);
my_mod = mod;
}
diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c
index 64f4f2221..4e144cc3c 100644
--- a/grub-core/fs/ntfs.c
+++ b/grub-core/fs/ntfs.c
@@ -1541,6 +1541,7 @@ static struct grub_fs grub_ntfs_fs =
GRUB_MOD_INIT (ntfs)
{
+ grub_ntfs_fs.mod = mod;
grub_fs_register (&grub_ntfs_fs);
my_mod = mod;
}
diff --git a/grub-core/fs/odc.c b/grub-core/fs/odc.c
index 790000622..8e4e8aeac 100644
--- a/grub-core/fs/odc.c
+++ b/grub-core/fs/odc.c
@@ -52,6 +52,7 @@ read_number (const char *str, grub_size_t size)
GRUB_MOD_INIT (odc)
{
+ grub_cpio_fs.mod = mod;
grub_fs_register (&grub_cpio_fs);
}
diff --git a/grub-core/fs/proc.c b/grub-core/fs/proc.c
index 5f516502d..bcde43349 100644
--- a/grub-core/fs/proc.c
+++ b/grub-core/fs/proc.c
@@ -192,6 +192,7 @@ static struct grub_fs grub_procfs_fs =
GRUB_MOD_INIT (procfs)
{
+ grub_procfs_fs.mod = mod;
grub_disk_dev_register (&grub_procfs_dev);
grub_fs_register (&grub_procfs_fs);
}
diff --git a/grub-core/fs/reiserfs.c b/grub-core/fs/reiserfs.c
index 42818c376..e8b0b6383 100644
--- a/grub-core/fs/reiserfs.c
+++ b/grub-core/fs/reiserfs.c
@@ -1407,6 +1407,7 @@ static struct grub_fs grub_reiserfs_fs =
GRUB_MOD_INIT(reiserfs)
{
+ grub_reiserfs_fs.mod = mod;
grub_fs_register (&grub_reiserfs_fs);
my_mod = mod;
}
diff --git a/grub-core/fs/romfs.c b/grub-core/fs/romfs.c
index 1f7dcfca1..56b0b2b2f 100644
--- a/grub-core/fs/romfs.c
+++ b/grub-core/fs/romfs.c
@@ -475,6 +475,7 @@ static struct grub_fs grub_romfs_fs =
GRUB_MOD_INIT(romfs)
{
+ grub_romfs_fs.mod = mod;
grub_fs_register (&grub_romfs_fs);
}
diff --git a/grub-core/fs/sfs.c b/grub-core/fs/sfs.c
index 983e88008..f0d7cac43 100644
--- a/grub-core/fs/sfs.c
+++ b/grub-core/fs/sfs.c
@@ -779,6 +779,7 @@ static struct grub_fs grub_sfs_fs =
GRUB_MOD_INIT(sfs)
{
+ grub_sfs_fs.mod = mod;
grub_fs_register (&grub_sfs_fs);
my_mod = mod;
}
diff --git a/grub-core/fs/squash4.c b/grub-core/fs/squash4.c
index a30e6ebe1..6e9d63874 100644
--- a/grub-core/fs/squash4.c
+++ b/grub-core/fs/squash4.c
@@ -1044,6 +1044,7 @@ static struct grub_fs grub_squash_fs =
GRUB_MOD_INIT(squash4)
{
+ grub_squash_fs.mod = mod;
grub_fs_register (&grub_squash_fs);
}
diff --git a/grub-core/fs/tar.c b/grub-core/fs/tar.c
index 386c09022..fd2ec1f74 100644
--- a/grub-core/fs/tar.c
+++ b/grub-core/fs/tar.c
@@ -354,6 +354,7 @@ static struct grub_fs grub_cpio_fs = {
GRUB_MOD_INIT (tar)
{
+ grub_cpio_fs.mod = mod;
grub_fs_register (&grub_cpio_fs);
}
diff --git a/grub-core/fs/udf.c b/grub-core/fs/udf.c
index b836e6107..8765c633c 100644
--- a/grub-core/fs/udf.c
+++ b/grub-core/fs/udf.c
@@ -1455,6 +1455,7 @@ static struct grub_fs grub_udf_fs = {
GRUB_MOD_INIT (udf)
{
+ grub_udf_fs.mod = mod;
grub_fs_register (&grub_udf_fs);
my_mod = mod;
}
diff --git a/grub-core/fs/ufs.c b/grub-core/fs/ufs.c
index 01235101b..e82d9356d 100644
--- a/grub-core/fs/ufs.c
+++ b/grub-core/fs/ufs.c
@@ -899,6 +899,7 @@ GRUB_MOD_INIT(ufs1)
#endif
#endif
{
+ grub_ufs_fs.mod = mod;
grub_fs_register (&grub_ufs_fs);
my_mod = mod;
}
diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c
index a837f9824..6c952aef1 100644
--- a/grub-core/fs/xfs.c
+++ b/grub-core/fs/xfs.c
@@ -1304,6 +1304,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..a497b1869 100644
--- a/grub-core/fs/zfs/zfs.c
+++ b/grub-core/fs/zfs/zfs.c
@@ -4424,6 +4424,7 @@ static struct grub_fs grub_zfs_fs = {
GRUB_MOD_INIT (zfs)
{
COMPILE_TIME_ASSERT (sizeof (zap_leaf_chunk_t) == ZAP_LEAF_CHUNKSIZE);
+ grub_zfs_fs.mod = mod;
grub_fs_register (&grub_zfs_fs);
#ifndef GRUB_UTIL
my_mod = mod;
diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c
index 85e832bd8..ec90a26ba 100644
--- a/grub-core/kern/file.c
+++ b/grub-core/kern/file.c
@@ -25,6 +25,7 @@
#include <grub/fs.h>
#include <grub/device.h>
#include <grub/i18n.h>
+#include <grub/dl.h>
void (*EXPORT_VAR (grub_grubnet_fini)) (void);
@@ -127,6 +128,9 @@ grub_file_open (const char *name, enum grub_file_type type)
if (file->data == NULL)
goto fail;
+ if (file->fs->mod)
+ grub_dl_ref (file->fs->mod);
+
file->name = grub_strdup (name);
grub_errno = GRUB_ERR_NONE;
@@ -219,6 +223,9 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len)
grub_err_t
grub_file_close (grub_file_t file)
{
+ if (file->fs->mod)
+ grub_dl_unref (file->fs->mod);
+
grub_dprintf ("file", "Closing `%s' ...\n", file->name);
if (file->fs->fs_close)
(file->fs->fs_close) (file);
diff --git a/include/grub/fs.h b/include/grub/fs.h
index 026bc3bb8..df4c93b16 100644
--- a/include/grub/fs.h
+++ b/include/grub/fs.h
@@ -23,6 +23,7 @@
#include <grub/device.h>
#include <grub/symbol.h>
#include <grub/types.h>
+#include <grub/dl.h>
#include <grub/list.h>
/* 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);

View file

@ -0,0 +1,366 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alec Brown <alec.r.brown@oracle.com>
Date: Wed, 24 Jan 2024 06:26:37 +0000
Subject: [PATCH] cli_lock: Add build option to block command line interface
Add functionality to disable command line interface access and editing of GRUB
menu entries if GRUB image is built with --disable-cli.
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Vladimir Serbinenko <phcoder@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
docs/grub.texi | 6 ++++--
grub-core/kern/main.c | 28 ++++++++++++++++++++++++++++
grub-core/kern/rescue_reader.c | 13 +++++++++++++
grub-core/normal/auth.c | 3 +++
grub-core/normal/menu_text.c | 31 +++++++++++++++++--------------
include/grub/kernel.h | 1 +
include/grub/misc.h | 2 ++
include/grub/util/install.h | 8 ++++++--
util/grub-install-common.c | 10 ++++++++--
util/grub-mkimage.c | 9 ++++++++-
util/mkimage.c | 15 ++++++++++++++-
11 files changed, 104 insertions(+), 22 deletions(-)
diff --git a/docs/grub.texi b/docs/grub.texi
index 096a3cde0..9ce9c5b82 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -6520,8 +6520,10 @@ the GRUB command line, edit menu entries, and execute any menu entry. If
@samp{superusers} is set, then use of the command line and editing of menu
entries are automatically restricted to superusers. Setting @samp{superusers}
to empty string effectively disables both access to CLI and editing of menu
-entries. Note: The environment variable needs to be exported to also affect
-the section defined by the @samp{submenu} command (@pxref{submenu}).
+entries. Building a grub image with @samp{--disable-cli} option will also
+disable access to CLI and editing of menu entries, as well as disabling rescue
+mode. Note: The environment variable needs to be exported to also affect the
+section defined by the @samp{submenu} command (@pxref{submenu}).
Other users may be allowed to execute specific menu entries by giving a list of
usernames (as above) using the @option{--users} option to the
diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c
index 8e89763f4..0d6b8138d 100644
--- a/grub-core/kern/main.c
+++ b/grub-core/kern/main.c
@@ -30,11 +30,14 @@
#include <grub/reader.h>
#include <grub/parser.h>
#include <grub/verify.h>
+#include <grub/types.h>
#ifdef GRUB_MACHINE_PCBIOS
#include <grub/machine/memory.h>
#endif
+static bool cli_disabled = false;
+
grub_addr_t
grub_modules_get_end (void)
{
@@ -299,6 +302,28 @@ grub_load_normal_mode (void)
grub_command_execute ("normal", 0, 0);
}
+bool
+grub_is_cli_disabled (void)
+{
+ return cli_disabled;
+}
+
+static void
+check_is_cli_disabled (void)
+{
+ struct grub_module_header *header;
+ header = 0;
+
+ FOR_MODULES (header)
+ {
+ if (header->type == OBJ_TYPE_DISABLE_CLI)
+ {
+ cli_disabled = true;
+ return;
+ }
+ }
+}
+
static void
reclaim_module_space (void)
{
@@ -356,6 +381,9 @@ grub_main (void)
grub_boot_time ("After loading embedded modules.");
+ /* Check if the CLI should be disabled */
+ check_is_cli_disabled ();
+
/* It is better to set the root device as soon as possible,
for convenience. */
grub_set_prefix_and_root ();
diff --git a/grub-core/kern/rescue_reader.c b/grub-core/kern/rescue_reader.c
index dcd7d4439..4259857ba 100644
--- a/grub-core/kern/rescue_reader.c
+++ b/grub-core/kern/rescue_reader.c
@@ -78,6 +78,19 @@ grub_rescue_read_line (char **line, int cont,
void __attribute__ ((noreturn))
grub_rescue_run (void)
{
+ /* Stall if the CLI has been disabled */
+ if (grub_is_cli_disabled ())
+ {
+ grub_printf ("Rescue mode has been disabled...\n");
+
+ do
+ {
+ /* Do not optimize out the loop. */
+ asm volatile ("");
+ }
+ while (1);
+ }
+
grub_printf ("Entering rescue mode...\n");
while (1)
diff --git a/grub-core/normal/auth.c b/grub-core/normal/auth.c
index 517fc623f..d94020186 100644
--- a/grub-core/normal/auth.c
+++ b/grub-core/normal/auth.c
@@ -209,6 +209,9 @@ grub_auth_check_authentication (const char *userlist)
char entered[GRUB_AUTH_MAX_PASSLEN];
struct grub_auth_user *user;
+ if (grub_is_cli_disabled ())
+ return GRUB_ACCESS_DENIED;
+
grub_memset (login, 0, sizeof (login));
if (is_authenticated (userlist))
diff --git a/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c
index 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/include/grub/kernel.h b/include/grub/kernel.h
index 98edc0863..f98a780da 100644
--- a/include/grub/kernel.h
+++ b/include/grub/kernel.h
@@ -33,6 +33,7 @@ enum
OBJ_TYPE_DISABLE_SHIM_LOCK,
OBJ_TYPE_GPG_PUBKEY,
OBJ_TYPE_X509_PUBKEY,
+ OBJ_TYPE_DISABLE_CLI
};
/* The module header. */
diff --git a/include/grub/misc.h b/include/grub/misc.h
index 6b1e084af..d6e9bae8e 100644
--- a/include/grub/misc.h
+++ b/include/grub/misc.h
@@ -442,6 +442,8 @@ grub_uint64_t EXPORT_FUNC(grub_divmod64) (grub_uint64_t n,
grub_uint64_t d,
grub_uint64_t *r);
+extern bool EXPORT_FUNC(grub_is_cli_disabled) (void);
+
/* Must match softdiv group in gentpl.py. */
#if !defined(GRUB_MACHINE_EMU) && (defined(__arm__) || defined(__ia64__) || \
(defined(__riscv) && (__riscv_xlen == 32)))
diff --git a/include/grub/util/install.h b/include/grub/util/install.h
index 59eabb9bb..dbf3c216d 100644
--- a/include/grub/util/install.h
+++ b/include/grub/util/install.h
@@ -72,6 +72,8 @@
{ "appended-signature-size", GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,\
"SIZE", 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), \
1}, \
+ { "disable-cli", GRUB_INSTALL_OPTIONS_DISABLE_CLI, 0, 0, \
+ N_("disabled command line interface access"), 0 }, \
{ "verbose", 'v', 0, 0, \
N_("print verbose messages."), 1 }
@@ -135,7 +137,8 @@ enum grub_install_options {
GRUB_INSTALL_OPTIONS_DTB,
GRUB_INSTALL_OPTIONS_SBAT,
GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK,
- GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE
+ GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,
+ GRUB_INSTALL_OPTIONS_DISABLE_CLI
};
extern char *grub_install_source_directory;
@@ -198,7 +201,8 @@ grub_install_generate_image (const char *dir, const char *prefix,
const struct grub_install_image_target_desc *image_target,
int note, size_t appsig_size,
grub_compression_t comp, const char *dtb_file,
- const char *sbat_path, const int disable_shim_lock);
+ const char *sbat_path, const int disable_shim_lock,
+ const int disable_cli);
const struct grub_install_image_target_desc *
grub_install_get_image_target (const char *arg);
diff --git a/util/grub-install-common.c b/util/grub-install-common.c
index 67afc2eed..42aec141e 100644
--- a/util/grub-install-common.c
+++ b/util/grub-install-common.c
@@ -469,6 +469,7 @@ static char **x509keys;
static size_t nx509keys;
static grub_compression_t compression;
static size_t appsig_size;
+static int disable_cli;
int
grub_install_parse (int key, char *arg)
@@ -514,6 +515,9 @@ grub_install_parse (int key, char *arg)
* (nx509keys + 1));
x509keys[nx509keys++] = xstrdup (arg);
return 1;
+ case GRUB_INSTALL_OPTIONS_DISABLE_CLI:
+ disable_cli = 1;
+ return 1;
case GRUB_INSTALL_OPTIONS_VERBOSITY:
verbosity++;
@@ -708,11 +712,13 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
grub_util_info ("grub-mkimage --directory '%s' --prefix '%s' --output '%s'"
" --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" : "",
+ disable_cli ? " --disable-cli" : "", s);
free (s);
tgt = grub_install_get_image_target (mkimage_target);
@@ -725,7 +731,7 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
x509keys, nx509keys,
config_path, tgt,
note, appsig_size, compression, dtb, sbat,
- disable_shim_lock);
+ disable_shim_lock, disable_cli);
while (dc--)
grub_install_pop_module ();
}
diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c
index e1f111278..13bdc6cf0 100644
--- a/util/grub-mkimage.c
+++ b/util/grub-mkimage.c
@@ -84,6 +84,7 @@ static struct argp_option options[] = {
{"compression", 'C', "(xz|none|auto)", 0, N_("choose the compression to use for core image"), 0},
{"sbat", 's', N_("FILE"), 0, N_("SBAT metadata"), 0},
{"disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, N_("disable shim_lock verifier"), 0},
+ {"disable-cli", GRUB_INSTALL_OPTIONS_DISABLE_CLI, 0, 0, N_("disable command line interface access"), 0},
{"verbose", 'v', 0, 0, N_("print verbose messages."), 0},
{"appended-signature-size", 'S', N_("SIZE"), 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), 0},
{ 0, 0, 0, 0, 0, 0 }
@@ -133,6 +134,7 @@ struct arguments
int note;
int disable_shim_lock;
size_t appsig_size;
+ int disable_cli;
const struct grub_install_image_target_desc *image_target;
grub_compression_t comp;
};
@@ -259,6 +261,10 @@ argp_parser (int key, char *arg, struct argp_state *state)
arguments->disable_shim_lock = 1;
break;
+ case GRUB_INSTALL_OPTIONS_DISABLE_CLI:
+ arguments->disable_cli = 1;
+ break;
+
case 'v':
verbosity++;
break;
@@ -347,7 +353,8 @@ main (int argc, char *argv[])
arguments.image_target, arguments.note,
arguments.appsig_size, arguments.comp,
arguments.dtb, arguments.sbat,
- arguments.disable_shim_lock);
+ arguments.disable_shim_lock,
+ arguments.disable_cli);
if (grub_util_file_sync (fp) < 0)
grub_util_error (_("cannot sync `%s': %s"), arguments.output ? : "stdout",
diff --git a/util/mkimage.c b/util/mkimage.c
index 425d920ff..f31fdefa8 100644
--- a/util/mkimage.c
+++ b/util/mkimage.c
@@ -888,7 +888,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
const struct grub_install_image_target_desc *image_target,
int note, size_t appsig_size, grub_compression_t comp,
const char *dtb_path, const char *sbat_path,
- int disable_shim_lock)
+ int disable_shim_lock, int disable_cli)
{
char *kernel_img, *core_img;
size_t total_module_size, core_size;
@@ -963,6 +963,9 @@ grub_install_generate_image (const char *dir, const char *prefix,
if (disable_shim_lock)
total_module_size += sizeof (struct grub_module_header);
+ if (disable_cli)
+ total_module_size += sizeof (struct grub_module_header);
+
if (config_path)
{
config_size = ALIGN_ADDR (grub_util_get_image_size (config_path) + 1);
@@ -1129,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;

View file

@ -0,0 +1,337 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Tue, 11 Feb 2025 15:08:06 -0600
Subject: [PATCH] disk/cryptodisk: Require authentication after TPM unlock for
CLI access
The GRUB may use TPM to verify the integrity of boot components and the
result can determine whether a previously sealed key can be released. If
everything checks out, showing nothing has been tampered with, the key
is released and GRUB unlocks the encrypted root partition for the next
stage of booting.
However, the liberal Command Line Interface (CLI) can be misused by
anyone in this case to access files in the encrypted partition one way
or another. Despite efforts to keep the CLI secure by preventing utility
command output from leaking file content, many techniques in the wild
could still be used to exploit the CLI, enabling attacks or learning
methods to attack. It's nearly impossible to account for all scenarios
where a hack could be applied.
Therefore, to mitigate potential misuse of the CLI after the root device
has been successfully unlocked via TPM, the user should be required to
authenticate using the LUKS password. This added layer of security
ensures that only authorized users can access the CLI reducing the risk
of exploitation or unauthorized access to the encrypted partition.
Fixes: CVE-2024-49504
Signed-off-by: Michael Chang <mchang@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
docs/grub.texi | 29 +++++++++++++++
grub-core/disk/cryptodisk.c | 87 ++++++++++++++++++++++++++++++++++++++++++-
grub-core/kern/main.c | 12 ++++++
grub-core/normal/auth.c | 30 +++++++++++++++
grub-core/normal/main.c | 4 ++
grub-core/normal/menu_entry.c | 4 ++
include/grub/auth.h | 1 +
include/grub/cryptodisk.h | 3 ++
include/grub/misc.h | 2 +
9 files changed, 171 insertions(+), 1 deletion(-)
diff --git a/docs/grub.texi b/docs/grub.texi
index 9ce9c5b82..2d6d73a78 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -6882,6 +6882,35 @@ sign-file SHA256 grub.key certificate.der core.elf.unsigned core.elf.signed
As with UEFI secure boot, it is necessary to build in the required modules,
or sign them separately.
+@subsection Command line and menuentry editor protection
+
+The TPM key protector provides full disk encryption support on servers or
+virtual machine images, meanwhile keeping the boot process unattended. This
+prevents service disruptions by eliminating the need for manual password input
+during startup, improving system uptime and continuity. It is achieved by TPM,
+which verifies the integrity of boot components by checking cryptographic
+hashes against securely stored values, to confirm the disks are unlocked in a
+trusted state.
+
+However, for users to access the system interactively, some form of
+authentication is still required, as the disks are not unlocked by an
+authorized user. This raised concerns about using an unprotected
+@samp{command-line interface} (@pxref{Command-line interface}), as anyone could
+execute commands to access decrypted data. To address this issue, the LUKS
+password is used to ensure that only authorized users are granted access to the
+interface. Additionally, the @samp{menu entry editor} (@pxref{Menu entry
+editor}) is also safeguarded by the LUKS password, as modifying a boot entry is
+effectively the same as altering the @file{grub.cfg} file read from encrypted
+files.
+
+It is worth mentioning that the built-in password support, as described in
+@samp{Authentication and Authorization in GRUB} (@pxref{Authentication and
+authorisation}), can also be used to protect the command-line interface from
+unauthorized access. However, it is not recommended to rely on this approach as
+it is an optional step. Setting it up requires additional manual intervention,
+which increases the risk of password leakage during the process. Moreover, the
+superuser list must be well maintained, and the password used cannot be
+synchronized with LUKS key rotation.
@node Platform limitations
@chapter Platform limitations
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index 98e176a13..06a42b2d7 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -1144,7 +1144,9 @@ grub_cryptodisk_scan_device_real (const char *name,
ret = grub_cryptodisk_insert (dev, name, source);
if (ret != GRUB_ERR_NONE)
goto error;
-
+#ifndef GRUB_UTIL
+ grub_cli_set_auth_needed ();
+#endif
goto cleanup;
}
grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk module can handle this device");
@@ -1576,6 +1578,89 @@ luks_script_get (grub_size_t *sz)
return ret;
}
+#ifdef GRUB_MACHINE_EFI
+grub_err_t
+grub_cryptodisk_challenge_password (void)
+{
+ grub_cryptodisk_t cr_dev;
+
+ for (cr_dev = cryptodisk_list; cr_dev != NULL; cr_dev = cr_dev->next)
+ {
+ grub_cryptodisk_dev_t cr;
+ grub_disk_t source = NULL;
+ grub_err_t ret = GRUB_ERR_NONE;
+ grub_cryptodisk_t dev = NULL;
+ char *part = NULL;
+ struct grub_cryptomount_args cargs = {0};
+
+ cargs.check_boot = 0;
+ cargs.search_uuid = cr_dev->uuid;
+
+ source = grub_disk_open (cr_dev->source);
+
+ if (source == NULL)
+ {
+ ret = grub_errno;
+ goto error_out;
+ }
+
+ FOR_CRYPTODISK_DEVS (cr)
+ {
+ dev = cr->scan (source, &cargs);
+ if (grub_errno)
+ {
+ ret = grub_errno;
+ goto error_out;
+ }
+ if (dev == NULL)
+ continue;
+ break;
+ }
+
+ if (dev == NULL)
+ {
+ ret = grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk module can handle this device");
+ goto error_out;
+ }
+
+ part = grub_partition_get_name (source->partition);
+ grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name,
+ source->partition != NULL ? "," : "",
+ part != NULL ? part : N_("UNKNOWN"), cr_dev->uuid);
+ grub_free (part);
+
+ cargs.key_data = grub_malloc (GRUB_CRYPTODISK_MAX_PASSPHRASE);
+ if (cargs.key_data == NULL)
+ {
+ ret = grub_errno;
+ goto error_out;
+ }
+
+ if (!grub_password_get ((char *) cargs.key_data, GRUB_CRYPTODISK_MAX_PASSPHRASE))
+ {
+ ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "passphrase not supplied");
+ goto error_out;
+ }
+ cargs.key_len = grub_strlen ((char *) cargs.key_data);
+ ret = cr->recover_key (source, dev, &cargs);
+
+ error_out:
+ grub_disk_close (source);
+ if (dev != NULL)
+ cryptodisk_close (dev);
+ if (cargs.key_data)
+ {
+ grub_memset (cargs.key_data, 0, cargs.key_len);
+ grub_free (cargs.key_data);
+ }
+
+ return ret;
+ }
+
+ return GRUB_ERR_NONE;
+}
+#endif /* GRUB_MACHINE_EFI */
+
struct grub_procfs_entry luks_script =
{
.name = "luks_script",
diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c
index 0d6b8138d..2e6b79ee3 100644
--- a/grub-core/kern/main.c
+++ b/grub-core/kern/main.c
@@ -37,6 +37,7 @@
#endif
static bool cli_disabled = false;
+static bool cli_need_auth = false;
grub_addr_t
grub_modules_get_end (void)
@@ -308,6 +309,17 @@ grub_is_cli_disabled (void)
return cli_disabled;
}
+bool
+grub_is_cli_need_auth (void)
+{
+ return cli_need_auth;
+}
+
+void grub_cli_set_auth_needed (void)
+{
+ cli_need_auth = true;
+}
+
static void
check_is_cli_disabled (void)
{
diff --git a/grub-core/normal/auth.c b/grub-core/normal/auth.c
index d94020186..71b361bc0 100644
--- a/grub-core/normal/auth.c
+++ b/grub-core/normal/auth.c
@@ -25,6 +25,10 @@
#include <grub/time.h>
#include <grub/i18n.h>
+#ifdef GRUB_MACHINE_EFI
+#include <grub/cryptodisk.h>
+#endif
+
struct grub_auth_user
{
struct grub_auth_user *next;
@@ -200,6 +204,32 @@ grub_username_get (char buf[], unsigned buf_size)
return (key != GRUB_TERM_ESC);
}
+grub_err_t
+grub_auth_check_cli_access (void)
+{
+ if (grub_is_cli_need_auth () == true)
+ {
+#ifdef GRUB_MACHINE_EFI
+ static bool authenticated = false;
+
+ if (authenticated == false)
+ {
+ grub_err_t ret;
+
+ ret = grub_cryptodisk_challenge_password ();
+ if (ret == GRUB_ERR_NONE)
+ authenticated = true;
+ return ret;
+ }
+ return GRUB_ERR_NONE;
+#else
+ return GRUB_ACCESS_DENIED;
+#endif
+ }
+
+ return GRUB_ERR_NONE;
+}
+
grub_err_t
grub_auth_check_authentication (const char *userlist)
{
diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
index 26872ce94..86ffb388d 100644
--- a/grub-core/normal/main.c
+++ b/grub-core/normal/main.c
@@ -557,9 +557,13 @@ grub_cmdline_run (int nested, int force_auth)
}
while (err && force_auth);
+ if (err == GRUB_ERR_NONE)
+ err = grub_auth_check_cli_access ();
+
if (err)
{
grub_print_error ();
+ grub_wait_after_message ();
grub_errno = GRUB_ERR_NONE;
return;
}
diff --git a/grub-core/normal/menu_entry.c b/grub-core/normal/menu_entry.c
index 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/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/cryptodisk.h b/include/grub/cryptodisk.h
index d94df68b6..d2572f8b0 100644
--- a/include/grub/cryptodisk.h
+++ b/include/grub/cryptodisk.h
@@ -187,4 +187,7 @@ grub_util_get_geli_uuid (const char *dev);
grub_cryptodisk_t grub_cryptodisk_get_by_uuid (const char *uuid);
grub_cryptodisk_t grub_cryptodisk_get_by_source_disk (grub_disk_t disk);
+#ifdef GRUB_MACHINE_EFI
+grub_err_t grub_cryptodisk_challenge_password (void);
+#endif
#endif
diff --git a/include/grub/misc.h b/include/grub/misc.h
index d6e9bae8e..0429339ef 100644
--- a/include/grub/misc.h
+++ b/include/grub/misc.h
@@ -443,6 +443,8 @@ grub_uint64_t EXPORT_FUNC(grub_divmod64) (grub_uint64_t n,
grub_uint64_t *r);
extern bool EXPORT_FUNC(grub_is_cli_disabled) (void);
+extern bool EXPORT_FUNC(grub_is_cli_need_auth) (void);
+extern void EXPORT_FUNC(grub_cli_set_auth_needed) (void);
/* Must match softdiv group in gentpl.py. */
#if !defined(GRUB_MACHINE_EMU) && (defined(__arm__) || defined(__ia64__) || \

View file

@ -0,0 +1,108 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Tue, 11 Feb 2025 15:22:28 -0600
Subject: [PATCH] disk/loopback: Reference tracking for the loopback
It was possible to delete a loopback while there were still references
to it. This led to an exploitable use-after-free.
Fixed by implementing a reference counting in the grub_loopback struct.
Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/disk/loopback.c | 17 +++++++++++++++++
include/grub/err.h | 3 ++-
include/grub/loopback.h | 1 +
3 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/grub-core/disk/loopback.c b/grub-core/disk/loopback.c
index 11a5e0cbd..f39281323 100644
--- a/grub-core/disk/loopback.c
+++ b/grub-core/disk/loopback.c
@@ -25,6 +25,7 @@
#include <grub/mm.h>
#include <grub/extcmd.h>
#include <grub/i18n.h>
+#include <grub/safemath.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -57,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;
@@ -113,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;
@@ -154,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)
@@ -171,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)
@@ -213,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/include/grub/err.h b/include/grub/err.h
index 3c587b9b8..29f1a73c5 100644
--- a/include/grub/err.h
+++ b/include/grub/err.h
@@ -73,7 +73,8 @@ typedef enum
GRUB_ERR_NET_NO_DOMAIN,
GRUB_ERR_EOF,
GRUB_ERR_BAD_SIGNATURE,
- GRUB_ERR_BAD_FIRMWARE
+ GRUB_ERR_BAD_FIRMWARE,
+ GRUB_ERR_STILL_REFERENCED
}
grub_err_t;
diff --git a/include/grub/loopback.h b/include/grub/loopback.h
index 3b9a9e32e..915ef65fc 100644
--- a/include/grub/loopback.h
+++ b/include/grub/loopback.h
@@ -25,6 +25,7 @@ struct grub_loopback
grub_file_t file;
struct grub_loopback *next;
unsigned long id;
+ grub_uint64_t refcnt;
};
#endif /* ! GRUB_LOOPBACK_HEADER */

View file

@ -0,0 +1,120 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Sun, 12 May 2024 04:09:24 +0100
Subject: [PATCH] kern/disk: Limit recursion depth
The grub_disk_read() may trigger other disk reads, e.g. via loopbacks.
This may lead to very deep recursion which can corrupt the heap. So, fix
the issue by limiting reads depth.
Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/kern/disk.c | 27 ++++++++++++++++++++-------
include/grub/err.h | 3 ++-
2 files changed, 22 insertions(+), 8 deletions(-)
diff --git a/grub-core/kern/disk.c b/grub-core/kern/disk.c
index 355b6579d..5747ad85c 100644
--- a/grub-core/kern/disk.c
+++ b/grub-core/kern/disk.c
@@ -28,6 +28,10 @@
#define GRUB_CACHE_TIMEOUT 2
+/* Disk reads may trigger other disk reads. So, limit recursion depth. */
+#define MAX_READ_RECURSION_DEPTH 16
+static unsigned int read_recursion_depth = 0;
+
/* The last time the disk was used. */
static grub_uint64_t grub_last_time = 0;
@@ -421,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, &sector, &offset, size) != GRUB_ERR_NONE)
{
@@ -431,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);
@@ -448,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;
@@ -461,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
@@ -497,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,
@@ -531,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/include/grub/err.h b/include/grub/err.h
index 29f1a73c5..7530f58b2 100644
--- a/include/grub/err.h
+++ b/include/grub/err.h
@@ -74,7 +74,8 @@ typedef enum
GRUB_ERR_EOF,
GRUB_ERR_BAD_SIGNATURE,
GRUB_ERR_BAD_FIRMWARE,
- GRUB_ERR_STILL_REFERENCED
+ GRUB_ERR_STILL_REFERENCED,
+ GRUB_ERR_RECURSION_DEPTH
}
grub_err_t;

View file

@ -0,0 +1,44 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Sat, 16 Nov 2024 21:24:19 +0000
Subject: [PATCH] kern/partition: Limit recursion in part_iterate()
The part_iterate() is used by grub_partition_iterate() as a callback in
the partition iterate functions. However, part_iterate() may also call
the partition iterate functions which may lead to recursion. Fix potential
issue by limiting the recursion depth.
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/kern/partition.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/grub-core/kern/partition.c b/grub-core/kern/partition.c
index edad9f9e4..704512a20 100644
--- a/grub-core/kern/partition.c
+++ b/grub-core/kern/partition.c
@@ -28,6 +28,9 @@
grub_partition_map_t grub_partition_map_list;
+#define MAX_RECURSION_DEPTH 32
+static unsigned int recursion_depth = 0;
+
/*
* Checks that disk->partition contains part. This function assumes that the
* start of part is relative to the start of disk->partition. Returns 1 if
@@ -208,7 +211,12 @@ part_iterate (grub_disk_t dsk, const grub_partition_t partition, void *data)
FOR_PARTITION_MAPS(partmap)
{
grub_err_t err;
- err = partmap->iterate (dsk, part_iterate, ctx);
+ recursion_depth++;
+ if (recursion_depth <= MAX_RECURSION_DEPTH)
+ err = partmap->iterate (dsk, part_iterate, ctx);
+ else
+ err = grub_error (GRUB_ERR_RECURSION_DEPTH, "maximum recursion depth exceeded");
+ recursion_depth--;
if (err)
grub_errno = GRUB_ERR_NONE;
if (ctx->ret)

View file

@ -0,0 +1,55 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Thu, 18 Apr 2024 19:04:13 +0100
Subject: [PATCH] script/execute: Limit the recursion depth
If unbounded recursion is allowed it becomes possible to collide the
stack with the heap. As UEFI firmware often lacks guard pages this
becomes an exploitable issue as it is possible in some cases to do
a controlled overwrite of a section of this heap region with
arbitrary data.
Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/script/execute.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c
index c19b4bf70..7ed3a1a03 100644
--- a/grub-core/script/execute.c
+++ b/grub-core/script/execute.c
@@ -36,10 +36,18 @@
is sizeof (int) * 3, and one extra for a possible -ve sign. */
#define ERRNO_DIGITS_MAX (sizeof (int) * 3 + 1)
+/*
+ * A limit on recursion, to avoid colliding with the heap. UEFI defines a baseline
+ * stack size of 128 KiB. So, assuming at most 1-2 KiB per iteration this should
+ * keep us safe.
+ */
+#define MAX_RECURSION_DEPTH 64
+
static unsigned long is_continue;
static unsigned long active_loops;
static unsigned long active_breaks;
static unsigned long function_return;
+static unsigned long recursion_depth;
#define GRUB_SCRIPT_SCOPE_MALLOCED 1
#define GRUB_SCRIPT_SCOPE_ARGS_MALLOCED 2
@@ -850,7 +858,13 @@ grub_script_execute_cmd (struct grub_script_cmd *cmd)
if (cmd == 0)
return 0;
+ recursion_depth++;
+
+ if (recursion_depth >= MAX_RECURSION_DEPTH)
+ return grub_error (GRUB_ERR_RECURSION_DEPTH, N_("maximum recursion depth exceeded"));
+
ret = cmd->exec (cmd);
+ recursion_depth--;
grub_snprintf (errnobuf, sizeof (errnobuf), "%d", ret);
grub_env_set ("?", errnobuf);

View file

@ -0,0 +1,29 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Tue, 11 Feb 2025 15:27:10 -0600
Subject: [PATCH] net: Unregister net_default_ip and net_default_mac variables
hooks on unload
The net module is a dependency of normal. So, it shouldn't be possible
to unload the net. Though unregister variables hooks as a precaution.
It also gets in line with unregistering the other net module hooks.
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/net/net.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/grub-core/net/net.c b/grub-core/net/net.c
index fdec64d55..9959a2ae8 100644
--- a/grub-core/net/net.c
+++ b/grub-core/net/net.c
@@ -2221,6 +2221,8 @@ GRUB_MOD_FINI(net)
grub_register_variable_hook ("net_default_server", 0, 0);
grub_register_variable_hook ("pxe_default_server", 0, 0);
+ grub_register_variable_hook ("net_default_ip", 0, 0);
+ grub_register_variable_hook ("net_default_mac", 0, 0);
grub_bootp_fini ();
grub_dns_fini ();

View file

@ -0,0 +1,84 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Tue, 11 Feb 2025 15:42:44 -0600
Subject: [PATCH] net: Remove variables hooks when interface is unregisted
The grub_net_network_level_interface_unregister(), previously
implemented in a header, did not remove the variables hooks that
were registered in grub_net_network_level_interface_register().
Fix this by implementing the same logic used to register the
variables and move the function into the grub-core/net/net.c.
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/net/net.c | 33 +++++++++++++++++++++++++++++++++
include/grub/net.h | 11 +----------
2 files changed, 34 insertions(+), 10 deletions(-)
diff --git a/grub-core/net/net.c b/grub-core/net/net.c
index 9959a2ae8..22d5cc3ba 100644
--- a/grub-core/net/net.c
+++ b/grub-core/net/net.c
@@ -1066,6 +1066,39 @@ grub_net_add_ipv6_local (struct grub_net_network_level_interface *inter,
return 0;
}
+void
+grub_net_network_level_interface_unregister (struct grub_net_network_level_interface *inter)
+{
+ char *name;
+
+ {
+ char buf[GRUB_NET_MAX_STR_HWADDR_LEN];
+
+ grub_net_hwaddr_to_str (&inter->hwaddress, buf);
+ name = grub_xasprintf ("net_%s_mac", inter->name);
+ if (name != NULL)
+ grub_register_variable_hook (name, NULL, NULL);
+ grub_free (name);
+ }
+
+ {
+ char buf[GRUB_NET_MAX_STR_ADDR_LEN];
+
+ grub_net_addr_to_str (&inter->address, buf);
+ name = grub_xasprintf ("net_%s_ip", inter->name);
+ if (name != NULL)
+ grub_register_variable_hook (name, NULL, NULL);
+ grub_free (name);
+ }
+
+ inter->card->num_ifaces--;
+ *inter->prev = inter->next;
+ if (inter->next)
+ inter->next->prev = inter->prev;
+ inter->next = 0;
+ inter->prev = 0;
+}
+
grub_err_t
grub_net_add_ipv4_local (struct grub_net_network_level_interface *inter,
int mask)
diff --git a/include/grub/net.h b/include/grub/net.h
index 868c9a2ef..273afbddf 100644
--- a/include/grub/net.h
+++ b/include/grub/net.h
@@ -625,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);

View file

@ -0,0 +1,79 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Tue, 11 Feb 2025 16:38:44 -0600
Subject: [PATCH] net: Fix OOB write in grub_net_search_config_file()
The function included a call to grub_strcpy() which copied data from an
environment variable to a buffer allocated in grub_cmd_normal(). The
grub_cmd_normal() didn't consider the length of the environment variable.
So, the copy operation could exceed the allocation and lead to an OOB
write. Fix the issue by replacing grub_strcpy() with grub_strlcpy() and
pass the underlying buffers size to the grub_net_search_config_file().
Fixes: CVE-2025-0624
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/net/net.c | 7 ++++---
grub-core/normal/main.c | 2 +-
include/grub/net.h | 2 +-
3 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/grub-core/net/net.c b/grub-core/net/net.c
index 22d5cc3ba..6c8dfcba2 100644
--- a/grub-core/net/net.c
+++ b/grub-core/net/net.c
@@ -2023,14 +2023,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)
@@ -2056,7 +2057,7 @@ grub_net_search_config_file (char *config)
if (client_uuid)
{
- grub_strcpy (suffix, client_uuid);
+ grub_strlcpy (suffix, client_uuid, suffix_len);
if (grub_config_search_through (config, suffix, 1, 0) == 0)
return GRUB_ERR_NONE;
}
diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
index 86ffb388d..cad840e06 100644
--- a/grub-core/normal/main.c
+++ b/grub-core/normal/main.c
@@ -360,7 +360,7 @@ grub_try_normal_prefix (const char *prefix)
return err;
grub_snprintf (config, config_len, "%s/grub.cfg", prefix);
- err = grub_net_search_config_file (config);
+ err = grub_net_search_config_file (config, config_len);
}
if (err != GRUB_ERR_NONE)
diff --git a/include/grub/net.h b/include/grub/net.h
index 273afbddf..d280acd72 100644
--- a/include/grub/net.h
+++ b/include/grub/net.h
@@ -655,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;

View file

@ -0,0 +1,115 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Thu, 18 Apr 2024 17:32:34 +0100
Subject: [PATCH] net/tftp: Fix stack buffer overflow in tftp_open()
An overly long filename can be passed to tftp_open() which would cause
grub_normalize_filename() to write out of bounds.
Fixed by adding an extra argument to grub_normalize_filename() for the
space available, making it act closer to a strlcpy(). As several fixed
strings are strcpy()'d after into the same buffer, their total length is
checked to see if they exceed the remaining space in the buffer. If so,
return an error.
On the occasion simplify code a bit by removing unneeded rrqlen zeroing.
Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/net/tftp.c | 38 ++++++++++++++++++++++++--------------
1 file changed, 24 insertions(+), 14 deletions(-)
diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c
index f300a9d40..3d96e50f4 100644
--- a/grub-core/net/tftp.c
+++ b/grub-core/net/tftp.c
@@ -266,17 +266,19 @@ tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)),
* forward slashes to a single forward slash.
*/
static void
-grub_normalize_filename (char *normalized, const char *filename)
+grub_normalize_filename (char *normalized, const char *filename, int c)
{
char *dest = normalized;
const char *src = filename;
- while (*src != '\0')
+ while (*src != '\0' && c > 0)
{
if (src[0] == '/' && src[1] == '/')
src++;
- else
+ else {
+ c--;
*dest++ = *src++;
+ }
}
*dest = '\0';
}
@@ -287,7 +289,7 @@ tftp_open (struct grub_file *file, const char *filename)
struct tftphdr *tftph;
char *rrq;
int i;
- int rrqlen;
+ int rrqlen, rrqsize;
int hdrlen;
grub_uint8_t open_data[1500];
struct grub_net_buff nb;
@@ -315,37 +317,45 @@ tftp_open (struct grub_file *file, const char *filename)
tftph = (struct tftphdr *) nb.data;
- rrq = (char *) tftph->u.rrq;
- rrqlen = 0;
-
tftph->opcode = grub_cpu_to_be16_compile_time (TFTP_RRQ);
+ rrq = (char *) tftph->u.rrq;
+ rrqsize = sizeof (tftph->u.rrq);
+
/*
* Copy and normalize the filename to work-around issues on some TFTP
* servers when file names are being matched for remapping.
*/
- grub_normalize_filename (rrq, filename);
- rrqlen += grub_strlen (rrq) + 1;
+ grub_normalize_filename (rrq, filename, rrqsize);
+
+ rrqlen = grub_strlen (rrq) + 1;
rrq += grub_strlen (rrq) + 1;
- grub_strcpy (rrq, "octet");
+ /* Verify there is enough space for the remaining components. */
rrqlen += grub_strlen ("octet") + 1;
+ rrqlen += grub_strlen ("blksize") + 1;
+ rrqlen += grub_strlen ("1024") + 1;
+ rrqlen += grub_strlen ("tsize") + 1;
+ rrqlen += grub_strlen ("0") + 1;
+
+ if (rrqlen >= rrqsize) {
+ grub_free (data);
+ return grub_error (GRUB_ERR_BAD_FILENAME, N_("filename too long"));
+ }
+
+ grub_strcpy (rrq, "octet");
rrq += grub_strlen ("octet") + 1;
grub_strcpy (rrq, "blksize");
- rrqlen += grub_strlen ("blksize") + 1;
rrq += grub_strlen ("blksize") + 1;
grub_strcpy (rrq, "1024");
- rrqlen += grub_strlen ("1024") + 1;
rrq += grub_strlen ("1024") + 1;
grub_strcpy (rrq, "tsize");
- rrqlen += grub_strlen ("tsize") + 1;
rrq += grub_strlen ("tsize") + 1;
grub_strcpy (rrq, "0");
- rrqlen += grub_strlen ("0") + 1;
rrq += grub_strlen ("0") + 1;
hdrlen = sizeof (tftph->opcode) + rrqlen;

View file

@ -0,0 +1,33 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Fri, 8 Mar 2024 22:47:20 +1100
Subject: [PATCH] video/readers/jpeg: Do not permit duplicate SOF0 markers in
JPEG
Otherwise a subsequent header could change the height and width
allowing future OOB writes.
Fixes: CVE-2024-45774
Reported-by: Nils Langius <nils@langius.de>
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/video/readers/jpeg.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c
index 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");

View file

@ -0,0 +1,138 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Tue, 11 Feb 2025 16:41:57 -0600
Subject: [PATCH] kern/dl: Fix for an integer overflow in grub_dl_ref()
It was possible to overflow the value of mod->ref_count, a signed
integer, by repeatedly invoking insmod on an already loaded module.
This led to a use-after-free. As once ref_count was overflowed it became
possible to unload the module while there was still references to it.
This resolves the issue by using grub_add() to check if the ref_count
will overflow and then stops further increments. Further changes were
also made to grub_dl_unref() to check for the underflow condition and
the reference count was changed to an unsigned 64-bit integer.
Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/commands/minicmd.c | 2 +-
grub-core/kern/dl.c | 17 ++++++++++++-----
include/grub/dl.h | 8 ++++----
util/misc.c | 4 ++--
4 files changed, 19 insertions(+), 12 deletions(-)
diff --git a/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c
index 2bd3ac76f..2001043cf 100644
--- a/grub-core/commands/minicmd.c
+++ b/grub-core/commands/minicmd.c
@@ -167,7 +167,7 @@ grub_mini_cmd_lsmod (struct grub_command *cmd __attribute__ ((unused)),
{
grub_dl_dep_t dep;
- grub_printf ("%s\t%d\t\t", mod->name, mod->ref_count);
+ grub_printf ("%s\t%" PRIuGRUB_UINT64_T "\t\t", mod->name, mod->ref_count);
for (dep = mod->dep; dep; dep = dep->next)
{
if (dep != mod->dep)
diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
index 2eaef7150..fe7c3b940 100644
--- a/grub-core/kern/dl.c
+++ b/grub-core/kern/dl.c
@@ -32,6 +32,7 @@
#include <grub/env.h>
#include <grub/cache.h>
#include <grub/i18n.h>
+#include <grub/safemath.h>
#include <grub/efi/sb.h>
/* Platforms where modules are in a readonly area of memory. */
@@ -613,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;
@@ -624,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;
@@ -638,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)
diff --git a/include/grub/dl.h b/include/grub/dl.h
index 1e1262a28..055bb564e 100644
--- a/include/grub/dl.h
+++ b/include/grub/dl.h
@@ -177,7 +177,7 @@ typedef struct grub_dl_dep *grub_dl_dep_t;
struct grub_dl
{
char *name;
- int ref_count;
+ grub_uint64_t ref_count;
int persistent;
grub_dl_dep_t dep;
grub_dl_segment_t segment;
@@ -206,9 +206,9 @@ grub_dl_t EXPORT_FUNC(grub_dl_load) (const char *name);
grub_dl_t grub_dl_load_core (void *addr, grub_size_t size);
grub_dl_t EXPORT_FUNC(grub_dl_load_core_noinit) (void *addr, grub_size_t size);
int EXPORT_FUNC(grub_dl_unload) (grub_dl_t mod);
-extern int EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod);
-extern int EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod);
-extern int EXPORT_FUNC(grub_dl_ref_count) (grub_dl_t mod);
+extern grub_uint64_t EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod);
+extern grub_uint64_t EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod);
+extern grub_uint64_t EXPORT_FUNC(grub_dl_ref_count) (grub_dl_t mod);
extern grub_dl_t EXPORT_VAR(grub_dl_head);
diff --git a/util/misc.c b/util/misc.c
index d545212d9..0f928e5b4 100644
--- a/util/misc.c
+++ b/util/misc.c
@@ -190,14 +190,14 @@ grub_xputs_real (const char *str)
void (*grub_xputs) (const char *str) = grub_xputs_real;
-int
+grub_uint64_t
grub_dl_ref (grub_dl_t mod)
{
(void) mod;
return 0;
}
-int
+grub_uint64_t
grub_dl_unref (grub_dl_t mod)
{
(void) mod;

View file

@ -0,0 +1,34 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Tue, 11 Feb 2025 17:01:26 -0600
Subject: [PATCH] kern/dl: Check for the SHF_INFO_LINK flag in
grub_dl_relocate_symbols()
The grub_dl_relocate_symbols() iterates through the sections in
an ELF looking for relocation sections. According to the spec [1]
the SHF_INFO_LINK flag should be set if the sh_info field is meant
to be a section index.
[1] https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html
Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/kern/dl.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
index fe7c3b940..cb49bdc4b 100644
--- a/grub-core/kern/dl.c
+++ b/grub-core/kern/dl.c
@@ -681,6 +681,9 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
grub_dl_segment_t seg;
grub_err_t err;
+ if (!(s->sh_flags & SHF_INFO_LINK))
+ continue;
+
seg = grub_dl_find_segment(mod, s->sh_info);
if (!seg)
continue;

View file

@ -0,0 +1,34 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lidong Chen <lidong.chen@oracle.com>
Date: Fri, 22 Nov 2024 06:27:55 +0000
Subject: [PATCH] commands/extcmd: Missing check for failed allocation
The grub_extcmd_dispatcher() calls grub_arg_list_alloc() to allocate
a grub_arg_list struct but it does not verify the allocation was successful.
In case of failed allocation the NULL state pointer can be accessed in
parse_option() through grub_arg_parse() which may lead to a security issue.
Fixes: CVE-2024-45775
Reported-by: Nils Langius <nils@langius.de>
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Reviewed-by: Alec Brown <alec.r.brown@oracle.com>
---
grub-core/commands/extcmd.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/grub-core/commands/extcmd.c b/grub-core/commands/extcmd.c
index 90a5ca24a..c236be13a 100644
--- a/grub-core/commands/extcmd.c
+++ b/grub-core/commands/extcmd.c
@@ -49,6 +49,9 @@ grub_extcmd_dispatcher (struct grub_command *cmd, int argc, char **args,
}
state = grub_arg_list_alloc (ext, argc, args);
+ if (state == NULL)
+ return grub_errno;
+
if (grub_arg_parse (ext, argc, args, state, &new_args, &new_argc))
{
context.state = state;

View file

@ -0,0 +1,32 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Sun, 12 May 2024 11:08:23 +0100
Subject: [PATCH] commands/ls: Fix NULL dereference
The grub_strrchr() may return NULL when the dirname do not contain "/".
This can happen on broken filesystems.
Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/commands/ls.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/grub-core/commands/ls.c b/grub-core/commands/ls.c
index 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;

View file

@ -0,0 +1,31 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Fri, 1 Nov 2024 19:24:29 +0000
Subject: [PATCH] commands/pgp: Unregister the "check_signatures" hooks on
module unload
If the hooks are not removed they can be called after the module has
been unloaded leading to an use-after-free.
Fixes: CVE-2025-0622
Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/commands/pgp.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c
index 847a5046a..fa3ef5c75 100644
--- a/grub-core/commands/pgp.c
+++ b/grub-core/commands/pgp.c
@@ -982,6 +982,8 @@ GRUB_MOD_INIT(pgp)
GRUB_MOD_FINI(pgp)
{
+ grub_register_variable_hook ("check_signatures", NULL, NULL);
+ grub_env_unset ("check_signatures");
grub_verifier_unregister (&grub_pubkey_verifier);
grub_unregister_extcmd (cmd);
grub_unregister_extcmd (cmd_trust);

View file

@ -0,0 +1,37 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Fri, 1 Nov 2024 23:46:55 +0000
Subject: [PATCH] normal: Remove variables hooks on module unload
The normal module does not entirely cleanup after itself in
its GRUB_MOD_FINI() leaving a few variables hooks in place.
It is not possible to unload normal module now but fix the
issues for completeness.
On the occasion replace 0s with NULLs for "pager" variable
hooks unregister.
Fixes: CVE-2025-0622
Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/normal/main.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
index cad840e06..dd20e5129 100644
--- a/grub-core/normal/main.c
+++ b/grub-core/normal/main.c
@@ -690,7 +690,9 @@ GRUB_MOD_FINI(normal)
grub_xputs = grub_xputs_saved;
grub_set_history (0);
- grub_register_variable_hook ("pager", 0, 0);
+ grub_register_variable_hook ("pager", NULL, NULL);
+ grub_register_variable_hook ("color_normal", NULL, NULL);
+ grub_register_variable_hook ("color_highlight", NULL, NULL);
grub_fs_autoload_hook = 0;
grub_unregister_command (cmd_clear);
}

View file

@ -0,0 +1,34 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Fri, 1 Nov 2024 23:52:06 +0000
Subject: [PATCH] gettext: Remove variables hooks on module unload
The gettext module does not entirely cleanup after itself in
its GRUB_MOD_FINI() leaving a few variables hooks in place.
It is not possible to unload gettext module because normal
module depends on it. Though fix the issues for completeness.
Fixes: CVE-2025-0622
Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/gettext/gettext.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/grub-core/gettext/gettext.c b/grub-core/gettext/gettext.c
index 631af7a94..465143cb6 100644
--- a/grub-core/gettext/gettext.c
+++ b/grub-core/gettext/gettext.c
@@ -542,6 +542,10 @@ GRUB_MOD_INIT (gettext)
GRUB_MOD_FINI (gettext)
{
+ grub_register_variable_hook ("locale_dir", NULL, NULL);
+ grub_register_variable_hook ("secondary_locale_dir", NULL, NULL);
+ grub_register_variable_hook ("lang", NULL, NULL);
+
grub_gettext_delete_list (&main_context);
grub_gettext_delete_list (&secondary_context);

View file

@ -0,0 +1,35 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lidong Chen <lidong.chen@oracle.com>
Date: Fri, 22 Nov 2024 06:27:56 +0000
Subject: [PATCH] gettext: Integer overflow leads to heap OOB write or read
Calculation of ctx->grub_gettext_msg_list size in grub_mofile_open() may
overflow leading to subsequent OOB write or read. This patch fixes the
issue by replacing grub_zalloc() and explicit multiplication with
grub_calloc() which does the same thing in safe manner.
Fixes: CVE-2024-45776
Reported-by: Nils Langius <nils@langius.de>
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Reviewed-by: Alec Brown <alec.r.brown@oracle.com>
---
grub-core/gettext/gettext.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/grub-core/gettext/gettext.c b/grub-core/gettext/gettext.c
index 465143cb6..c17040269 100644
--- a/grub-core/gettext/gettext.c
+++ b/grub-core/gettext/gettext.c
@@ -323,8 +323,8 @@ grub_mofile_open (struct grub_gettext_context *ctx,
for (ctx->grub_gettext_max_log = 0; ctx->grub_gettext_max >> ctx->grub_gettext_max_log;
ctx->grub_gettext_max_log++);
- ctx->grub_gettext_msg_list = grub_zalloc (ctx->grub_gettext_max
- * sizeof (ctx->grub_gettext_msg_list[0]));
+ ctx->grub_gettext_msg_list = grub_calloc (ctx->grub_gettext_max,
+ sizeof (ctx->grub_gettext_msg_list[0]));
if (!ctx->grub_gettext_msg_list)
{
grub_file_close (fd);

View file

@ -0,0 +1,53 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lidong Chen <lidong.chen@oracle.com>
Date: Fri, 22 Nov 2024 06:27:57 +0000
Subject: [PATCH] gettext: Integer overflow leads to heap OOB write
The size calculation of the translation buffer in
grub_gettext_getstr_from_position() may overflow
to 0 leading to heap OOB write. This patch fixes
the issue by using grub_add() and checking for
an overflow.
Fixes: CVE-2024-45777
Reported-by: Nils Langius <nils@langius.de>
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Reviewed-by: Alec Brown <alec.r.brown@oracle.com>
---
grub-core/gettext/gettext.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/grub-core/gettext/gettext.c b/grub-core/gettext/gettext.c
index c17040269..fffe3a054 100644
--- a/grub-core/gettext/gettext.c
+++ b/grub-core/gettext/gettext.c
@@ -26,6 +26,7 @@
#include <grub/file.h>
#include <grub/kernel.h>
#include <grub/i18n.h>
+#include <grub/safemath.h>
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;

View file

@ -0,0 +1,69 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jonathan Bar Or <jonathanbaror@gmail.com>
Date: Thu, 23 Jan 2025 19:17:05 +0100
Subject: [PATCH] commands/read: Fix an integer overflow when supplying more
than 2^31 characters
The grub_getline() function currently has a signed integer variable "i"
that can be overflown when user supplies more than 2^31 characters.
It results in a memory corruption of the allocated line buffer as well
as supplying large negative values to grub_realloc().
Fixes: CVE-2025-0690
Reported-by: Jonathan Bar Or <jonathanbaror@gmail.com>
Signed-off-by: Jonathan Bar Or <jonathanbaror@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/commands/read.c | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/grub-core/commands/read.c b/grub-core/commands/read.c
index 597c90706..8d72e45c9 100644
--- a/grub-core/commands/read.c
+++ b/grub-core/commands/read.c
@@ -25,6 +25,7 @@
#include <grub/types.h>
#include <grub/extcmd.h>
#include <grub/i18n.h>
+#include <grub/safemath.h>
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);

View file

@ -0,0 +1,83 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lidong Chen <lidong.chen@oracle.com>
Date: Mon, 16 Dec 2024 20:22:41 +0000
Subject: [PATCH] commands/test: Stack overflow due to unlimited recursion
depth
The test_parse() evaluates test expression recursively. Due to lack of
recursion depth check a specially crafted expression may cause a stack
overflow. The recursion is only triggered by the parentheses usage and
it can be unlimited. However, sensible expressions are unlikely to
contain more than a few parentheses. So, this patch limits the recursion
depth to 100, which should be sufficient.
Reported-by: Nils Langius <nils@langius.de>
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/commands/test.c | 21 ++++++++++++++++++---
1 file changed, 18 insertions(+), 3 deletions(-)
diff --git a/grub-core/commands/test.c b/grub-core/commands/test.c
index 62d3fb398..b585c3d70 100644
--- a/grub-core/commands/test.c
+++ b/grub-core/commands/test.c
@@ -29,6 +29,9 @@
GRUB_MOD_LICENSE ("GPLv3+");
+/* Set a limit on recursion to avoid stack overflow. */
+#define MAX_TEST_RECURSION_DEPTH 100
+
/* A simple implementation for signed numbers. */
static int
grub_strtosl (char *arg, const char ** const end, int base)
@@ -150,7 +153,7 @@ get_fileinfo (char *path, struct test_parse_ctx *ctx)
/* Parse a test expression starting from *argn. */
static int
-test_parse (char **args, int *argn, int argc)
+test_parse (char **args, int *argn, int argc, int *depth)
{
struct test_parse_ctx ctx = {
.and = 1,
@@ -387,13 +390,24 @@ test_parse (char **args, int *argn, int argc)
if (grub_strcmp (args[*argn], ")") == 0)
{
(*argn)++;
+ if (*depth > 0)
+ (*depth)--;
+
return ctx.or || ctx.and;
}
/* Recursively invoke if parenthesis. */
if (grub_strcmp (args[*argn], "(") == 0)
{
(*argn)++;
- update_val (test_parse (args, argn, argc), &ctx);
+
+ if (++(*depth) > MAX_TEST_RECURSION_DEPTH)
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("max recursion depth exceeded"));
+ depth--;
+ return ctx.or || ctx.and;
+ }
+
+ update_val (test_parse (args, argn, argc, depth), &ctx);
continue;
}
@@ -428,11 +442,12 @@ grub_cmd_test (grub_command_t cmd __attribute__ ((unused)),
int argc, char **args)
{
int argn = 0;
+ int depth = 0;
if (argc >= 1 && grub_strcmp (args[argc - 1], "]") == 0)
argc--;
- return test_parse (args, &argn, argc) ? GRUB_ERR_NONE
+ return test_parse (args, &argn, argc, &depth) ? GRUB_ERR_NONE
: grub_error (GRUB_ERR_TEST_FAILURE, N_("false"));
}

View file

@ -0,0 +1,33 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Thu, 18 Apr 2024 20:29:39 +0100
Subject: [PATCH] commands/minicmd: Block the dump command in lockdown mode
The dump enables a user to read memory which should not be possible
in lockdown mode.
Fixes: CVE-2025-1118
Reported-by: B Horn <b@horn.uk>
Reported-by: Jonathan Bar Or <jonathanbaror@gmail.com>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/commands/minicmd.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c
index 2001043cf..9efb7718c 100644
--- a/grub-core/commands/minicmd.c
+++ b/grub-core/commands/minicmd.c
@@ -215,8 +215,8 @@ GRUB_MOD_INIT(minicmd)
grub_register_command ("help", grub_mini_cmd_help,
0, N_("Show this message."));
cmd_dump =
- grub_register_command ("dump", grub_mini_cmd_dump,
- N_("ADDR [SIZE]"), N_("Show memory contents."));
+ grub_register_command_lockdown ("dump", grub_mini_cmd_dump,
+ N_("ADDR [SIZE]"), N_("Show memory contents."));
cmd_rmmod =
grub_register_command ("rmmod", grub_mini_cmd_rmmod,
N_("MODULE"), N_("Remove a module."));

View file

@ -0,0 +1,50 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Tue, 11 Feb 2025 17:12:29 -0600
Subject: [PATCH] commands/memrw: Disable memory reading in lockdown mode
With the rest of module being blocked in lockdown mode it does not make
a lot of sense to leave memory reading enabled. This also goes in par
with disabling the dump command.
Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/commands/memrw.c | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/grub-core/commands/memrw.c b/grub-core/commands/memrw.c
index 39cf3a06d..9d8a54a4b 100644
--- a/grub-core/commands/memrw.c
+++ b/grub-core/commands/memrw.c
@@ -126,17 +126,20 @@ GRUB_MOD_INIT(memrw)
return;
cmd_read_byte =
- grub_register_extcmd ("read_byte", grub_cmd_read, 0,
- N_("ADDR"), N_("Read 8-bit value from ADDR."),
- options);
+ grub_register_extcmd_lockdown ("read_byte", grub_cmd_read, 0,
+ N_("ADDR"),
+ N_("Read 8-bit value from ADDR."),
+ options);
cmd_read_word =
- grub_register_extcmd ("read_word", grub_cmd_read, 0,
- N_("ADDR"), N_("Read 16-bit value from ADDR."),
- options);
+ grub_register_extcmd_lockdown ("read_word", grub_cmd_read, 0,
+ N_("ADDR"),
+ N_("Read 16-bit value from ADDR."),
+ options);
cmd_read_dword =
- grub_register_extcmd ("read_dword", grub_cmd_read, 0,
- N_("ADDR"), N_("Read 32-bit value from ADDR."),
- options);
+ grub_register_extcmd_lockdown ("read_dword", grub_cmd_read, 0,
+ N_("ADDR"),
+ N_("Read 32-bit value from ADDR."),
+ options);
cmd_write_byte =
grub_register_command_lockdown ("write_byte", grub_cmd_write,
N_("ADDR VALUE [MASK]"),

View file

@ -0,0 +1,37 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Fri, 19 Apr 2024 22:31:45 +0100
Subject: [PATCH] commands/hexdump: Disable memory reading in lockdown mode
Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/commands/hexdump.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/grub-core/commands/hexdump.c b/grub-core/commands/hexdump.c
index eaa12465b..d6f61d98a 100644
--- a/grub-core/commands/hexdump.c
+++ b/grub-core/commands/hexdump.c
@@ -24,6 +24,7 @@
#include <grub/lib/hexdump.h>
#include <grub/extcmd.h>
#include <grub/i18n.h>
+#include <grub/lockdown.h>
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;

View file

@ -0,0 +1,52 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Sat, 23 Mar 2024 15:59:43 +1100
Subject: [PATCH] fs/bfs: Disable under lockdown
The BFS is not fuzz-clean. Don't allow it to be loaded under lockdown.
This will also disable the AFS.
Fixes: CVE-2024-45778
Fixes: CVE-2024-45779
Reported-by: Nils Langius <nils@langius.de>
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/bfs.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/grub-core/fs/bfs.c b/grub-core/fs/bfs.c
index f37b16895..c92fd7916 100644
--- a/grub-core/fs/bfs.c
+++ b/grub-core/fs/bfs.c
@@ -30,6 +30,7 @@
#include <grub/types.h>
#include <grub/i18n.h>
#include <grub/fshelp.h>
+#include <grub/lockdown.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -1106,8 +1107,11 @@ GRUB_MOD_INIT (bfs)
{
COMPILE_TIME_ASSERT (1 << LOG_EXTENT_SIZE ==
sizeof (struct grub_bfs_extent));
- grub_bfs_fs.mod = mod;
- grub_fs_register (&grub_bfs_fs);
+ if (!grub_is_lockdown ())
+ {
+ grub_bfs_fs.mod = mod;
+ grub_fs_register (&grub_bfs_fs);
+ }
}
#ifdef MODE_AFS
@@ -1116,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);
}

View file

@ -0,0 +1,391 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Sat, 23 Mar 2024 16:20:45 +1100
Subject: [PATCH] fs: Disable many filesystems under lockdown
The idea is to permit the following: btrfs, cpio, exfat, ext, f2fs, fat,
hfsplus, iso9660, squash4, tar, xfs and zfs.
The JFS, ReiserFS, romfs, UDF and UFS security vulnerabilities were
reported by Jonathan Bar Or <jonathanbaror@gmail.com>.
Fixes: CVE-2025-0677
Fixes: CVE-2025-0684
Fixes: CVE-2025-0685
Fixes: CVE-2025-0686
Fixes: CVE-2025-0689
Suggested-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/affs.c | 11 ++++++++---
grub-core/fs/cbfs.c | 11 ++++++++---
grub-core/fs/jfs.c | 11 ++++++++---
grub-core/fs/minix.c | 11 ++++++++---
grub-core/fs/nilfs2.c | 11 ++++++++---
grub-core/fs/ntfs.c | 11 ++++++++---
grub-core/fs/reiserfs.c | 11 ++++++++---
grub-core/fs/romfs.c | 11 ++++++++---
grub-core/fs/sfs.c | 11 ++++++++---
grub-core/fs/udf.c | 11 ++++++++---
grub-core/fs/ufs.c | 11 ++++++++---
11 files changed, 88 insertions(+), 33 deletions(-)
diff --git a/grub-core/fs/affs.c b/grub-core/fs/affs.c
index 9b0afb954..520a001c7 100644
--- a/grub-core/fs/affs.c
+++ b/grub-core/fs/affs.c
@@ -26,6 +26,7 @@
#include <grub/types.h>
#include <grub/fshelp.h>
#include <grub/charset.h>
+#include <grub/lockdown.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -703,12 +704,16 @@ static struct grub_fs grub_affs_fs =
GRUB_MOD_INIT(affs)
{
- grub_affs_fs.mod = mod;
- grub_fs_register (&grub_affs_fs);
+ if (!grub_is_lockdown ())
+ {
+ grub_affs_fs.mod = mod;
+ grub_fs_register (&grub_affs_fs);
+ }
my_mod = mod;
}
GRUB_MOD_FINI(affs)
{
- grub_fs_unregister (&grub_affs_fs);
+ if (!grub_is_lockdown ())
+ grub_fs_unregister (&grub_affs_fs);
}
diff --git a/grub-core/fs/cbfs.c b/grub-core/fs/cbfs.c
index 2332745fe..b62c8777c 100644
--- a/grub-core/fs/cbfs.c
+++ b/grub-core/fs/cbfs.c
@@ -26,6 +26,7 @@
#include <grub/dl.h>
#include <grub/i18n.h>
#include <grub/cbfs_core.h>
+#include <grub/lockdown.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -390,13 +391,17 @@ GRUB_MOD_INIT (cbfs)
#if (defined (__i386__) || defined (__x86_64__)) && !defined (GRUB_UTIL) && !defined (GRUB_MACHINE_EMU) && !defined (GRUB_MACHINE_XEN)
init_cbfsdisk ();
#endif
- grub_cbfs_fs.mod = mod;
- grub_fs_register (&grub_cbfs_fs);
+ if (!grub_is_lockdown ())
+ {
+ grub_cbfs_fs.mod = mod;
+ grub_fs_register (&grub_cbfs_fs);
+ }
}
GRUB_MOD_FINI (cbfs)
{
- grub_fs_unregister (&grub_cbfs_fs);
+ if (!grub_is_lockdown ())
+ grub_fs_unregister (&grub_cbfs_fs);
#if (defined (__i386__) || defined (__x86_64__)) && !defined (GRUB_UTIL) && !defined (GRUB_MACHINE_EMU) && !defined (GRUB_MACHINE_XEN)
fini_cbfsdisk ();
#endif
diff --git a/grub-core/fs/jfs.c b/grub-core/fs/jfs.c
index b0283ac00..ab175c7f1 100644
--- a/grub-core/fs/jfs.c
+++ b/grub-core/fs/jfs.c
@@ -26,6 +26,7 @@
#include <grub/types.h>
#include <grub/charset.h>
#include <grub/i18n.h>
+#include <grub/lockdown.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -1005,12 +1006,16 @@ static struct grub_fs grub_jfs_fs =
GRUB_MOD_INIT(jfs)
{
- grub_jfs_fs.mod = mod;
- grub_fs_register (&grub_jfs_fs);
+ if (!grub_is_lockdown ())
+ {
+ grub_jfs_fs.mod = mod;
+ grub_fs_register (&grub_jfs_fs);
+ }
my_mod = mod;
}
GRUB_MOD_FINI(jfs)
{
- grub_fs_unregister (&grub_jfs_fs);
+ if (!grub_is_lockdown ())
+ grub_fs_unregister (&grub_jfs_fs);
}
diff --git a/grub-core/fs/minix.c b/grub-core/fs/minix.c
index b7679c3e2..4440fcca8 100644
--- a/grub-core/fs/minix.c
+++ b/grub-core/fs/minix.c
@@ -25,6 +25,7 @@
#include <grub/dl.h>
#include <grub/types.h>
#include <grub/i18n.h>
+#include <grub/lockdown.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -734,8 +735,11 @@ GRUB_MOD_INIT(minix)
#endif
#endif
{
- grub_minix_fs.mod = mod;
- grub_fs_register (&grub_minix_fs);
+ if (!grub_is_lockdown ())
+ {
+ grub_minix_fs.mod = mod;
+ grub_fs_register (&grub_minix_fs);
+ }
my_mod = mod;
}
@@ -757,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/nilfs2.c b/grub-core/fs/nilfs2.c
index 4e1e71738..26e6077ff 100644
--- a/grub-core/fs/nilfs2.c
+++ b/grub-core/fs/nilfs2.c
@@ -34,6 +34,7 @@
#include <grub/dl.h>
#include <grub/types.h>
#include <grub/fshelp.h>
+#include <grub/lockdown.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -1231,12 +1232,16 @@ GRUB_MOD_INIT (nilfs2)
grub_nilfs2_dat_entry));
COMPILE_TIME_ASSERT (1 << LOG_INODE_SIZE
== sizeof (struct grub_nilfs2_inode));
- grub_nilfs2_fs.mod = mod;
- grub_fs_register (&grub_nilfs2_fs);
+ if (!grub_is_lockdown ())
+ {
+ grub_nilfs2_fs.mod = mod;
+ grub_fs_register (&grub_nilfs2_fs);
+ }
my_mod = mod;
}
GRUB_MOD_FINI (nilfs2)
{
- grub_fs_unregister (&grub_nilfs2_fs);
+ if (!grub_is_lockdown ())
+ grub_fs_unregister (&grub_nilfs2_fs);
}
diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c
index 4e144cc3c..e00349b1d 100644
--- a/grub-core/fs/ntfs.c
+++ b/grub-core/fs/ntfs.c
@@ -27,6 +27,7 @@
#include <grub/fshelp.h>
#include <grub/ntfs.h>
#include <grub/charset.h>
+#include <grub/lockdown.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -1541,12 +1542,16 @@ static struct grub_fs grub_ntfs_fs =
GRUB_MOD_INIT (ntfs)
{
- grub_ntfs_fs.mod = mod;
- grub_fs_register (&grub_ntfs_fs);
+ if (!grub_is_lockdown ())
+ {
+ grub_ntfs_fs.mod = mod;
+ grub_fs_register (&grub_ntfs_fs);
+ }
my_mod = mod;
}
GRUB_MOD_FINI (ntfs)
{
- grub_fs_unregister (&grub_ntfs_fs);
+ if (!grub_is_lockdown ())
+ grub_fs_unregister (&grub_ntfs_fs);
}
diff --git a/grub-core/fs/reiserfs.c b/grub-core/fs/reiserfs.c
index e8b0b6383..ca47e0a43 100644
--- a/grub-core/fs/reiserfs.c
+++ b/grub-core/fs/reiserfs.c
@@ -39,6 +39,7 @@
#include <grub/types.h>
#include <grub/fshelp.h>
#include <grub/i18n.h>
+#include <grub/lockdown.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -1407,12 +1408,16 @@ static struct grub_fs grub_reiserfs_fs =
GRUB_MOD_INIT(reiserfs)
{
- grub_reiserfs_fs.mod = mod;
- grub_fs_register (&grub_reiserfs_fs);
+ if (!grub_is_lockdown ())
+ {
+ grub_reiserfs_fs.mod = mod;
+ grub_fs_register (&grub_reiserfs_fs);
+ }
my_mod = mod;
}
GRUB_MOD_FINI(reiserfs)
{
- grub_fs_unregister (&grub_reiserfs_fs);
+ if (!grub_is_lockdown ())
+ grub_fs_unregister (&grub_reiserfs_fs);
}
diff --git a/grub-core/fs/romfs.c b/grub-core/fs/romfs.c
index 56b0b2b2f..eafab03b2 100644
--- a/grub-core/fs/romfs.c
+++ b/grub-core/fs/romfs.c
@@ -23,6 +23,7 @@
#include <grub/disk.h>
#include <grub/fs.h>
#include <grub/fshelp.h>
+#include <grub/lockdown.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -475,11 +476,15 @@ static struct grub_fs grub_romfs_fs =
GRUB_MOD_INIT(romfs)
{
- grub_romfs_fs.mod = mod;
- grub_fs_register (&grub_romfs_fs);
+ if (!grub_is_lockdown ())
+ {
+ grub_romfs_fs.mod = mod;
+ grub_fs_register (&grub_romfs_fs);
+ }
}
GRUB_MOD_FINI(romfs)
{
- grub_fs_unregister (&grub_romfs_fs);
+ if (!grub_is_lockdown ())
+ grub_fs_unregister (&grub_romfs_fs);
}
diff --git a/grub-core/fs/sfs.c b/grub-core/fs/sfs.c
index f0d7cac43..88705b3a2 100644
--- a/grub-core/fs/sfs.c
+++ b/grub-core/fs/sfs.c
@@ -26,6 +26,7 @@
#include <grub/types.h>
#include <grub/fshelp.h>
#include <grub/charset.h>
+#include <grub/lockdown.h>
#include <grub/safemath.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -779,12 +780,16 @@ static struct grub_fs grub_sfs_fs =
GRUB_MOD_INIT(sfs)
{
- grub_sfs_fs.mod = mod;
- grub_fs_register (&grub_sfs_fs);
+ if (!grub_is_lockdown ())
+ {
+ grub_sfs_fs.mod = mod;
+ grub_fs_register (&grub_sfs_fs);
+ }
my_mod = mod;
}
GRUB_MOD_FINI(sfs)
{
- grub_fs_unregister (&grub_sfs_fs);
+ if (!grub_is_lockdown ())
+ grub_fs_unregister (&grub_sfs_fs);
}
diff --git a/grub-core/fs/udf.c b/grub-core/fs/udf.c
index 8765c633c..3d5ee5af5 100644
--- a/grub-core/fs/udf.c
+++ b/grub-core/fs/udf.c
@@ -27,6 +27,7 @@
#include <grub/fshelp.h>
#include <grub/charset.h>
#include <grub/datetime.h>
+#include <grub/lockdown.h>
#include <grub/udf.h>
#include <grub/safemath.h>
@@ -1455,12 +1456,16 @@ static struct grub_fs grub_udf_fs = {
GRUB_MOD_INIT (udf)
{
- grub_udf_fs.mod = mod;
- grub_fs_register (&grub_udf_fs);
+ if (!grub_is_lockdown ())
+ {
+ grub_udf_fs.mod = mod;
+ grub_fs_register (&grub_udf_fs);
+ }
my_mod = mod;
}
GRUB_MOD_FINI (udf)
{
- grub_fs_unregister (&grub_udf_fs);
+ if (!grub_is_lockdown ())
+ grub_fs_unregister (&grub_udf_fs);
}
diff --git a/grub-core/fs/ufs.c b/grub-core/fs/ufs.c
index e82d9356d..8b5adbd48 100644
--- a/grub-core/fs/ufs.c
+++ b/grub-core/fs/ufs.c
@@ -25,6 +25,7 @@
#include <grub/dl.h>
#include <grub/types.h>
#include <grub/i18n.h>
+#include <grub/lockdown.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -899,8 +900,11 @@ GRUB_MOD_INIT(ufs1)
#endif
#endif
{
- grub_ufs_fs.mod = mod;
- grub_fs_register (&grub_ufs_fs);
+ if (!grub_is_lockdown ())
+ {
+ grub_ufs_fs.mod = mod;
+ grub_fs_register (&grub_ufs_fs);
+ }
my_mod = mod;
}
@@ -914,6 +918,7 @@ GRUB_MOD_FINI(ufs1)
#endif
#endif
{
- grub_fs_unregister (&grub_ufs_fs);
+ if (!grub_is_lockdown ())
+ grub_fs_unregister (&grub_ufs_fs);
}

View file

@ -0,0 +1,543 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alec Brown <alec.r.brown@oracle.com>
Date: Tue, 11 Feb 2025 17:59:04 -0600
Subject: [PATCH] disk: Use safe math macros to prevent overflows
Replace direct arithmetic operations with macros from include/grub/safemath.h
to prevent potential overflow issues when calculating the memory sizes.
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/disk/cryptodisk.c | 36 ++++++++++++++++++------
grub-core/disk/diskfilter.c | 9 ++++--
grub-core/disk/ieee1275/obdisk.c | 43 ++++++++++++++++++++++++----
grub-core/disk/ieee1275/ofdisk.c | 60 ++++++++++++++++++++++++++++++++++------
grub-core/disk/ldm.c | 36 ++++++++++++++++++++----
grub-core/disk/luks2.c | 7 ++++-
grub-core/disk/memdisk.c | 7 ++++-
grub-core/disk/plainmount.c | 9 ++++--
8 files changed, 172 insertions(+), 35 deletions(-)
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index 06a42b2d7..872776010 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -26,6 +26,7 @@
#include <grub/file.h>
#include <grub/procfs.h>
#include <grub/partition.h>
+#include <grub/safemath.h>
#ifdef GRUB_UTIL
#include <grub/emu/hostdisk.h>
@@ -1475,7 +1476,7 @@ static char *
luks_script_get (grub_size_t *sz)
{
grub_cryptodisk_t i;
- grub_size_t size = 0;
+ grub_size_t size = 0, mul;
char *ptr, *ret;
*sz = 0;
@@ -1484,10 +1485,6 @@ luks_script_get (grub_size_t *sz)
if (grub_strcmp (i->modname, "luks") == 0 ||
grub_strcmp (i->modname, "luks2") == 0)
{
- size += grub_strlen (i->modname);
- size += sizeof ("_mount");
- size += grub_strlen (i->uuid);
- size += grub_strlen (i->cipher->cipher->name);
/*
* Add space in the line for (in order) spaces, cipher mode, cipher IV
* mode, sector offset, sector size and the trailing newline. This is
@@ -1495,14 +1492,35 @@ luks_script_get (grub_size_t *sz)
* in an earlier version of this code that are unaccounted for. It is
* left in the calculations in case it is needed. At worst, its short-
* lived wasted space.
+ *
+ * 60 = 5 + 5 + 8 + 20 + 6 + 1 + 15
*/
- size += 5 + 5 + 8 + 20 + 6 + 1 + 15;
+ if (grub_add (size, grub_strlen (i->modname), &size) ||
+ grub_add (size, sizeof ("_mount") + 60, &size) ||
+ grub_add (size, grub_strlen (i->uuid), &size) ||
+ grub_add (size, grub_strlen (i->cipher->cipher->name), &size) ||
+ grub_mul (i->keysize, 2, &mul) ||
+ grub_add (size, mul, &size))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while obtaining size of luks script");
+ return 0;
+ }
if (i->essiv_hash)
- size += grub_strlen (i->essiv_hash->name);
- size += i->keysize * 2;
+ {
+ if (grub_add (size, grub_strlen (i->essiv_hash->name), &size))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while obtaining size of luks script");
+ return 0;
+ }
+ }
}
+ if (grub_add (size, 1, &size))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while obtaining size of luks script");
+ return 0;
+ }
- ret = grub_malloc (size + 1);
+ ret = grub_malloc (size);
if (!ret)
return 0;
diff --git a/grub-core/disk/diskfilter.c b/grub-core/disk/diskfilter.c
index c35ce8915..fef0b815a 100644
--- a/grub-core/disk/diskfilter.c
+++ b/grub-core/disk/diskfilter.c
@@ -24,6 +24,7 @@
#include <grub/misc.h>
#include <grub/diskfilter.h>
#include <grub/partition.h>
+#include <grub/safemath.h>
#ifdef GRUB_UTIL
#include <grub/i18n.h>
#include <grub/util/misc.h>
@@ -1041,7 +1042,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;
@@ -1142,7 +1143,11 @@ grub_diskfilter_make_raid (grub_size_t uuidlen, char *uuid, int nmemb,
}
array->lvs->vg = array;
- array->lvs->idname = grub_malloc (sizeof ("mduuid/") + 2 * uuidlen);
+ if (grub_mul (uuidlen, 2, &sz) ||
+ grub_add (sz, sizeof ("mduuid/"), &sz))
+ goto fail;
+
+ array->lvs->idname = grub_malloc (sz);
if (!array->lvs->idname)
goto fail;
diff --git a/grub-core/disk/ieee1275/obdisk.c b/grub-core/disk/ieee1275/obdisk.c
index cd923b90f..9d4c42665 100644
--- a/grub-core/disk/ieee1275/obdisk.c
+++ b/grub-core/disk/ieee1275/obdisk.c
@@ -26,6 +26,7 @@
#include <grub/mm.h>
#include <grub/scsicmd.h>
#include <grub/time.h>
+#include <grub/safemath.h>
#include <grub/ieee1275/ieee1275.h>
#include <grub/ieee1275/obdisk.h>
@@ -128,9 +129,17 @@ count_commas (const char *src)
static char *
decode_grub_devname (const char *name)
{
- char *devpath = grub_malloc (grub_strlen (name) + 1);
+ char *devpath;
char *p, c;
+ grub_size_t sz;
+ if (grub_add (grub_strlen (name), 1, &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining size of device name"));
+ return NULL;
+ }
+
+ devpath = grub_malloc (sz);
if (devpath == NULL)
return NULL;
@@ -156,12 +165,20 @@ static char *
encode_grub_devname (const char *path)
{
char *encoding, *optr;
+ grub_size_t sz;
if (path == NULL)
return NULL;
- encoding = grub_malloc (sizeof (IEEE1275_DEV) + count_commas (path) +
- grub_strlen (path) + 1);
+ if (grub_add (sizeof (IEEE1275_DEV) + 1, count_commas (path), &sz) ||
+ grub_add (sz, grub_strlen (path), &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining encoding size"));
+ grub_print_error ();
+ return NULL;
+ }
+
+ encoding = grub_malloc (sz);
if (encoding == NULL)
{
@@ -396,6 +413,14 @@ canonicalise_disk (const char *devname)
real_unit_str_len = grub_strlen (op->name) + sizeof (IEEE1275_DISK_ALIAS)
+ grub_strlen (real_unit_address);
+ if (grub_add (grub_strlen (op->name), sizeof (IEEE1275_DISK_ALIAS), &real_unit_str_len) ||
+ grub_add (real_unit_str_len, grub_strlen (real_unit_address), &real_unit_str_len))
+ {
+ grub_free (parent);
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining size of canonical name"));
+ grub_print_error ();
+ return NULL;
+ }
real_canon = grub_malloc (real_unit_str_len);
@@ -413,6 +438,7 @@ canonicalise_disk (const char *devname)
static struct disk_dev *
add_canon_disk (const char *cname)
{
+ grub_size_t sz;
struct disk_dev *dev;
dev = grub_zalloc (sizeof (struct disk_dev));
@@ -428,13 +454,18 @@ add_canon_disk (const char *cname)
* arguments and allows a client program to open
* the entire (raw) disk. Any disk label is ignored.
*/
- dev->raw_name = grub_malloc (grub_strlen (cname) + sizeof (":nolabel"));
+ if (grub_add (grub_strlen (cname), sizeof (":nolabel"), &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while appending :nolabel to end of canonical name");
+ goto failed;
+ }
+
+ dev->raw_name = grub_malloc (sz);
if (dev->raw_name == NULL)
goto failed;
- grub_snprintf (dev->raw_name, grub_strlen (cname) + sizeof (":nolabel"),
- "%s:nolabel", cname);
+ grub_snprintf (dev->raw_name, sz, "%s:nolabel", cname);
}
/*
diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c
index 57624fde5..6c628635f 100644
--- a/grub-core/disk/ieee1275/ofdisk.c
+++ b/grub-core/disk/ieee1275/ofdisk.c
@@ -25,6 +25,7 @@
#include <grub/i18n.h>
#include <grub/time.h>
#include <grub/env.h>
+#include <grub/safemath.h>
static char *last_devpath;
static grub_ieee1275_ihandle_t last_ihandle;
@@ -81,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)
@@ -88,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)
{
@@ -99,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);
@@ -225,7 +239,7 @@ dev_iterate (const struct grub_ieee1275_devalias *alias)
args;
char *buf, *bufptr;
unsigned i;
-
+ grub_size_t sz;
RETRY_IEEE1275_OFDISK_OPEN(alias->path, &ihandle)
if (! ihandle)
@@ -246,7 +260,14 @@ dev_iterate (const struct grub_ieee1275_devalias *alias)
return;
}
- buf = grub_malloc (grub_strlen (alias->path) + 32);
+ if (grub_add (grub_strlen (alias->path), 32, &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while creating buffer for vscsi");
+ grub_ieee1275_close (ihandle);
+ return;
+ }
+
+ buf = grub_malloc (sz);
if (!buf)
return;
bufptr = grub_stpcpy (buf, alias->path);
@@ -290,9 +311,15 @@ dev_iterate (const struct grub_ieee1275_devalias *alias)
grub_uint64_t *table;
grub_uint16_t table_size;
grub_ieee1275_ihandle_t ihandle;
+ grub_size_t sz;
- buf = grub_malloc (grub_strlen (alias->path) +
- sizeof ("/disk@7766554433221100"));
+ if (grub_add (grub_strlen (alias->path), sizeof ("/disk@7766554433221100"), &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while creating buffer for sas_ioa");
+ return;
+ }
+
+ buf = grub_malloc (sz);
if (!buf)
return;
bufptr = grub_stpcpy (buf, alias->path);
@@ -432,9 +459,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;
@@ -657,6 +692,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)
@@ -667,7 +703,13 @@ insert_bootpath (void)
return;
}
- bootpath = (char *) grub_malloc ((grub_size_t) bootpath_size + 64);
+ if (grub_add (bootpath_size, 64, &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining bootpath size"));
+ return;
+ }
+
+ bootpath = (char *) grub_malloc (sz);
if (! bootpath)
{
grub_print_error ();
diff --git a/grub-core/disk/ldm.c b/grub-core/disk/ldm.c
index 34bfe6bd1..4101b15d8 100644
--- a/grub-core/disk/ldm.c
+++ b/grub-core/disk/ldm.c
@@ -220,6 +220,7 @@ make_vg (grub_disk_t disk,
struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE
/ sizeof (struct grub_ldm_vblk)];
unsigned i;
+ grub_size_t sz;
err = grub_disk_read (disk, cursec, 0,
sizeof(vblk), &vblk);
if (err)
@@ -251,7 +252,13 @@ make_vg (grub_disk_t disk,
grub_free (pv);
goto fail2;
}
- pv->internal_id = grub_malloc (ptr[0] + 2);
+ if (grub_add (ptr[0], 2, &sz))
+ {
+ grub_free (pv);
+ goto fail2;
+ }
+
+ pv->internal_id = grub_malloc (sz);
if (!pv->internal_id)
{
grub_free (pv);
@@ -276,7 +283,15 @@ make_vg (grub_disk_t disk,
goto fail2;
}
pv->id.uuidlen = *ptr;
- pv->id.uuid = grub_malloc (pv->id.uuidlen + 1);
+
+ if (grub_add (pv->id.uuidlen, 1, &sz))
+ {
+ grub_free (pv->internal_id);
+ grub_free (pv);
+ goto fail2;
+ }
+
+ pv->id.uuid = grub_malloc (sz);
grub_memcpy (pv->id.uuid, ptr + 1, pv->id.uuidlen);
pv->id.uuid[pv->id.uuidlen] = 0;
@@ -343,7 +358,13 @@ make_vg (grub_disk_t disk,
grub_free (lv);
goto fail2;
}
- lv->internal_id = grub_malloc ((grub_size_t) ptr[0] + 2);
+ if (grub_add (ptr[0], 2, &sz))
+ {
+ grub_free (lv->segments);
+ grub_free (lv);
+ goto fail2;
+ }
+ lv->internal_id = grub_malloc (sz);
if (!lv->internal_id)
{
grub_free (lv);
@@ -455,6 +476,7 @@ make_vg (grub_disk_t disk,
struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE
/ sizeof (struct grub_ldm_vblk)];
unsigned i;
+ grub_size_t sz;
err = grub_disk_read (disk, cursec, 0,
sizeof(vblk), &vblk);
if (err)
@@ -490,7 +512,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 +667,6 @@ make_vg (grub_disk_t disk,
if (lv->segments->node_alloc == lv->segments->node_count)
{
void *t;
- grub_size_t sz;
if (grub_mul (lv->segments->node_alloc, 2, &lv->segments->node_alloc) ||
grub_mul (lv->segments->node_alloc, sizeof (*lv->segments->nodes), &sz))
diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c
index d5106402f..8036d76ff 100644
--- a/grub-core/disk/luks2.c
+++ b/grub-core/disk/luks2.c
@@ -26,6 +26,7 @@
#include <grub/crypto.h>
#include <grub/partition.h>
#include <grub/i18n.h>
+#include <grub/safemath.h>
#include <base64.h>
#include <json.h>
@@ -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/memdisk.c b/grub-core/disk/memdisk.c
index 613779cf3..36de3bfab 100644
--- a/grub-core/disk/memdisk.c
+++ b/grub-core/disk/memdisk.c
@@ -23,6 +23,7 @@
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/types.h>
+#include <grub/safemath.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -96,7 +97,11 @@ GRUB_MOD_INIT(memdisk)
grub_dprintf ("memdisk", "Found memdisk image at %p\n", memdisk_orig_addr);
- memdisk_size = header->size - sizeof (struct grub_module_header);
+ if (grub_sub (header->size, sizeof (struct grub_module_header), &memdisk_size))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "underflow detected while obtaining memdisk size");
+ return;
+ }
memdisk_addr = grub_malloc (memdisk_size);
grub_dprintf ("memdisk", "Copying memdisk image to dynamic memory\n");
diff --git a/grub-core/disk/plainmount.c b/grub-core/disk/plainmount.c
index 47e64805f..21ec4072c 100644
--- a/grub-core/disk/plainmount.c
+++ b/grub-core/disk/plainmount.c
@@ -24,6 +24,7 @@
#include <grub/extcmd.h>
#include <grub/partition.h>
#include <grub/file.h>
+#include <grub/safemath.h>
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)
{

View file

@ -0,0 +1,38 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alec Brown <alec.r.brown@oracle.com>
Date: Wed, 12 Feb 2025 10:26:44 -0600
Subject: [PATCH] disk: Prevent overflows when allocating memory for arrays
Use grub_calloc() when allocating memory for arrays to ensure proper
overflow checks are in place.
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/disk/lvm.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/grub-core/disk/lvm.c b/grub-core/disk/lvm.c
index 794248540..a395b200d 100644
--- a/grub-core/disk/lvm.c
+++ b/grub-core/disk/lvm.c
@@ -671,8 +671,7 @@ grub_lvm_detect (grub_disk_t disk,
goto lvs_segment_fail;
}
- seg->nodes = grub_zalloc (sizeof (seg->nodes[0])
- * seg->node_count);
+ seg->nodes = grub_calloc (seg->node_count, sizeof (seg->nodes[0]));
p = grub_strstr (p, "mirrors = [");
if (p == NULL)
@@ -760,8 +759,7 @@ grub_lvm_detect (grub_disk_t disk,
}
}
- seg->nodes = grub_zalloc (sizeof (seg->nodes[0])
- * seg->node_count);
+ seg->nodes = grub_calloc (seg->node_count, sizeof (seg->nodes[0]));
p = grub_strstr (p, "raids = [");
if (p == NULL)

View file

@ -0,0 +1,152 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alec Brown <alec.r.brown@oracle.com>
Date: Wed, 22 Jan 2025 02:55:11 +0000
Subject: [PATCH] disk: Check if returned pointer for allocated memory is NULL
When using grub_malloc(), grub_zalloc() or grub_calloc(), these functions can
fail if we are out of memory. After allocating memory we should check if these
functions returned NULL and handle this error if they did.
On the occasion make a NULL check in ATA code more obvious.
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/disk/ata.c | 4 ++--
grub-core/disk/ieee1275/obdisk.c | 6 ++++++
grub-core/disk/ldm.c | 6 ++++++
grub-core/disk/lvm.c | 14 ++++++++++++++
grub-core/disk/memdisk.c | 2 ++
5 files changed, 30 insertions(+), 2 deletions(-)
diff --git a/grub-core/disk/ata.c b/grub-core/disk/ata.c
index 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/ieee1275/obdisk.c b/grub-core/disk/ieee1275/obdisk.c
index 9d4c42665..fcc39e0a2 100644
--- a/grub-core/disk/ieee1275/obdisk.c
+++ b/grub-core/disk/ieee1275/obdisk.c
@@ -423,6 +423,12 @@ canonicalise_disk (const char *devname)
}
real_canon = grub_malloc (real_unit_str_len);
+ if (real_canon == NULL)
+ {
+ grub_free (parent);
+ grub_print_error ();
+ return NULL;
+ }
grub_snprintf (real_canon, real_unit_str_len, "%s/disk@%s",
op->name, real_unit_address);
diff --git a/grub-core/disk/ldm.c b/grub-core/disk/ldm.c
index 4101b15d8..048e29cd0 100644
--- a/grub-core/disk/ldm.c
+++ b/grub-core/disk/ldm.c
@@ -292,6 +292,12 @@ make_vg (grub_disk_t disk,
}
pv->id.uuid = grub_malloc (sz);
+ if (pv->id.uuid == NULL)
+ {
+ grub_free (pv->internal_id);
+ grub_free (pv);
+ goto fail2;
+ }
grub_memcpy (pv->id.uuid, ptr + 1, pv->id.uuidlen);
pv->id.uuid[pv->id.uuidlen] = 0;
diff --git a/grub-core/disk/lvm.c b/grub-core/disk/lvm.c
index a395b200d..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 = [");
@@ -672,6 +682,8 @@ grub_lvm_detect (grub_disk_t disk,
}
seg->nodes = grub_calloc (seg->node_count, sizeof (seg->nodes[0]));
+ if (seg->nodes == NULL)
+ goto lvs_segment_fail;
p = grub_strstr (p, "mirrors = [");
if (p == NULL)
@@ -760,6 +772,8 @@ grub_lvm_detect (grub_disk_t disk,
}
seg->nodes = grub_calloc (seg->node_count, sizeof (seg->nodes[0]));
+ if (seg->nodes == NULL)
+ goto lvs_segment_fail;
p = grub_strstr (p, "raids = [");
if (p == NULL)
diff --git a/grub-core/disk/memdisk.c b/grub-core/disk/memdisk.c
index 36de3bfab..2d7afaea3 100644
--- a/grub-core/disk/memdisk.c
+++ b/grub-core/disk/memdisk.c
@@ -103,6 +103,8 @@ GRUB_MOD_INIT(memdisk)
return;
}
memdisk_addr = grub_malloc (memdisk_size);
+ if (memdisk_addr == NULL)
+ return;
grub_dprintf ("memdisk", "Copying memdisk image to dynamic memory\n");
grub_memmove (memdisk_addr, memdisk_orig_addr, memdisk_size);

View file

@ -0,0 +1,31 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alec Brown <alec.r.brown@oracle.com>
Date: Wed, 22 Jan 2025 02:55:12 +0000
Subject: [PATCH] disk/ieee1275/ofdisk: Call grub_ieee1275_close() when
grub_malloc() fails
In the dev_iterate() function a handle is opened but isn't closed when
grub_malloc() returns NULL. We should fix this by closing it on error.
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/disk/ieee1275/ofdisk.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c
index 6c628635f..71237b256 100644
--- a/grub-core/disk/ieee1275/ofdisk.c
+++ b/grub-core/disk/ieee1275/ofdisk.c
@@ -269,7 +269,10 @@ dev_iterate (const struct grub_ieee1275_devalias *alias)
buf = grub_malloc (sz);
if (!buf)
- return;
+ {
+ grub_ieee1275_close (ihandle);
+ return;
+ }
bufptr = grub_stpcpy (buf, alias->path);
for (i = 0; i < args.nentries; i++)

View file

@ -0,0 +1,353 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lidong Chen <lidong.chen@oracle.com>
Date: Wed, 12 Feb 2025 10:33:31 -0600
Subject: [PATCH] fs: Use safe math macros to prevent overflows
Replace direct arithmetic operations with macros from include/grub/safemath.h
to prevent potential overflow issues when calculating the memory sizes.
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/archelp.c | 9 ++++++++-
grub-core/fs/btrfs.c | 34 ++++++++++++++++++++++++++++------
grub-core/fs/cpio_common.c | 16 ++++++++++++++--
grub-core/fs/f2fs.c | 17 +++++++++++++++--
grub-core/fs/ntfscomp.c | 9 ++++++++-
grub-core/fs/squash4.c | 12 +++++++++---
grub-core/fs/xfs.c | 17 +++++++++++++++--
7 files changed, 97 insertions(+), 17 deletions(-)
diff --git a/grub-core/fs/archelp.c b/grub-core/fs/archelp.c
index c1dcc6285..0816b28de 100644
--- a/grub-core/fs/archelp.c
+++ b/grub-core/fs/archelp.c
@@ -21,6 +21,7 @@
#include <grub/fs.h>
#include <grub/disk.h>
#include <grub/dl.h>
+#include <grub/safemath.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -68,6 +69,7 @@ handle_symlink (struct grub_archelp_data *data,
char *rest;
char *linktarget;
grub_size_t linktarget_len;
+ grub_size_t sz;
*restart = 0;
@@ -98,7 +100,12 @@ handle_symlink (struct grub_archelp_data *data,
if (linktarget[0] == '\0')
return GRUB_ERR_NONE;
linktarget_len = grub_strlen (linktarget);
- target = grub_malloc (linktarget_len + grub_strlen (*name) + 2);
+
+ if (grub_add (linktarget_len, grub_strlen (*name), &sz) ||
+ grub_add (sz, 2, &sz))
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("link target length overflow"));
+
+ target = grub_malloc (sz);
if (!target)
return grub_errno;
diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
index 6593f5175..3e4924b65 100644
--- a/grub-core/fs/btrfs.c
+++ b/grub-core/fs/btrfs.c
@@ -2031,6 +2031,7 @@ find_path (struct grub_btrfs_data *data,
char *origpath = NULL;
unsigned symlinks_max = 32;
const char *relpath = grub_env_get ("btrfs_relative_path");
+ grub_size_t sz;
follow_default = 0;
origpath = grub_strdup (path);
@@ -2157,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);
@@ -2223,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);
@@ -2371,6 +2386,7 @@ grub_btrfs_dir (grub_device_t device, const char *path,
grub_uint8_t type;
grub_size_t est_size = 0;
char *new_path = NULL;
+ grub_size_t sz;
if (!data)
return grub_errno;
@@ -2420,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;
diff --git a/grub-core/fs/cpio_common.c b/grub-core/fs/cpio_common.c
index 5d41b6fdb..6ba58b354 100644
--- a/grub-core/fs/cpio_common.c
+++ b/grub-core/fs/cpio_common.c
@@ -24,6 +24,7 @@
#include <grub/dl.h>
#include <grub/i18n.h>
#include <grub/archelp.h>
+#include <grub/safemath.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -48,6 +49,7 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name,
struct head hd;
grub_size_t namesize;
grub_uint32_t modeval;
+ grub_size_t sz;
data->hofs = data->next_hofs;
@@ -76,7 +78,10 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name,
*mode = modeval;
- *name = grub_malloc (namesize + 1);
+ if (grub_add (namesize, 1, &sz))
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("file name size overflow"));
+
+ *name = grub_malloc (sz);
if (*name == NULL)
return grub_errno;
@@ -110,10 +115,17 @@ grub_cpio_get_link_target (struct grub_archelp_data *data)
{
char *ret;
grub_err_t err;
+ grub_size_t sz;
if (data->size == 0)
return grub_strdup ("");
- ret = grub_malloc (data->size + 1);
+
+ if (grub_add (data->size, 1, &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("target data size overflow"));
+ return NULL;
+ }
+ ret = grub_malloc (sz);
if (!ret)
return NULL;
diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c
index f6d6beaa5..72b4aa1e6 100644
--- a/grub-core/fs/f2fs.c
+++ b/grub-core/fs/f2fs.c
@@ -28,6 +28,7 @@
#include <grub/types.h>
#include <grub/charset.h>
#include <grub/fshelp.h>
+#include <grub/safemath.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -958,6 +959,7 @@ grub_f2fs_read_symlink (grub_fshelp_node_t node)
char *symlink;
struct grub_fshelp_node *diro = node;
grub_uint64_t filesize;
+ grub_size_t sz;
if (!diro->inode_read)
{
@@ -968,7 +970,12 @@ grub_f2fs_read_symlink (grub_fshelp_node_t node)
filesize = grub_f2fs_file_size(&diro->inode.i);
- symlink = grub_malloc (filesize + 1);
+ if (grub_add (filesize, 1, &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("symlink size overflow"));
+ return 0;
+ }
+ symlink = grub_malloc (sz);
if (!symlink)
return 0;
@@ -997,6 +1004,7 @@ grub_f2fs_check_dentries (struct grub_f2fs_dir_iter_ctx *ctx)
enum FILE_TYPE ftype;
int name_len;
int ret;
+ int sz;
if (grub_f2fs_test_bit_le (i, ctx->bitmap) == 0)
{
@@ -1010,7 +1018,12 @@ grub_f2fs_check_dentries (struct grub_f2fs_dir_iter_ctx *ctx)
if (name_len >= F2FS_NAME_LEN)
return 0;
- filename = grub_malloc (name_len + 1);
+ if (grub_add (name_len, 1, &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("directory entry name length overflow"));
+ return 0;
+ }
+ filename = grub_malloc (sz);
if (!filename)
return 0;
diff --git a/grub-core/fs/ntfscomp.c b/grub-core/fs/ntfscomp.c
index a009f2c2d..f168a318e 100644
--- a/grub-core/fs/ntfscomp.c
+++ b/grub-core/fs/ntfscomp.c
@@ -22,6 +22,7 @@
#include <grub/disk.h>
#include <grub/dl.h>
#include <grub/ntfs.h>
+#include <grub/safemath.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -310,6 +311,7 @@ ntfscomp (grub_uint8_t *dest, grub_disk_addr_t ofs,
{
grub_err_t ret;
grub_disk_addr_t vcn;
+ int log_sz;
if (ctx->attr->sbuf)
{
@@ -349,7 +351,12 @@ ntfscomp (grub_uint8_t *dest, grub_disk_addr_t ofs,
}
ctx->comp.comp_head = ctx->comp.comp_tail = 0;
- ctx->comp.cbuf = grub_malloc (1 << (ctx->comp.log_spc + GRUB_NTFS_BLK_SHR));
+ if (grub_add (ctx->comp.log_spc, GRUB_NTFS_BLK_SHR, &log_sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("compression buffer size overflow"));
+ return 0;
+ }
+ ctx->comp.cbuf = grub_malloc (1 << log_sz);
if (!ctx->comp.cbuf)
return 0;
diff --git a/grub-core/fs/squash4.c b/grub-core/fs/squash4.c
index 6e9d63874..f91ff3bfa 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,
diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c
index 6c952aef1..c60db7361 100644
--- a/grub-core/fs/xfs.c
+++ b/grub-core/fs/xfs.c
@@ -718,6 +718,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)
{
@@ -739,7 +740,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;
@@ -789,8 +795,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 ();

View file

@ -0,0 +1,82 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lidong Chen <lidong.chen@oracle.com>
Date: Tue, 21 Jan 2025 19:02:37 +0000
Subject: [PATCH] fs: Prevent overflows when allocating memory for arrays
Use grub_calloc() when allocating memory for arrays to ensure proper
overflow checks are in place.
The HFS+ and squash4 security vulnerabilities were reported by
Jonathan Bar Or <jonathanbaror@gmail.com>.
Fixes: CVE-2025-0678
Fixes: CVE-2025-1125
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/btrfs.c | 4 ++--
grub-core/fs/hfspluscomp.c | 9 +++++++--
grub-core/fs/squash4.c | 8 ++++----
3 files changed, 13 insertions(+), 8 deletions(-)
diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
index 3e4924b65..3228e1788 100644
--- a/grub-core/fs/btrfs.c
+++ b/grub-core/fs/btrfs.c
@@ -1409,8 +1409,8 @@ grub_btrfs_mount (grub_device_t dev)
}
data->n_devices_allocated = 16;
- data->devices_attached = grub_malloc (sizeof (data->devices_attached[0])
- * data->n_devices_allocated);
+ data->devices_attached = grub_calloc (data->n_devices_allocated,
+ sizeof (data->devices_attached[0]));
if (!data->devices_attached)
{
grub_free (data);
diff --git a/grub-core/fs/hfspluscomp.c b/grub-core/fs/hfspluscomp.c
index 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/squash4.c b/grub-core/fs/squash4.c
index f91ff3bfa..cf2bca822 100644
--- a/grub-core/fs/squash4.c
+++ b/grub-core/fs/squash4.c
@@ -822,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);

View file

@ -0,0 +1,105 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lidong Chen <lidong.chen@oracle.com>
Date: Tue, 21 Jan 2025 19:02:38 +0000
Subject: [PATCH] fs: Prevent overflows when assigning returned values from
read_number()
The direct assignment of the unsigned long long value returned by
read_number() can potentially lead to an overflow on a 32-bit systems.
The fix replaces the direct assignments with calls to grub_cast()
which detects the overflows and safely assigns the values if no
overflow is detected.
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/cpio_common.c | 18 ++++++++++++++----
grub-core/fs/tar.c | 23 ++++++++++++++++-------
2 files changed, 30 insertions(+), 11 deletions(-)
diff --git a/grub-core/fs/cpio_common.c b/grub-core/fs/cpio_common.c
index 6ba58b354..45ac119a8 100644
--- a/grub-core/fs/cpio_common.c
+++ b/grub-core/fs/cpio_common.c
@@ -62,11 +62,21 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name,
#endif
)
return grub_error (GRUB_ERR_BAD_FS, "invalid cpio archive");
- data->size = read_number (hd.filesize, ARRAY_SIZE (hd.filesize));
+
+ if (grub_cast (read_number (hd.filesize, ARRAY_SIZE (hd.filesize)), &data->size))
+ return grub_error (GRUB_ERR_BAD_FS, N_("data size overflow"));
+
if (mtime)
- *mtime = read_number (hd.mtime, ARRAY_SIZE (hd.mtime));
- modeval = read_number (hd.mode, ARRAY_SIZE (hd.mode));
- namesize = read_number (hd.namesize, ARRAY_SIZE (hd.namesize));
+ {
+ if (grub_cast (read_number (hd.mtime, ARRAY_SIZE (hd.mtime)), mtime))
+ return grub_error (GRUB_ERR_BAD_FS, N_("mtime overflow"));
+ }
+
+ if (grub_cast (read_number (hd.mode, ARRAY_SIZE (hd.mode)), &modeval))
+ return grub_error (GRUB_ERR_BAD_FS, N_("mode overflow"));
+
+ if (grub_cast (read_number (hd.namesize, ARRAY_SIZE (hd.namesize)), &namesize))
+ return grub_error (GRUB_ERR_BAD_FS, N_("namesize overflow"));
/* Don't allow negative numbers. */
if (namesize >= 0x80000000)
diff --git a/grub-core/fs/tar.c b/grub-core/fs/tar.c
index fd2ec1f74..1eaa5349f 100644
--- a/grub-core/fs/tar.c
+++ b/grub-core/fs/tar.c
@@ -99,9 +99,10 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name,
if (hd.typeflag == 'L')
{
grub_err_t err;
- grub_size_t namesize = read_number (hd.size, sizeof (hd.size));
+ grub_size_t namesize;
- if (grub_add (namesize, 1, &sz))
+ if (grub_cast (read_number (hd.size, sizeof (hd.size)), &namesize) ||
+ grub_add (namesize, 1, &sz))
return grub_error (GRUB_ERR_BAD_FS, N_("name size overflow"));
*name = grub_malloc (sz);
@@ -123,9 +124,10 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name,
if (hd.typeflag == 'K')
{
grub_err_t err;
- grub_size_t linksize = read_number (hd.size, sizeof (hd.size));
+ grub_size_t linksize;
- if (grub_add (linksize, 1, &sz))
+ if (grub_cast (read_number (hd.size, sizeof (hd.size)), &linksize) ||
+ grub_add (linksize, 1, &sz))
return grub_error (GRUB_ERR_BAD_FS, N_("link size overflow"));
if (data->linkname_alloc < sz)
@@ -174,15 +176,22 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name,
(*name)[extra_size + sizeof (hd.name)] = 0;
}
- data->size = read_number (hd.size, sizeof (hd.size));
+ if (grub_cast (read_number (hd.size, sizeof (hd.size)), &data->size))
+ return grub_error (GRUB_ERR_BAD_FS, N_("data size overflow"));
+
data->dofs = data->hofs + GRUB_DISK_SECTOR_SIZE;
data->next_hofs = data->dofs + ((data->size + GRUB_DISK_SECTOR_SIZE - 1) &
~(GRUB_DISK_SECTOR_SIZE - 1));
if (mtime)
- *mtime = read_number (hd.mtime, sizeof (hd.mtime));
+ {
+ if (grub_cast (read_number (hd.mtime, sizeof (hd.mtime)), mtime))
+ return grub_error (GRUB_ERR_BAD_FS, N_("mtime overflow"));
+ }
if (mode)
{
- *mode = read_number (hd.mode, sizeof (hd.mode));
+ if (grub_cast (read_number (hd.mode, sizeof (hd.mode)), mode))
+ return grub_error (GRUB_ERR_BAD_FS, N_("mode overflow"));
+
switch (hd.typeflag)
{
/* Hardlink. */

View file

@ -0,0 +1,138 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lidong Chen <lidong.chen@oracle.com>
Date: Wed, 22 Jan 2025 07:17:02 +0000
Subject: [PATCH] fs/zfs: Use safe math macros to prevent overflows
Replace direct arithmetic operations with macros from include/grub/safemath.h
to prevent potential overflow issues when calculating the memory sizes.
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/zfs/zfs.c | 50 ++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 44 insertions(+), 6 deletions(-)
diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c
index a497b1869..2f303d655 100644
--- a/grub-core/fs/zfs/zfs.c
+++ b/grub-core/fs/zfs/zfs.c
@@ -2387,6 +2387,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 +2449,14 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
if (le->le_type != ZAP_CHUNK_ENTRY)
continue;
- buf = grub_malloc (grub_zfs_to_cpu16 (le->le_name_length, endian)
- * name_elem_length + 1);
+ if (grub_mul (grub_zfs_to_cpu16 (le->le_name_length, endian), name_elem_length, &sz) ||
+ grub_add (sz, 1, &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("buffer size overflow"));
+ grub_free (l);
+ return grub_errno;
+ }
+ buf = grub_malloc (sz);
if (zap_leaf_array_get (l, endian, blksft,
grub_zfs_to_cpu16 (le->le_name_chunk,
endian),
@@ -2872,6 +2879,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 +2931,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 +2979,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 +3013,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);
@@ -3568,6 +3596,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 +3631,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));
@@ -4193,6 +4227,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 +4248,10 @@ iterate_zap_snap (const char *name, grub_uint64_t val,
return 0;
}
- name2 = grub_malloc (grub_strlen (name) + 2);
+ if (grub_add (grub_strlen (name), 2, &sz))
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("name length overflow"));
+
+ name2 = grub_malloc (sz);
name2[0] = '@';
grub_memcpy (name2 + 1, name, grub_strlen (name) + 1);
ret = ctx->hook (name2, &info, ctx->hook_data);

View file

@ -0,0 +1,40 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lidong Chen <lidong.chen@oracle.com>
Date: Wed, 22 Jan 2025 07:17:03 +0000
Subject: [PATCH] fs/zfs: Prevent overflows when allocating memory for arrays
Use grub_calloc() when allocating memory for arrays to ensure proper
overflow checks are in place.
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/zfs/zfs.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c
index 2f303d655..9ab7bf319 100644
--- a/grub-core/fs/zfs/zfs.c
+++ b/grub-core/fs/zfs/zfs.c
@@ -723,8 +723,8 @@ fill_vdev_info_real (struct grub_zfs_data *data,
{
fill->n_children = nelm;
- fill->children = grub_zalloc (fill->n_children
- * sizeof (fill->children[0]));
+ fill->children = grub_calloc (fill->n_children,
+ sizeof (fill->children[0]));
}
for (i = 0; i < nelm; i++)
@@ -3712,8 +3712,8 @@ zfs_mount (grub_device_t dev)
#endif
data->n_devices_allocated = 16;
- data->devices_attached = grub_malloc (sizeof (data->devices_attached[0])
- * data->n_devices_allocated);
+ data->devices_attached = grub_calloc (data->n_devices_allocated,
+ sizeof (data->devices_attached[0]));
data->n_devices_attached = 0;
err = scan_disk (dev, data, 1, &inserted);
if (err)

View file

@ -0,0 +1,88 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lidong Chen <lidong.chen@oracle.com>
Date: Wed, 22 Jan 2025 07:17:01 +0000
Subject: [PATCH] fs/zfs: Check if returned pointer for allocated memory is
NULL
When using grub_malloc() or grub_zalloc(), these functions can fail if
we are out of memory. After allocating memory we should check if these
functions returned NULL and handle this error if they did.
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/zfs/zfs.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c
index 9ab7bf319..6e6d1c921 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,
@@ -725,6 +727,11 @@ fill_vdev_info_real (struct grub_zfs_data *data,
fill->children = grub_calloc (fill->n_children,
sizeof (fill->children[0]));
+ if (!fill->children)
+ {
+ grub_free (type);
+ return grub_errno;
+ }
}
for (i = 0; i < nelm; i++)
@@ -2457,6 +2464,11 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
return grub_errno;
}
buf = grub_malloc (sz);
+ if (!buf)
+ {
+ grub_free (l);
+ return grub_errno;
+ }
if (zap_leaf_array_get (l, endian, blksft,
grub_zfs_to_cpu16 (le->le_name_chunk,
endian),
@@ -2472,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),
@@ -3714,6 +3732,11 @@ zfs_mount (grub_device_t dev)
data->n_devices_allocated = 16;
data->devices_attached = grub_calloc (data->n_devices_allocated,
sizeof (data->devices_attached[0]));
+ if (!data->devices_attached)
+ {
+ grub_free (data);
+ return NULL;
+ }
data->n_devices_attached = 0;
err = scan_disk (dev, data, 1, &inserted);
if (err)
@@ -4252,6 +4275,9 @@ iterate_zap_snap (const char *name, grub_uint64_t val,
return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("name length overflow"));
name2 = grub_malloc (sz);
+ if (!name2)
+ return grub_errno;
+
name2[0] = '@';
grub_memcpy (name2 + 1, name, grub_strlen (name) + 1);
ret = ctx->hook (name2, &info, ctx->hook_data);

View file

@ -0,0 +1,24 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lidong Chen <lidong.chen@oracle.com>
Date: Wed, 22 Jan 2025 07:17:04 +0000
Subject: [PATCH] fs/zfs: Add missing NULL check after grub_strdup() call
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/zfs/zfs.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c
index 6e6d1c921..5ff647ffb 100644
--- a/grub-core/fs/zfs/zfs.c
+++ b/grub-core/fs/zfs/zfs.c
@@ -3309,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
{

View file

@ -0,0 +1,240 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lidong Chen <lidong.chen@oracle.com>
Date: Wed, 12 Feb 2025 10:38:17 -0600
Subject: [PATCH] net: Use safe math macros to prevent overflows
Replace direct arithmetic operations with macros from include/grub/safemath.h
to prevent potential overflow issues when calculating the memory sizes.
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/net/bootp.c | 16 +++++++++++--
grub-core/net/dns.c | 9 ++++++-
grub-core/net/drivers/ieee1275/ofnet.c | 20 ++++++++++++++--
grub-core/net/net.c | 43 +++++++++++++++++++++++++++-------
4 files changed, 75 insertions(+), 13 deletions(-)
diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c
index 9cbdc2264..bed70c0b2 100644
--- a/grub-core/net/bootp.c
+++ b/grub-core/net/bootp.c
@@ -27,6 +27,7 @@
#include <grub/datetime.h>
#include <grub/time.h>
#include <grub/list.h>
+#include <grub/safemath.h>
static int
dissect_url (const char *url, char **proto, char **host, char **path)
@@ -1479,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,
@@ -1520,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);
@@ -1553,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;
diff --git a/grub-core/net/dns.c b/grub-core/net/dns.c
index fcc09aa65..39b0c46cf 100644
--- a/grub-core/net/dns.c
+++ b/grub-core/net/dns.c
@@ -224,10 +224,17 @@ get_name (const grub_uint8_t *name_at, const grub_uint8_t *head,
{
int length;
char *ret;
+ int len;
if (!check_name_real (name_at, head, tail, NULL, &length, NULL))
return NULL;
- ret = grub_malloc (length + 1);
+
+ if (grub_add (length, 1, &len))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("name length overflow"));
+ return NULL;
+ }
+ ret = grub_malloc (len);
if (!ret)
return NULL;
if (!check_name_real (name_at, head, tail, NULL, NULL, ret))
diff --git a/grub-core/net/drivers/ieee1275/ofnet.c b/grub-core/net/drivers/ieee1275/ofnet.c
index c56461ff1..b5336dfbb 100644
--- a/grub-core/net/drivers/ieee1275/ofnet.c
+++ b/grub-core/net/drivers/ieee1275/ofnet.c
@@ -22,6 +22,7 @@
#include <grub/net.h>
#include <grub/time.h>
#include <grub/i18n.h>
+#include <grub/safemath.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -392,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;
@@ -449,9 +451,23 @@ search_net_devices (struct grub_ieee1275_devalias *alias)
}
if (need_suffix)
- ofdata->path = grub_malloc (grub_strlen (alias->path) + sizeof (SUFFIX));
+ {
+ if (grub_add (grub_strlen (alias->path), sizeof (SUFFIX), &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obatining size of ofdata path"));
+ grub_print_error ();
+ return 0;
+ }
+ }
else
- ofdata->path = grub_malloc (grub_strlen (alias->path) + 1);
+ {
+ if (grub_add (grub_strlen (alias->path), 1, &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obatining size of ofdata path"));
+ grub_print_error ();
+ return 0;
+ }
+ }
if (!ofdata->path)
{
grub_print_error ();
diff --git a/grub-core/net/net.c b/grub-core/net/net.c
index 6c8dfcba2..22224453f 100644
--- a/grub-core/net/net.c
+++ b/grub-core/net/net.c
@@ -32,6 +32,7 @@
#include <grub/loader.h>
#include <grub/bufio.h>
#include <grub/kernel.h>
+#include <grub/safemath.h>
#ifdef GRUB_MACHINE_EFI
#include <grub/net/efi.h>
#endif
@@ -211,6 +212,7 @@ grub_net_ipv6_get_slaac (struct grub_net_card *card,
{
struct grub_net_slaac_mac_list *slaac;
char *ptr;
+ grub_size_t sz;
for (slaac = card->slaac_list; slaac; slaac = slaac->next)
if (grub_net_hwaddr_cmp (&slaac->address, hwaddr) == 0)
@@ -220,9 +222,16 @@ grub_net_ipv6_get_slaac (struct grub_net_card *card,
if (!slaac)
return NULL;
- slaac->name = grub_malloc (grub_strlen (card->name)
- + GRUB_NET_MAX_STR_HWADDR_LEN
- + sizeof (":slaac"));
+ if (grub_add (grub_strlen (card->name),
+ (GRUB_NET_MAX_STR_HWADDR_LEN + sizeof (":slaac")), &sz))
+ {
+ grub_free (slaac);
+ grub_error (GRUB_ERR_OUT_OF_RANGE,
+ "overflow detected while obtaining size of slaac name");
+ return NULL;
+ }
+
+ slaac->name = grub_malloc (sz);
ptr = grub_stpcpy (slaac->name, card->name);
if (grub_net_hwaddr_cmp (&card->default_address, hwaddr) != 0)
{
@@ -293,6 +302,7 @@ grub_net_ipv6_get_link_local (struct grub_net_card *card,
char *name;
char *ptr;
grub_net_network_level_address_t addr;
+ grub_size_t sz;
addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
addr.ipv6[0] = grub_cpu_to_be64_compile_time (0xfe80ULL << 48);
@@ -307,9 +317,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;
@@ -1516,9 +1531,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;
@@ -1773,6 +1794,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)
@@ -1780,7 +1802,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);

View file

@ -0,0 +1,45 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lidong Chen <lidong.chen@oracle.com>
Date: Wed, 22 Jan 2025 18:04:43 +0000
Subject: [PATCH] net: Prevent overflows when allocating memory for arrays
Use grub_calloc() when allocating memory for arrays to ensure proper
overflow checks are in place.
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/net/dns.c | 4 ++--
grub-core/net/net.c | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/grub-core/net/dns.c b/grub-core/net/dns.c
index 39b0c46cf..f20cd6f83 100644
--- a/grub-core/net/dns.c
+++ b/grub-core/net/dns.c
@@ -470,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/net.c b/grub-core/net/net.c
index 22224453f..d426ad2c4 100644
--- a/grub-core/net/net.c
+++ b/grub-core/net/net.c
@@ -91,8 +91,8 @@ grub_net_link_layer_add_address (struct grub_net_card *card,
/* Add sender to cache table. */
if (card->link_layer_table == NULL)
{
- card->link_layer_table = grub_zalloc (LINK_LAYER_CACHE_SIZE
- * sizeof (card->link_layer_table[0]));
+ card->link_layer_table = grub_calloc (LINK_LAYER_CACHE_SIZE,
+ sizeof (card->link_layer_table[0]));
if (card->link_layer_table == NULL)
return;
}

View file

@ -0,0 +1,31 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alec Brown <alec.r.brown@oracle.com>
Date: Wed, 22 Jan 2025 18:04:44 +0000
Subject: [PATCH] net: Check if returned pointer for allocated memory is NULL
When using grub_malloc(), the function can fail if we are out of memory.
After allocating memory we should check if this function returned NULL
and handle this error if it did.
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/net/net.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/grub-core/net/net.c b/grub-core/net/net.c
index d426ad2c4..bec297cb6 100644
--- a/grub-core/net/net.c
+++ b/grub-core/net/net.c
@@ -232,6 +232,11 @@ grub_net_ipv6_get_slaac (struct grub_net_card *card,
}
slaac->name = grub_malloc (sz);
+ if (slaac->name == NULL)
+ {
+ grub_free (slaac);
+ return NULL;
+ }
ptr = grub_stpcpy (slaac->name, card->name);
if (grub_net_hwaddr_cmp (&card->default_address, hwaddr) != 0)
{

View file

@ -0,0 +1,32 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alec Brown <alec.r.brown@oracle.com>
Date: Tue, 28 Jan 2025 05:15:50 +0000
Subject: [PATCH] fs/sfs: Check if allocated memory is NULL
When using grub_zalloc(), if we are out of memory, this function can fail.
After allocating memory, we should check if grub_zalloc() returns NULL.
If so, we should handle this error.
Fixes: CID 473856
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Ross Philipson <ross.philipson@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/sfs.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/grub-core/fs/sfs.c b/grub-core/fs/sfs.c
index 88705b3a2..bad4ae8d1 100644
--- a/grub-core/fs/sfs.c
+++ b/grub-core/fs/sfs.c
@@ -429,6 +429,9 @@ grub_sfs_mount (grub_disk_t disk)
- 24 /* offsetof (struct grub_sfs_objc, objects) */
- 25); /* offsetof (struct grub_sfs_obj, filename) */
data->label = grub_zalloc (max_len + 1);
+ if (data->label == NULL)
+ goto fail;
+
grub_strncpy (data->label, (char *) rootobjc->objects[0].filename, max_len);
grub_free (rootobjc_data);

View file

@ -0,0 +1,32 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lidong Chen <lidong.chen@oracle.com>
Date: Wed, 29 Jan 2025 06:48:37 +0000
Subject: [PATCH] script/execute: Fix potential underflow and NULL dereference
The result is initialized to 0 in grub_script_arglist_to_argv().
If the for loop condition is not met both result.args and result.argc
remain 0 causing result.argc - 1 to underflow and/or result.args NULL
dereference. Fix the issues by adding relevant checks.
Fixes: CID 473880
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/script/execute.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c
index 7ed3a1a03..014132703 100644
--- a/grub-core/script/execute.c
+++ b/grub-core/script/execute.c
@@ -794,6 +794,9 @@ cleanup:
}
}
+ if (result.args == NULL || result.argc == 0)
+ goto fail;
+
if (! result.args[result.argc - 1])
result.argc--;

View file

@ -0,0 +1,35 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lidong Chen <lidong.chen@oracle.com>
Date: Wed, 29 Jan 2025 06:48:38 +0000
Subject: [PATCH] osdep/unix/getroot: Fix potential underflow
The entry_len is initialized in grub_find_root_devices_from_mountinfo()
to 0 before the while loop iterates through /proc/self/mountinfo. If the
file is empty or contains only invalid entries entry_len remains
0 causing entry_len - 1 in the subsequent for loop initialization
to underflow. To prevent this add a check to ensure entry_len > 0 before
entering the for loop.
Fixes: CID 473877
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Reviewed-by: Ross Philipson <ross.philipson@oracle.com>
---
grub-core/osdep/linux/getroot.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c
index b32582eb3..b83259321 100644
--- a/grub-core/osdep/linux/getroot.c
+++ b/grub-core/osdep/linux/getroot.c
@@ -596,6 +596,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--)
{

View file

@ -0,0 +1,55 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lidong Chen <lidong.chen@oracle.com>
Date: Tue, 21 Jan 2025 19:02:39 +0000
Subject: [PATCH] misc: Ensure consistent overflow error messages
Update the overflow error messages to make them consistent
across the GRUB code.
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/ntfs.c | 2 +-
grub-core/fs/ntfscomp.c | 2 +-
grub-core/video/readers/png.c | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c
index e00349b1d..960833a34 100644
--- a/grub-core/fs/ntfs.c
+++ b/grub-core/fs/ntfs.c
@@ -574,7 +574,7 @@ retry:
goto retry;
}
}
- return grub_error (GRUB_ERR_BAD_FS, "run list overflown");
+ return grub_error (GRUB_ERR_BAD_FS, "run list overflow");
}
ctx->curr_vcn = ctx->next_vcn;
ctx->next_vcn += read_run_data (run, c1, 0); /* length of current VCN */
diff --git a/grub-core/fs/ntfscomp.c b/grub-core/fs/ntfscomp.c
index f168a318e..b68bf5e40 100644
--- a/grub-core/fs/ntfscomp.c
+++ b/grub-core/fs/ntfscomp.c
@@ -30,7 +30,7 @@ static grub_err_t
decomp_nextvcn (struct grub_ntfs_comp *cc)
{
if (cc->comp_head >= cc->comp_tail)
- return grub_error (GRUB_ERR_BAD_FS, "compression block overflown");
+ return grub_error (GRUB_ERR_BAD_FS, "compression block overflow");
if (grub_disk_read
(cc->disk,
(cc->comp_table[cc->comp_head].next_lcn -
diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c
index 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)
{

View file

@ -0,0 +1,30 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alec Brown <alec.r.brown@oracle.com>
Date: Tue, 4 Feb 2025 15:11:10 +0000
Subject: [PATCH] bus/usb/ehci: Define GRUB_EHCI_TOGGLE as grub_uint32_t
The Coverity indicates that GRUB_EHCI_TOGGLE is an int that contains
a negative value and we are using it for the variable token which is
grub_uint32_t. To remedy this we can cast the definition to grub_uint32_t.
Fixes: CID 473851
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/bus/usb/ehci.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/grub-core/bus/usb/ehci.c b/grub-core/bus/usb/ehci.c
index 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
{

View file

@ -0,0 +1,41 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alec Brown <alec.r.brown@oracle.com>
Date: Tue, 4 Feb 2025 15:11:11 +0000
Subject: [PATCH] normal/menu: Use safe math to avoid an integer overflow
The Coverity indicates that the variable current_entry might overflow.
To prevent this use safe math when adding GRUB_MENU_PAGE_SIZE to current_entry.
On the occasion fix limiting condition which was broken.
Fixes: CID 473853
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/normal/menu.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
index cda10fa8b..97687013c 100644
--- a/grub-core/normal/menu.c
+++ b/grub-core/normal/menu.c
@@ -32,6 +32,7 @@
#include <grub/script_sh.h>
#include <grub/gfxterm.h>
#include <grub/dl.h>
+#include <grub/safemath.h>
/* Time to delay after displaying an error message about a default/fallback
entry failing to boot. */
@@ -784,9 +785,7 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot, int *notify_boot)
case GRUB_TERM_CTRL | 'c':
case GRUB_TERM_KEY_NPAGE:
- if (current_entry + GRUB_MENU_PAGE_SIZE < menu->size)
- current_entry += GRUB_MENU_PAGE_SIZE;
- else
+ if (grub_add (current_entry, GRUB_MENU_PAGE_SIZE, &current_entry) || current_entry >= menu->size)
current_entry = menu->size - 1;
menu_set_chosen_entry (current_entry);
break;

View file

@ -0,0 +1,46 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lidong Chen <lidong.chen@oracle.com>
Date: Thu, 6 Feb 2025 18:16:56 +0000
Subject: [PATCH] kern/partition: Add sanity check after grub_strtoul() call
The current code incorrectly assumes that both the input and the values
returned by grub_strtoul() are always valid which can lead to potential
errors. This fix ensures proper validation to prevent any unintended issues.
Fixes: CID 473843
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/kern/partition.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/grub-core/kern/partition.c b/grub-core/kern/partition.c
index 704512a20..c6a578cf4 100644
--- a/grub-core/kern/partition.c
+++ b/grub-core/kern/partition.c
@@ -125,14 +125,22 @@ grub_partition_probe (struct grub_disk *disk, const char *str)
for (ptr = str; *ptr;)
{
grub_partition_map_t partmap;
- int num;
+ unsigned long num;
const char *partname, *partname_end;
partname = ptr;
while (*ptr && grub_isalpha (*ptr))
ptr++;
partname_end = ptr;
- num = grub_strtoul (ptr, &ptr, 0) - 1;
+
+ num = grub_strtoul (ptr, &ptr, 0);
+ if (*ptr != '\0' || num == 0 || num > GRUB_INT_MAX)
+ {
+ grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid partition number"));
+ return 0;
+ }
+
+ num -= 1;
curpart = 0;
/* Use the first partition map type found. */

View file

@ -0,0 +1,57 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lidong Chen <lidong.chen@oracle.com>
Date: Thu, 6 Feb 2025 18:16:57 +0000
Subject: [PATCH] kern/misc: Add sanity check after grub_strtoul() call
When the format string, fmt0, includes a positional argument
grub_strtoul() or grub_strtoull() is called to extract the argument
position. However, the returned argument position isn't fully validated.
If the format is something like "%0$x" then these functions return
0 which leads to an underflow in the calculation of the args index, curn.
The fix is to add a check to ensure the extracted argument position is
greater than 0 before computing curn. Additionally, replace one
grub_strtoull() with grub_strtoul() and change curn type to make code
more correct.
Fixes: CID 473841
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/kern/misc.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
index 98700423d..69bd655f3 100644
--- a/grub-core/kern/misc.c
+++ b/grub-core/kern/misc.c
@@ -912,7 +912,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 != '%')
@@ -930,7 +930,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++;
}
@@ -1116,6 +1119,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;

View file

@ -0,0 +1,30 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alec Brown <alec.r.brown@oracle.com>
Date: Wed, 12 Feb 2025 10:56:13 -0600
Subject: [PATCH] loader/i386/linux: Cast left shift to grub_uint32_t
The Coverity complains that we might overflow into a negative value when
setting linux_params.kernel_alignment to (1 << align). We can remedy
this by casting it to grub_uint32_t.
Fixes: CID 473876
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/loader/i386/linux.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c
index 90121e9bc..33a852197 100644
--- a/grub-core/loader/i386/linux.c
+++ b/grub-core/loader/i386/linux.c
@@ -823,7 +823,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W, GRUB_MEM_ATTR_X);
linux_params.code32_start = prot_mode_target + lh.code32_start - GRUB_LINUX_BZIMAGE_ADDR;
- linux_params.kernel_alignment = (1 << align);
+ linux_params.kernel_alignment = ((grub_uint32_t)1 << align);
linux_params.ps_mouse = linux_params.padding11 = 0;
linux_params.type_of_loader = GRUB_LINUX_BOOT_LOADER_TYPE;

View file

@ -0,0 +1,56 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alec Brown <alec.r.brown@oracle.com>
Date: Wed, 5 Feb 2025 22:04:08 +0000
Subject: [PATCH] loader/i386/bsd: Use safe math to avoid underflow
The operation kern_end - kern_start may underflow when we input it into
grub_relocator_alloc_chunk_addr() call. To avoid this we can use safe
math for this subtraction.
Fixes: CID 73845
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/loader/i386/bsd.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c
index 8075ac9b0..50f96ea7a 100644
--- a/grub-core/loader/i386/bsd.c
+++ b/grub-core/loader/i386/bsd.c
@@ -1341,6 +1341,7 @@ static grub_err_t
grub_bsd_load_elf (grub_elf_t elf, const char *filename)
{
grub_err_t err;
+ grub_size_t sz;
kern_end = 0;
kern_start = ~0;
@@ -1371,8 +1372,11 @@ grub_bsd_load_elf (grub_elf_t elf, const char *filename)
if (grub_errno)
return grub_errno;
- err = grub_relocator_alloc_chunk_addr (relocator, &ch,
- kern_start, kern_end - kern_start);
+
+ if (grub_sub (kern_end, kern_start, &sz))
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "underflow detected while determining size of kernel for relocator");
+
+ err = grub_relocator_alloc_chunk_addr (relocator, &ch, kern_start, sz);
if (err)
return err;
@@ -1432,8 +1436,10 @@ grub_bsd_load_elf (grub_elf_t elf, const char *filename)
{
grub_relocator_chunk_t ch;
- err = grub_relocator_alloc_chunk_addr (relocator, &ch, kern_start,
- kern_end - kern_start);
+ if (grub_sub (kern_end, kern_start, &sz))
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "underflow detected while determining size of kernel for relocator");
+
+ err = grub_relocator_alloc_chunk_addr (relocator, &ch, kern_start, sz);
if (err)
return err;
kern_chunk_src = get_virtual_current_address (ch);

View file

@ -0,0 +1,65 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Michael Chang via Grub-devel <grub-devel@gnu.org>
Date: Fri, 21 Feb 2025 09:06:12 +0800
Subject: [PATCH] fs/ext2: Rework out-of-bounds read for inline and external
extents
Previously, the number of extent entries was not properly capped based
on the actual available space. This could lead to insufficient reads for
external extents, since the computation was based solely on the inline
extent layout.
In this patch, when processing the extent header, we determine whether
the header is stored inline (i.e., at inode->blocks.dir_blocks) or in an
external extent block. We then clamp the number of entries accordingly
(using max_inline_ext for inline extents and max_external_ext for
external extent blocks).
This change ensures that only the valid number of extent entries is
processed, preventing out-of-bound reads and potential filesystem
corruption.
Fixes: 7e2f750f0a (fs/ext2: Fix out-of-bounds read for inline extents)
Signed-off-by: Michael Chang <mchang@suse.com>
Tested-by: Christian Hesse <mail@eworm.de>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/ext2.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/grub-core/fs/ext2.c b/grub-core/fs/ext2.c
index c3058f7..a5650c3 100644
--- a/grub-core/fs/ext2.c
+++ b/grub-core/fs/ext2.c
@@ -496,7 +496,10 @@ grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
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)
@@ -513,8 +516,18 @@ grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
nent = grub_le_to_cpu16 (leaf->entries);
- if (leaf->depth == 0)
+ /*
+ * Determine the effective number of extent entries (nent) to process:
+ * If the extent header (leaf) is stored inline in the inodes 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++)
{

View file

@ -0,0 +1,117 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Avnish Chouhan <avnish@linux.ibm.com>
Date: Thu, 13 Mar 2025 19:45:50 +0530
Subject: [PATCH] powerpc: increase MIN RMA size for CAS negotiation
Change RMA size from 512 MB to 768 MB which will result
in more memory at boot time for PowerPC. When vTPM, Secure Boot or
FADump are enabled on PowerPC, the 512 MB RMA memory is not sufficient for
booting. With this 512 MB RMA, GRUB2 runs out of memory and fails to
boot the machine. Sometimes even usage of CDROM requires more memory
for installation and along with the options mentioned above exhausts
the boot memory which results in boot failures. Increasing the RMA size
will resolves multiple out of memory issues observed in PowerPC.
Failure details (GRUB2 debugs):
kern/ieee1275/init.c:550: mm requested region of size 8513000, flags 1
kern/ieee1275/init.c:563: Cannot satisfy allocation and retain minimum runtime space
kern/ieee1275/init.c:550: mm requested region of size 8513000, flags 0
kern/ieee1275/init.c:563: Cannot satisfy allocation and retain minimum runtime space
kern/file.c:215: Closing `/ppc/ppc64/initrd.img' ...
kern/disk.c:297: Closing `ieee1275//vdevice/v-scsi@30000067/disk@8300000000000000'...
kern/disk.c:311: Closing `ieee1275//vdevice/v-scsi@30000067/disk@8300000000000000' succeeded.
kern/file.c:225: Closing `/ppc/ppc64/initrd.img' failed with 3.
kern/file.c:148: Opening `/ppc/ppc64/initrd.img' succeeded.
error: ../../grub-core/kern/mm.c:552:out of memory.
Signed-off-by: Avnish Chouhan <avnish@linux.ibm.com>
---
grub-core/kern/ieee1275/init.c | 51 +++++++++++++++++++++++++++++++++++++-----
1 file changed, 46 insertions(+), 5 deletions(-)
diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
index 4ec6598cfbb8..bb791f80f41c 100644
--- a/grub-core/kern/ieee1275/init.c
+++ b/grub-core/kern/ieee1275/init.c
@@ -737,7 +737,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.
*/
@@ -809,7 +809,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 */
@@ -846,6 +846,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);
@@ -858,11 +862,48 @@ 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 */
- if (err == GRUB_ERR_NONE && rmo_top < (512 * 1024 * 1024))
- grub_ieee1275_ibm_cas ();
+ /*
+ * 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

View file

@ -0,0 +1,66 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: James Le Cuirot <jlecuirot@microsoft.com>
Date: Thu, 24 Oct 2024 14:42:46 +0100
Subject: [PATCH] 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 <jlecuirot@microsoft.com>
---
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 014132703..3d26a3fe4 100644
--- a/grub-core/script/execute.c
+++ b/grub-core/script/execute.c
@@ -952,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/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.48.1

View file

@ -0,0 +1,45 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: James Le Cuirot <jlecuirot@microsoft.com>
Date: Thu, 24 Oct 2024 15:00:26 +0100
Subject: [PATCH] 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 <jlecuirot@microsoft.com>
---
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 97687013c..a2703dabb 100644
--- a/grub-core/normal/menu.c
+++ b/grub-core/normal/menu.c
@@ -377,14 +377,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.48.1

View file

@ -0,0 +1,32 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nicolas Frayer <nfrayer@redhat.com>
Date: Wed, 19 Mar 2025 17:39:41 +0100
Subject: [PATCH] ieee1275/ofnet: Fix grub_malloc() removed after added safe
math functions
grub_malloc() has been inadvertently removed from the ieee1275/ofnet
code after it has been modified to use safe match function.
Fixes: 4beeff8a (net: Use safe math macros to prevent overflows)
Tested-by: Marta Lewandowska <mlewando@redhat.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Signed-off-by: Nicolas Frayer <nfrayer@redhat.com>
---
grub-core/net/drivers/ieee1275/ofnet.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/grub-core/net/drivers/ieee1275/ofnet.c b/grub-core/net/drivers/ieee1275/ofnet.c
index 3e1b9094e2ab..37bc82467f60 100644
--- a/grub-core/net/drivers/ieee1275/ofnet.c
+++ b/grub-core/net/drivers/ieee1275/ofnet.c
@@ -463,6 +463,9 @@ search_net_devices (struct grub_ieee1275_devalias *alias)
return 0;
}
}
+
+ ofdata->path = grub_malloc(sz);
+
if (!ofdata->path)
{
grub_print_error ();

View file

@ -0,0 +1,167 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Wed, 23 Oct 2024 17:54:32 +0530
Subject: [PATCH] grub-mkimage: Create new ELF note for SBAT
In order to store the SBAT data we create a new ELF note. The string
".sbat", zero-padded to 4 byte alignment, shall be entered in the name
field. The string "SBAT"'s ASCII values, 0x53424154, should be entered
in the type field.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
include/grub/util/mkimage.h | 4 ++--
util/grub-mkimagexx.c | 48 +++++++++++++++++++++++++++++++++++++++++++--
util/mkimage.c | 5 +++--
3 files changed, 51 insertions(+), 6 deletions(-)
diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h
index 6f1da89b9b65..881e3031f41f 100644
--- a/include/grub/util/mkimage.h
+++ b/include/grub/util/mkimage.h
@@ -51,12 +51,12 @@ grub_mkimage_load_image64 (const char *kernel_path,
const struct grub_install_image_target_desc *image_target);
void
grub_mkimage_generate_elf32 (const struct grub_install_image_target_desc *image_target,
- int note, size_t appsig_size, char **core_img, size_t *core_size,
+ int note, size_t appsig_size, char *sbat, char **core_img, size_t *core_size,
Elf32_Addr target_addr,
struct grub_mkimage_layout *layout);
void
grub_mkimage_generate_elf64 (const struct grub_install_image_target_desc *image_target,
- int note, size_t appsig_size, char **core_img, size_t *core_size,
+ int note, size_t appsig_size, char *sbat, char **core_img, size_t *core_size,
Elf64_Addr target_addr,
struct grub_mkimage_layout *layout);
diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c
index 9488f052510a..b9930544889d 100644
--- a/util/grub-mkimagexx.c
+++ b/util/grub-mkimagexx.c
@@ -116,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)
{
@@ -217,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, 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)
{
@@ -226,10 +234,17 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
Elf_Ehdr *ehdr;
Elf_Phdr *phdr;
Elf_Shdr *shdr;
- int header_size, footer_size = 0;
+ int header_size, footer_size = 0, footer_offset = 0;
int phnum = 1;
int shnum = 4;
int string_size = sizeof (".text") + sizeof ("mods") + 1;
+ char *footer;
+
+ if (sbat)
+ {
+ phnum++;
+ footer_size += ALIGN_UP (sizeof (struct grub_sbat_note) + layout->sbat_size, 4);
+ }
if (appsig_size)
{
@@ -263,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)
@@ -435,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)
@@ -468,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)
@@ -498,6 +518,30 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
phdr->p_filesz = grub_host_to_target32 (note_size);
phdr->p_memsz = 0;
phdr->p_offset = grub_host_to_target32 (header_size + program_size);
+ footer = (elf_img + program_size + header_size + note_size);
+ footer_offset += note_size;
+ }
+
+ if (sbat)
+ {
+ int note_size = ALIGN_UP (sizeof (struct grub_sbat_note) + layout->sbat_size, 4);
+ struct grub_sbat_note *note_ptr = (struct grub_sbat_note *) footer;
+
+ note_ptr->header.n_namesz = grub_host_to_target32 (sizeof (GRUB_SBAT_NOTE_NAME));
+ note_ptr->header.n_descsz = grub_host_to_target32 (ALIGN_UP(layout->sbat_size, 4));
+ note_ptr->header.n_type = grub_host_to_target32 (GRUB_SBAT_NOTE_TYPE);
+ memcpy (note_ptr->name, GRUB_SBAT_NOTE_NAME, sizeof (GRUB_SBAT_NOTE_NAME));
+ memcpy ((char *)(note_ptr + 1), sbat, layout->sbat_size);
+
+ phdr++;
+ phdr->p_type = grub_host_to_target32 (PT_NOTE);
+ phdr->p_flags = grub_host_to_target32 (PF_R);
+ phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof);
+ phdr->p_vaddr = 0;
+ phdr->p_paddr = 0;
+ phdr->p_filesz = grub_host_to_target32 (note_size);
+ phdr->p_memsz = 0;
+ phdr->p_offset = grub_host_to_target32 (header_size + program_size + footer_offset);
}
if (appsig_size) {
diff --git a/util/mkimage.c b/util/mkimage.c
index f31fdefa814a..7fa6a7b21954 100644
--- a/util/mkimage.c
+++ b/util/mkimage.c
@@ -1848,6 +1848,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
case IMAGE_I386_IEEE1275:
{
grub_uint64_t target_addr;
+ char *sbat = NULL;
if (image_target->id == IMAGE_LOONGSON_ELF)
{
if (comp == GRUB_COMPRESSION_NONE)
@@ -1859,10 +1860,10 @@ grub_install_generate_image (const char *dir, const char *prefix,
else
target_addr = image_target->link_addr;
if (image_target->voidp_sizeof == 4)
- grub_mkimage_generate_elf32 (image_target, note, appsig_size, &core_img,
+ grub_mkimage_generate_elf32 (image_target, note, appsig_size, sbat, &core_img,
&core_size, target_addr, &layout);
else
- grub_mkimage_generate_elf64 (image_target, note, appsig_size, &core_img,
+ grub_mkimage_generate_elf64 (image_target, note, appsig_size, sbat, &core_img,
&core_size, target_addr, &layout);
}
break;

View file

@ -0,0 +1,45 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Wed, 23 Oct 2024 17:54:33 +0530
Subject: [PATCH] grub-mkimage: Add SBAT metadata into ELF note for PowerPC
targets
The SBAT metadata is read from CSV file and transformed into an ELF note
with the -s option.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
util/mkimage.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/util/mkimage.c b/util/mkimage.c
index 7fa6a7b21954..f92949d1df25 100644
--- a/util/mkimage.c
+++ b/util/mkimage.c
@@ -957,8 +957,8 @@ grub_install_generate_image (const char *dir, const char *prefix,
total_module_size += dtb_size + sizeof (struct grub_module_header);
}
- if (sbat_path != NULL && image_target->id != IMAGE_EFI)
- grub_util_error (_(".sbat section can be embedded into EFI images only"));
+ if (sbat_path != NULL && (image_target->id != IMAGE_EFI && image_target->id != IMAGE_PPC))
+ grub_util_error (_("SBAT data can be added only to EFI or powerpc-ieee1275 images"));
if (disable_shim_lock)
total_module_size += sizeof (struct grub_module_header);
@@ -1849,6 +1849,13 @@ grub_install_generate_image (const char *dir, const char *prefix,
{
grub_uint64_t target_addr;
char *sbat = NULL;
+ if (sbat_path != NULL)
+ {
+ sbat_size = grub_util_get_image_size (sbat_path);
+ sbat = xmalloc (sbat_size);
+ grub_util_load_image (sbat_path, sbat);
+ layout.sbat_size = sbat_size;
+ }
if (image_target->id == IMAGE_LOONGSON_ELF)
{
if (comp == GRUB_COMPRESSION_NONE)

View file

@ -0,0 +1,47 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Leo Sandoval <lsandova@redhat.com>
Date: Wed, 7 May 2025 13:23:37 -0600
Subject: [PATCH] 10_linux.in: escape kernel option characters properly
This handles cases where kernel options, specifically the values,
contain special characters, in this case ';', '&' and '$'.
For example, the user defines the following GRUB_CMDLINE_LINUX on the
default grub file /etc/default/grub, note the dolar sign on the 'memmap'
option
GRUB_CMDLINE_LINUX="console=ttyS0 memmap=32g\\\$0x2000000000"
then regenerating the grub cfg and BLS options line with the
grub2-mkconfig command, resulting into
options root=UUID=6baedf23-2510-499a-815d-48b58cf6e619 ro
rootflags=subvol=root console=ttyS0 memmap=32g\$0x2000000000
without this patch, we would end up with
options root=UUID=6baedf23-2510-499a-815d-48b58cf6e619 ro
rootflags=subvol=root console=ttyS0 memmap=32g$0x2000000000
Note the missing '\' which is required to escape the '$', otherwise
it would be consider a variable by blscfg parser which is not the case.
Signed-off-by: Leo Sandoval <lsandova@redhat.com>
---
util/grub.d/10_linux.in | 3 +++
1 file changed, 3 insertions(+)
diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
index 11c19304f8..cdfb72a1e3 100644
--- a/util/grub.d/10_linux.in
+++ b/util/grub.d/10_linux.in
@@ -178,6 +178,9 @@ update_bls_cmdline()
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
}

View file

@ -0,0 +1,26 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Leo Sandoval <lsandova@redhat.com>
Date: Wed, 7 May 2025 13:49:47 -0600
Subject: [PATCH] blscfg: check if variable is escaped before considering one
Otherwise escaped variables are considered real variables.
Signed-off-by: Leo Sandoval <lsandova@redhat.com>
---
grub-core/commands/blscfg.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
index 6e398fc175..5d931b0c9b 100644
--- a/grub-core/commands/blscfg.c
+++ b/grub-core/commands/blscfg.c
@@ -695,7 +695,8 @@ static char *expand_val(const char *value)
return NULL;
while (*value) {
- if (*value == '$') {
+ /* It's a variable only when *value is '$' and it is not escaped with '\'*/
+ if (*value == '$' && *end != '\\') {
if (start != end) {
buffer = field_append(is_var, buffer, start, end);
if (!buffer)

View file

@ -0,0 +1,30 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Maxim Suhanov <dfirblog@gmail.com>
Date: Fri, 28 Feb 2025 17:00:53 +0300
Subject: [PATCH] kern/rescue_reader: Block the rescue mode until the CLI
authentication
This further mitigates potential misuse of the CLI after the
root device has been successfully unlocked via TPM.
Fixes: CVE-2025-4382
Signed-off-by: Maxim Suhanov <dfirblog@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/kern/rescue_reader.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/grub-core/kern/rescue_reader.c b/grub-core/kern/rescue_reader.c
index 4259857ba9..a71ada8fb7 100644
--- a/grub-core/kern/rescue_reader.c
+++ b/grub-core/kern/rescue_reader.c
@@ -79,7 +79,7 @@ void __attribute__ ((noreturn))
grub_rescue_run (void)
{
/* Stall if the CLI has been disabled */
- if (grub_is_cli_disabled ())
+ if (grub_is_cli_disabled () || grub_is_cli_need_auth ())
{
grub_printf ("Rescue mode has been disabled...\n");

View file

@ -0,0 +1,133 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Maxim Suhanov <dfirblog@gmail.com>
Date: Sat, 1 Mar 2025 14:16:48 +0300
Subject: [PATCH] commands/search: Introduce the --cryptodisk-only argument
This allows users to restrict the "search" command's scope to
encrypted disks only.
Typically, this command is used to "rebase" $root and $prefix
before loading additional configuration files via "source" or
"configfile". Unfortunately, this leads to security problems,
like CVE-2023-4001, when an unexpected, attacker-controlled
device is chosen by the "search" command.
The --cryptodisk-only argument allows users to ensure that the
file system picked is encrypted.
This feature supports the CLI authentication, blocking bypass
attempts.
Signed-off-by: Maxim Suhanov <dfirblog@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/commands/search.c | 20 ++++++++++++++++++++
grub-core/commands/search_wrap.c | 7 ++++++-
grub-core/normal/main.c | 3 ++-
include/grub/search.h | 9 +++++----
4 files changed, 33 insertions(+), 6 deletions(-)
diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c
index d538b36219..84362b54b3 100644
--- a/grub-core/commands/search.c
+++ b/grub-core/commands/search.c
@@ -182,6 +182,26 @@ 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 || dev->disk->dev->id != GRUB_DISK_DEVICE_CRYPTODISK_ID)
+ {
+ 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)
{
diff --git a/grub-core/commands/search_wrap.c b/grub-core/commands/search_wrap.c
index 4fe6440c65..ec2fb638f1 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[] =
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, "
@@ -76,6 +77,7 @@ enum options
SEARCH_SET,
SEARCH_NO_FLOPPY,
SEARCH_EFIDISK_ONLY,
+ SEARCH_CRYPTODISK_ONLY,
SEARCH_ROOTDEV_ONLY,
SEARCH_HINT,
SEARCH_HINT_IEEE1275,
@@ -191,6 +193,9 @@ 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;
@@ -215,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/normal/main.c b/grub-core/normal/main.c
index dd20e51290..6f7290a897 100644
--- a/grub-core/normal/main.c
+++ b/grub-core/normal/main.c
@@ -615,7 +615,8 @@ 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)
diff --git a/include/grub/search.h b/include/grub/search.h
index 9343c66b13..b6b5c8be1f 100644
--- a/include/grub/search.h
+++ b/include/grub/search.h
@@ -21,10 +21,11 @@
enum search_flags
{
- SEARCH_FLAGS_NONE = 0,
- SEARCH_FLAGS_NO_FLOPPY = 1,
- 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,

View file

@ -0,0 +1,133 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Maxim Suhanov <dfirblog@gmail.com>
Date: Sun, 2 Mar 2025 18:08:22 +0300
Subject: [PATCH] disk/diskfilter: Introduce the "cryptocheck" command
This command examines a given diskfilter device, e.g., an LVM disk,
and checks if underlying disks, physical volumes, are cryptodisks,
e.g., LUKS disks, this layout is called "LVM-on-LUKS".
The return value is 0 when all underlying disks (of a given device)
are cryptodisks (1 if at least one disk is unencrypted or in an
unknown state).
Users are encouraged to include the relevant check before loading
anything from an LVM disk that is supposed to be encrypted.
This further supports the CLI authentication, blocking bypass
attempts when booting from an encrypted LVM disk.
Signed-off-by: Maxim Suhanov <dfirblog@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/disk/diskfilter.c | 75 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 75 insertions(+)
diff --git a/grub-core/disk/diskfilter.c b/grub-core/disk/diskfilter.c
index fef0b815ab..216be6a782 100644
--- a/grub-core/disk/diskfilter.c
+++ b/grub-core/disk/diskfilter.c
@@ -20,6 +20,7 @@
#include <grub/dl.h>
#include <grub/disk.h>
#include <grub/mm.h>
+#include <grub/command.h>
#include <grub/err.h>
#include <grub/misc.h>
#include <grub/diskfilter.h>
@@ -1365,6 +1366,73 @@ 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;
+
+ 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);
+
+ 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",
@@ -1381,14 +1449,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_("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 ();
}

View file

@ -0,0 +1,67 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Maxim Suhanov <dfirblog@gmail.com>
Date: Sun, 2 Mar 2025 23:32:43 +0300
Subject: [PATCH] commands/search: Add the diskfilter support
When the --cryptodisk-only argument is given, also check the target
device using the "cryptocheck" command, if available.
This extends the checks to common layouts like LVM-on-LUKS, so the
--cryptodisk-only argument transparently handles such setups.
Signed-off-by: Maxim Suhanov <dfirblog@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/commands/search.c | 32 +++++++++++++++++++++++++++++++-
1 file changed, 31 insertions(+), 1 deletion(-)
diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c
index 84362b54b3..1cf714ad7d 100644
--- a/grub-core/commands/search.c
+++ b/grub-core/commands/search.c
@@ -150,6 +150,36 @@ check_for_duplicate (const char *name, void *data)
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)
+ {
+ 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);
+ res = cmd->func (cmd, 1, &disk_str);
+ 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)
@@ -193,7 +223,7 @@ iterate_device (const char *name, void *data)
grub_errno = GRUB_ERR_NONE;
return 0;
}
- if (dev->disk == NULL || dev->disk->dev->id != GRUB_DISK_DEVICE_CRYPTODISK_ID)
+ if (dev->disk == NULL || is_unencrypted_disk (dev->disk) == true)
{
grub_device_close (dev);
grub_errno = GRUB_ERR_NONE;

View file

@ -0,0 +1,68 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Maxim Suhanov <dfirblog@gmail.com>
Date: Mon, 10 Mar 2025 15:33:46 +0300
Subject: [PATCH] docs: Document available crypto disks checks
Document the --cryptodisk-only argument. Also, document the
"cryptocheck" command invoked when that argument is processed.
Signed-off-by: Maxim Suhanov <dfirblog@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
docs/grub.texi | 22 +++++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/docs/grub.texi b/docs/grub.texi
index 2d6d73a78d..93e23be99d 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -4365,6 +4365,7 @@ 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
@@ -4674,6 +4675,16 @@ 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 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.
+@end deffn
@node cryptomount
@subsection cryptomount
@@ -5522,7 +5533,8 @@ unbootable. @xref{Using GPG-style 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}).
@@ -5537,6 +5549,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.

View file

@ -0,0 +1,147 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Maxim Suhanov <dfirblog@gmail.com>
Date: Tue, 6 May 2025 12:25:20 -0600
Subject: [PATCH] disk/cryptodisk: Add the "erase secrets" function
This commit adds the grub_cryptodisk_erasesecrets() function to wipe
master keys from all cryptodisks. This function is EFI-only.
Since there is no easy way to "force unmount" a given encrypted disk,
this function renders all mounted cryptodisks unusable. An attempt to
read them will return garbage.
This is why this function must be used in "no way back" conditions.
Currently, it is used when unloading the cryptodisk module and when
performing the "exit" command (it is often used to switch to the next
EFI application). This function is not called when performing the
"chainloader" command, because the callee may return to GRUB. For this
reason, users are encouraged to use "exit" instead of "chainloader" to
execute third-party boot applications.
This function does not guarantee that all secrets are wiped from RAM.
Console output, chunks from disk read requests and other may remain.
This function does not clear the IV prefix and rekey key for geli disks.
Also, this commit adds the relevant documentation improvements.
Signed-off-by: Maxim Suhanov <dfirblog@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
docs/grub.texi | 6 ++++++
grub-core/commands/minicmd.c | 11 +++++++++++
grub-core/disk/cryptodisk.c | 28 ++++++++++++++++++++++++++++
include/grub/cryptodisk.h | 1 +
4 files changed, 46 insertions(+)
diff --git a/docs/grub.texi b/docs/grub.texi
index 93e23be99d..0af47b5ade 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -4721,6 +4721,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
@@ -6982,6 +6987,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.
diff --git a/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c
index 9efb7718c3..eb786766a8 100644
--- a/grub-core/commands/minicmd.c
+++ b/grub-core/commands/minicmd.c
@@ -29,6 +29,10 @@
#include <grub/command.h>
#include <grub/i18n.h>
+#ifdef GRUB_MACHINE_EFI
+#include <grub/cryptodisk.h>
+#endif
+
GRUB_MOD_LICENSE ("GPLv3+");
/* cat FILE */
@@ -199,6 +203,13 @@ grub_mini_cmd_exit (struct grub_command *cmd __attribute__ ((unused)),
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. */
}
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index 8727760100..9597d2d3bd 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -1677,6 +1677,31 @@ grub_cryptodisk_challenge_password (void)
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 =
@@ -1700,6 +1725,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/include/grub/cryptodisk.h b/include/grub/cryptodisk.h
index d2572f8b05..ef307dfd5d 100644
--- a/include/grub/cryptodisk.h
+++ b/include/grub/cryptodisk.h
@@ -189,5 +189,6 @@ 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

View file

@ -0,0 +1,29 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Maxim Suhanov <dfirblog@gmail.com>
Date: Tue, 4 Mar 2025 15:27:59 +0300
Subject: [PATCH] disk/cryptodisk: Wipe the passphrase from memory
Switching to another EFI boot application while there are secrets in
RAM is dangerous, because not all firmware is wiping memory on free.
To reduce the attack surface, wipe the passphrase acquired when
unlocking an encrypted volume.
Signed-off-by: Maxim Suhanov <dfirblog@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/disk/cryptodisk.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index 9597d2d3bd..26457095d3 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -1164,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);
}

View file

@ -0,0 +1,114 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Fri, 14 Mar 2025 19:03:39 +0800
Subject: [PATCH] cryptocheck: Add --quiet option
The option can be used to suppress output if we only want to test the
return value of the command.
Also, mention this option in the documentation.
Signed-off-by: Michael Chang <mchang@suse.com>
Signed-off-by: Maxim Suhanov <dfirblog@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
docs/grub.texi | 4 +++-
grub-core/commands/search.c | 7 ++++++-
grub-core/disk/diskfilter.c | 25 +++++++++++++++++++------
3 files changed, 28 insertions(+), 8 deletions(-)
diff --git a/docs/grub.texi b/docs/grub.texi
index 0af47b5ade..ae01e8c994 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -4678,12 +4678,14 @@ Alias for @code{hashsum --hash crc32 arg @dots{}}. See command @command{hashsum}
@node cryptocheck
@subsection cryptocheck
-@deffn Command cryptocheck device
+@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
diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c
index 1cf714ad7d..c432c0ac6f 100644
--- a/grub-core/commands/search.c
+++ b/grub-core/commands/search.c
@@ -163,6 +163,9 @@ is_unencrypted_disk (grub_disk_t 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;
@@ -173,7 +176,9 @@ is_unencrypted_disk (grub_disk_t disk)
return true;
grub_snprintf (disk_str, disk_str_len, "(%s)", disk->name);
- res = cmd->func (cmd, 1, &disk_str);
+ 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. */
}
diff --git a/grub-core/disk/diskfilter.c b/grub-core/disk/diskfilter.c
index 216be6a782..04b64aebc6 100644
--- a/grub-core/disk/diskfilter.c
+++ b/grub-core/disk/diskfilter.c
@@ -1402,6 +1402,19 @@ grub_cmd_cryptocheck (grub_command_t cmd __attribute__ ((unused)),
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"));
@@ -1424,11 +1437,11 @@ grub_cmd_cryptocheck (grub_command_t cmd __attribute__ ((unused)),
check_pvs_res = grub_diskfilter_check_pvs_encrypted (disk, &pvs_cnt);
grub_disk_close (disk);
-
- 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" : "");
+ 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;
}
@@ -1456,7 +1469,7 @@ GRUB_MOD_INIT(diskfilter)
{
grub_disk_dev_register (&grub_diskfilter_dev);
cmd = grub_register_command ("cryptocheck", grub_cmd_cryptocheck,
- N_("DEVICE"),
+ N_("[--quiet] DEVICE"),
N_("Check if a logical volume resides on encrypted disks."));
}

View file

@ -0,0 +1,25 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Thomas Frauendorfer | Miray Software <tf@miray.de>
Date: Wed, 21 May 2025 10:56:19 +0200
Subject: [PATCH] loader/efi/chainloader: Fix double free
Signed-off-by: Thomas Frauendorfer | Miray Software <tf@miray.de>
Reviewed-by: Nicolas Frayer <nfrayer@redhat.com>
---
grub-core/loader/efi/chainloader.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
index 7652f5a..0a78d0d 100644
--- a/grub-core/loader/efi/chainloader.c
+++ b/grub-core/loader/efi/chainloader.c
@@ -1193,9 +1193,6 @@ fail:
if (address)
grub_efi_free_pages (address, pages);
- if (cmdline)
- grub_free (cmdline);
-
if (image_handle != NULL)
grub_efi_unload_image (image_handle);

View file

@ -0,0 +1,31 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Thomas Frauendorfer | Miray Software <tf@miray.de>
Date: Tue, 20 May 2025 09:20:46 +0200
Subject: [PATCH] loader/efi/chainloader: Fix null pointer dereference
This fixes a null pointer access during netboot
introduced in
* Allow chainloading EFI apps from loop mounts.
The commit accesses dev->disk without testing it.
But when booting through network dev->disk will be NULL
Signed-off-by: Thomas Frauendorfer | Miray Software <tf@miray.de>
Reviewed-by: Nicolas Frayer <nfrayer@redhat.com>
---
grub-core/loader/efi/chainloader.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
index 0a78d0d..a004020 100644
--- a/grub-core/loader/efi/chainloader.c
+++ b/grub-core/loader/efi/chainloader.c
@@ -1006,7 +1006,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
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;

View file

@ -0,0 +1,86 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
Date: Thu, 24 Apr 2025 11:43:28 +0200
Subject: [PATCH] osdep/linux/getroot: Detect DDF container similar to IMSM
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Similarly to Intel IMSM, there are BIOS and UEFI implementations that
support DDF containers natively.
DDF and IMSM are very similar in handling, especially these should not
be considered as RAID abstraction. This fixes the requirement of having
a device map when probing DDF containers.
Fixes: https://issues.redhat.com/browse/RHEL-44336
Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/osdep/linux/getroot.c | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)
diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c
index b832593213e6..4bf386b590b5 100644
--- a/grub-core/osdep/linux/getroot.c
+++ b/grub-core/osdep/linux/getroot.c
@@ -127,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)
@@ -759,10 +759,10 @@ out:
}
static int
-grub_util_is_imsm (const char *os_dev)
+grub_util_is_imsm_or_ddf (const char *os_dev)
{
int retry;
- int is_imsm = 0;
+ int is_imsm_or_ddf = 0;
int container_seen = 0;
const char *dev = os_dev;
@@ -823,10 +823,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);
@@ -837,7 +844,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 *
@@ -1202,7 +1209,7 @@ grub_util_get_dev_abstraction_os (const char *os_dev)
/* Check for RAID. */
if (!strncmp (os_dev, "/dev/md", 7) && ! grub_util_device_is_mapped (os_dev)
- && !grub_util_is_imsm (os_dev))
+ && !grub_util_is_imsm_or_ddf (os_dev))
return GRUB_DEV_ABSTRACTION_RAID;
return GRUB_DEV_ABSTRACTION_NONE;
}

View file

@ -0,0 +1,291 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Leo Sandoval <lsandova@redhat.com>
Date: Tue, 29 Jul 2025 09:43:37 -0600
Subject: [PATCH] Set correctly the memory attributes for the kernel PE
sections
Currently the whole kernel memory region is set to RO, so at some
point when execution is passed to the kernel, the latter faults on a
memory write access, e.g. zeroing .bss section. The proposed change
sets the memory attribute appropriately for each kernel PE section.
Signed-off-by: Leo Sandoval <lsandova@redhat.com>
---
grub-core/loader/efi/linux.c | 170 +++++++++++++++++++++++++++-----------
grub-core/loader/i386/efi/linux.c | 5 +-
include/grub/efi/linux.h | 6 ++
3 files changed, 134 insertions(+), 47 deletions(-)
diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
index ef55556f2d..111edf0e1d 100644
--- a/grub-core/loader/efi/linux.c
+++ b/grub-core/loader/efi/linux.c
@@ -36,6 +36,7 @@
#include <grub/efi/sb.h>
#include <grub/i18n.h>
#include <grub/lib/cmdline.h>
+#include <grub/safemath.h>
#include <grub/verify.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -202,22 +203,133 @@ grub_efi_check_nx_required (int *nx_required)
typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *);
grub_err_t
-grub_efi_linux_boot (grub_addr_t 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
@@ -241,47 +353,13 @@ grub_efi_linux_boot (grub_addr_t k_address, grub_size_t k_size,
if (nx_required && !nx_supported)
return grub_error (GRUB_ERR_BAD_OS, N_("kernel does not support NX loading required by policy"));
- if (nx_supported)
- {
- kernel_set_attrs &= ~GRUB_MEM_ATTR_W;
- kernel_clear_attrs |= GRUB_MEM_ATTR_W;
- stack_set_attrs &= ~GRUB_MEM_ATTR_X;
- stack_clear_attrs |= GRUB_MEM_ATTR_X;
- }
-
- grub_dprintf ("nx", "Setting attributes for 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to r%cx\n",
- 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;
@@ -451,7 +529,7 @@ grub_arch_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args,
grub_dprintf ("linux", "linux command line: '%s'\n", args);
- retval = grub_efi_linux_boot (addr, size, handover_offset,
+ retval = grub_efi_linux_boot (addr, size, 0, handover_offset,
(void *)addr, nx_supported);
/* Never reached... */
diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
index abbf6b24f5..6c310d9879 100644
--- a/grub-core/loader/i386/efi/linux.c
+++ b/grub-core/loader/i386/efi/linux.c
@@ -41,6 +41,7 @@ static grub_command_t cmd_linuxefi, cmd_initrdefi;
struct grub_linuxefi_context {
void *kernel_mem;
grub_uint64_t kernel_size;
+ grub_uint64_t kernel_start;
grub_uint32_t handover_offset;
struct linux_kernel_params *params;
char *cmdline;
@@ -169,6 +170,7 @@ grub_linuxefi_boot (void *data)
return grub_efi_linux_boot ((grub_addr_t)context->kernel_mem,
context->kernel_size,
+ context->kernel_start,
context->handover_offset,
context->params,
context->nx_supported);
@@ -527,7 +529,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
LOW_U32(kernel_mem));
lh->code32_start = LOW_U32(kernel_mem);
- grub_memcpy (kernel_mem, (char *)kernel + start, filelen - start);
+ grub_memcpy (kernel_mem, (char *)kernel, filelen);
lh->type_of_loader = 0x6;
grub_dprintf ("linux", "setting lh->type_of_loader = 0x%02x\n",
@@ -544,6 +546,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
goto fail;
context->kernel_mem = kernel_mem;
context->kernel_size = kernel_size;
+ context->kernel_start = start;
context->handover_offset = handover_offset;
context->params = params;
context->cmdline = cmdline;
diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h
index 5b4e626c37..cd17be506a 100644
--- a/include/grub/efi/linux.h
+++ b/include/grub/efi/linux.h
@@ -27,6 +27,7 @@
grub_err_t
EXPORT_FUNC(grub_efi_linux_boot) (grub_addr_t kernel_address,
grub_size_t kernel_size,
+ grub_size_t kernel_start,
grub_off_t handover_offset,
void *kernel_param, int nx_enabled);
@@ -38,4 +39,9 @@ EXPORT_FUNC(grub_efi_check_nx_image_support) (grub_addr_t kernel_addr,
grub_err_t
EXPORT_FUNC(grub_efi_check_nx_required) (int *nx_required);
+grub_err_t
+EXPORT_FUNC(grub_efi_mem_set_att) (grub_addr_t k_address,
+ grub_size_t k_size,
+ grub_size_t k_start, int nx_supported);
+
#endif /* ! GRUB_EFI_LINUX_HEADER */

View file

@ -0,0 +1,102 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Leo Sandoval <lsandova@redhat.com>
Date: Fri, 11 Apr 2025 15:31:53 -0600
Subject: [PATCH] Include function name on debug and error print functions
Together with the line number, the debug log gives more context when
debugging.
Signed-off-by: Leo Sandoval <lsandova@redhat.com>
---
grub-core/kern/err.c | 4 ++--
grub-core/kern/misc.c | 4 ++--
include/grub/err.h | 6 +++---
include/grub/misc.h | 5 +++--
4 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/grub-core/kern/err.c b/grub-core/kern/err.c
index aebfe0cf83..ba04b57fb7 100644
--- a/grub-core/kern/err.c
+++ b/grub-core/kern/err.c
@@ -38,14 +38,14 @@ static int grub_error_stack_assert;
#endif
grub_err_t
-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;
diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
index 69bd655f3d..541c7bb80c 100644
--- a/grub-core/kern/misc.c
+++ b/grub-core/kern/misc.c
@@ -248,7 +248,7 @@ 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;
@@ -272,7 +272,7 @@ grub_real_dprintf (const char *file, const int line, const char *condition,
else
last_had_cr = 0;
#endif
- grub_printf ("%s:%d:%s: ", file, line, condition);
+ grub_printf ("%s:%s:%d:%s: ", file, function, line, condition);
va_start (args, fmt);
grub_vprintf (fmt, args);
va_end (args);
diff --git a/include/grub/err.h b/include/grub/err.h
index 7530f58b29..6379a6baf8 100644
--- a/include/grub/err.h
+++ b/include/grub/err.h
@@ -88,10 +88,10 @@ 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 *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));
diff --git a/include/grub/misc.h b/include/grub/misc.h
index 0429339ef3..2b9096a0b3 100644
--- a/include/grub/misc.h
+++ b/include/grub/misc.h
@@ -43,7 +43,7 @@
#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);
char *EXPORT_FUNC(grub_strcpy) (char *dest, const char *src);
@@ -420,9 +420,10 @@ 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,
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,

View file

@ -0,0 +1,109 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alec Brown <alec.r.brown@oracle.com>
Date: Tue, 12 Aug 2025 03:45:32 +0000
Subject: [PATCH] kern/misc: Implement grub_strtok()
Add the functions grub_strtok() and grub_strtok_r() to help parse strings into
tokens separated by characters in the "delim" parameter. These functions are
present in gnulib but calling them directly from the gnulib code is quite
challenging since the call "#include <string.h>" would include the header file
grub-core/lib/posix_wrap/string.h instead of grub-core/lib/gnulib/string.h,
where strtok() and strtok_r() are declared. Since this overlap is quite
problematic, the simpler solution was to implement the code in the GRUB based
on gnulib's implementation. For more information on these functions, visit the
Linux Programmer's Manual, man strtok.
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/kern/misc.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++
include/grub/misc.h | 3 +++
2 files changed, 65 insertions(+)
diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
index 69bd655f3d..c69fe7fb19 100644
--- a/grub-core/kern/misc.c
+++ b/grub-core/kern/misc.c
@@ -453,6 +453,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);
+}
+
int
grub_isspace (int c)
{
diff --git a/include/grub/misc.h b/include/grub/misc.h
index 0429339ef3..626f0c3535 100644
--- a/include/grub/misc.h
+++ b/include/grub/misc.h
@@ -134,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 <bruno@clisp.org>, 2005. */
static inline char *

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,43 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alec Brown <alec.r.brown@oracle.com>
Date: Tue, 12 Aug 2025 03:45:34 +0000
Subject: [PATCH] util/misc.c: Change offset type for
grub_util_write_image_at()
Adding filevercmp support to grub-core/commands/blsuki.c from gnulib will cause
issues with the type of the offset parameter for grub_util_write_image_at() for
emu builds. To fix this issue, we can change the type from off_t to grub_off_t.
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
include/grub/util/misc.h | 2 +-
util/misc.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/include/grub/util/misc.h b/include/grub/util/misc.h
index e9e0a6724a..bfce065583 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/util/misc.c b/util/misc.c
index 0f928e5b49..6e16a68d9a 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%"

View file

@ -0,0 +1,342 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Tue, 12 Aug 2025 03:45:35 +0000
Subject: [PATCH] blsuki: Check for mounted /boot in emu
Irritatingly, BLS defines paths relative to the mountpoint of the
filesystem which contains its snippets, not / or any other fixed
location. So grub-emu needs to know whether /boot is a separate
filesystem from / and conditionally prepend a path.
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/Makefile.core.def | 3 ++
grub-core/commands/blsuki.c | 83 +++++++++++++++++++++++++++++++++++++----
grub-core/osdep/linux/getroot.c | 8 ++++
grub-core/osdep/unix/getroot.c | 4 +-
include/grub/emu/misc.h | 2 +-
5 files changed, 91 insertions(+), 9 deletions(-)
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 5e0e757344..885dd436de 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -376,6 +376,9 @@ kernel = {
emu = kern/emu/cache_s.S;
emu = kern/emu/hostdisk.c;
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;
diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c
index 9440adb100..ed93a150b1 100644
--- a/grub-core/commands/blsuki.c
+++ b/grub-core/commands/blsuki.c
@@ -32,6 +32,13 @@
#include <grub/lib/envblk.h>
#include <filevercmp.h>
+#ifdef GRUB_MACHINE_EMU
+#include <grub/emu/misc.h>
+#define GRUB_BOOT_DEVICE "/boot"
+#else
+#define GRUB_BOOT_DEVICE ""
+#endif
+
GRUB_MOD_LICENSE ("GPLv3+");
#define GRUB_BLS_CONFIG_PATH "/loader/entries/"
@@ -79,6 +86,34 @@ static grub_blsuki_entry_t *entries;
#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.
@@ -526,7 +561,7 @@ bls_get_linux (grub_blsuki_entry_t *entry)
linux_path = blsuki_get_val (entry, "linux", NULL);
options = blsuki_expand_val (blsuki_get_val (entry, "options", NULL));
- if (grub_add (sizeof ("linux "), grub_strlen (linux_path), &size))
+ 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;
@@ -548,6 +583,7 @@ bls_get_linux (grub_blsuki_entry_t *entry)
tmp = linux_cmd;
tmp = grub_stpcpy (tmp, "linux ");
+ tmp = blsuki_update_boot_device (tmp);
tmp = grub_stpcpy (tmp, linux_path);
if (options != NULL)
{
@@ -582,7 +618,7 @@ bls_get_initrd (grub_blsuki_entry_t *entry)
for (i = 0; initrd_list != NULL && initrd_list[i] != NULL; i++)
{
- if (grub_add (size, 1, &size) ||
+ 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");
@@ -605,6 +641,7 @@ bls_get_initrd (grub_blsuki_entry_t *entry)
{
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");
@@ -630,7 +667,7 @@ bls_get_devicetree (grub_blsuki_entry_t *entry)
dt_path = blsuki_expand_val (blsuki_get_val (entry, "devicetree", NULL));
if (dt_path != NULL)
{
- if (grub_add (sizeof ("devicetree "), grub_strlen (dt_path), &size) ||
+ 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");
@@ -643,6 +680,7 @@ bls_get_devicetree (grub_blsuki_entry_t *entry)
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");
}
@@ -757,7 +795,11 @@ blsuki_set_find_entry_info (struct find_entry_info *info, const char *dirname, c
if (devid == NULL)
{
+#ifdef GRUB_MACHINE_EMU
+ devid = "host";
+#else
devid = grub_env_get ("root");
+#endif
if (devid == NULL)
return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable '%s' isn't set"), "root");
}
@@ -799,10 +841,13 @@ blsuki_set_find_entry_info (struct find_entry_info *info, const char *dirname, c
* parameter. If the fallback option is enabled, the default location will be
* checked for BLS config files if the first attempt fails.
*/
-static void
+static grub_err_t
blsuki_find_entry (struct find_entry_info *info, bool enable_fallback)
{
struct read_entry_info read_entry_info;
+ char *default_dir = NULL;
+ char *tmp;
+ grub_size_t default_size;
grub_fs_t dir_fs = NULL;
grub_device_t dir_dev = NULL;
bool fallback = false;
@@ -833,7 +878,15 @@ blsuki_find_entry (struct find_entry_info *info, bool enable_fallback)
*/
if (entries == NULL && fallback == false && enable_fallback == true)
{
- blsuki_set_find_entry_info (info, GRUB_BLS_CONFIG_PATH, NULL);
+ default_size = sizeof (GRUB_BOOT_DEVICE) + sizeof (GRUB_BLS_CONFIG_PATH) - 1;
+ default_dir = grub_malloc (default_size);
+ if (default_dir == NULL)
+ return grub_errno;
+
+ tmp = blsuki_update_boot_device (default_dir);
+ tmp = grub_stpcpy (tmp, GRUB_BLS_CONFIG_PATH);
+
+ blsuki_set_find_entry_info (info, default_dir, NULL);
grub_dprintf ("blsuki", "Entries weren't found in %s, fallback to %s\n",
read_entry_info.dirname, info->dirname);
fallback = true;
@@ -842,6 +895,9 @@ blsuki_find_entry (struct find_entry_info *info, bool enable_fallback)
fallback = false;
}
while (fallback == true);
+
+ grub_free (default_dir);
+ return GRUB_ERR_NONE;
}
static grub_err_t
@@ -851,6 +907,9 @@ blsuki_load_entries (char *path, bool enable_fallback)
static grub_err_t r;
const char *devid = NULL;
char *dir = NULL;
+ char *default_dir = NULL;
+ char *tmp;
+ grub_size_t dir_size;
struct find_entry_info info = {
.dev = NULL,
.fs = NULL,
@@ -892,15 +951,25 @@ blsuki_load_entries (char *path, bool enable_fallback)
}
if (dir == NULL)
- dir = (char *) GRUB_BLS_CONFIG_PATH;
+ {
+ dir_size = sizeof (GRUB_BOOT_DEVICE) + sizeof (GRUB_BLS_CONFIG_PATH) - 2;
+ default_dir = grub_malloc (dir_size);
+ if (default_dir == NULL)
+ return grub_errno;
+
+ tmp = blsuki_update_boot_device (default_dir);
+ tmp = grub_stpcpy (tmp, GRUB_BLS_CONFIG_PATH);
+ dir = default_dir;
+ }
r = blsuki_set_find_entry_info (&info, dir, devid);
if (r == GRUB_ERR_NONE)
- blsuki_find_entry (&info, enable_fallback);
+ r = blsuki_find_entry (&info, enable_fallback);
if (info.dev != NULL)
grub_device_close (info.dev);
+ grub_free (default_dir);
return r;
}
diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c
index 4bf386b590..8bf281c1d8 100644
--- a/grub-core/osdep/linux/getroot.c
+++ b/grub-core/osdep/linux/getroot.c
@@ -139,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)
{
@@ -199,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
@@ -700,6 +702,7 @@ out:
return ret;
}
+#ifdef GRUB_UTIL
static char *
get_mdadm_uuid (const char *os_dev)
{
@@ -757,6 +760,7 @@ out:
return name;
}
+#endif
static int
grub_util_is_imsm_or_ddf (const char *os_dev)
@@ -1096,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)
{
@@ -1198,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)
@@ -1214,6 +1220,7 @@ grub_util_get_dev_abstraction_os (const char *os_dev)
return GRUB_DEV_ABSTRACTION_NONE;
}
+#ifdef GRUB_UTIL
int
grub_util_pull_device_os (const char *os_dev,
enum grub_dev_abstraction_types ab)
@@ -1270,6 +1277,7 @@ grub_util_get_grub_dev_os (const char *os_dev)
return grub_dev;
}
+#endif
static void *mp = NULL;
static void
diff --git a/grub-core/osdep/unix/getroot.c b/grub-core/osdep/unix/getroot.c
index ee11b02fb6..62581ba601 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 <http://www.gnu.org/licenses/>.
*/
-#include <config.h>
#include <config-util.h>
+#include <config.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -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/include/grub/emu/misc.h b/include/grub/emu/misc.h
index f3a712a8b2..59b8038c60 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);

View file

@ -0,0 +1,822 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alec Brown <alec.r.brown@oracle.com>
Date: Tue, 12 Aug 2025 03:45:36 +0000
Subject: [PATCH] blsuki: Add uki command to load Unified Kernel Image entries
A Unified Kernel Image (UKI) is a single UEFI PE file that combines
a UEFI boot stub, a Linux kernel image, an initrd, and further resources.
The uki command will locate where the UKI file is and create a GRUB menu
entry to load it.
The Unified Kernel Image Specification: https://uapi-group.org/specifications/specs/unified_kernel_image/
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
docs/grub.texi | 36 +++-
grub-core/commands/blsuki.c | 476 ++++++++++++++++++++++++++++++++++++++++----
include/grub/menu.h | 2 +
3 files changed, 474 insertions(+), 40 deletions(-)
diff --git a/docs/grub.texi b/docs/grub.texi
index 336f8e87ed..531e847f32 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -3344,7 +3344,8 @@ chain-loaded system, @pxref{drivemap}.
@subsection blsuki_save_default
If this variable is set, menu entries generated from BLS config files
-(@pxref{blscfg}) will be set as the default boot entry when selected.
+(@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
@@ -4434,6 +4435,7 @@ you forget a command, you can run the command @command{help}
* 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
@@ -6062,6 +6064,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
diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c
index ed93a150b1..cb00f936a7 100644
--- a/grub-core/commands/blsuki.c
+++ b/grub-core/commands/blsuki.c
@@ -32,6 +32,12 @@
#include <grub/lib/envblk.h>
#include <filevercmp.h>
+#ifdef GRUB_MACHINE_EFI
+#include <grub/efi/efi.h>
+#include <grub/efi/disk.h>
+#include <grub/efi/pe32.h>
+#endif
+
#ifdef GRUB_MACHINE_EMU
#include <grub/emu/misc.h>
#define GRUB_BOOT_DEVICE "/boot"
@@ -42,14 +48,28 @@
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[] =
{
@@ -61,6 +81,18 @@ static const struct grub_arg_option bls_opt[] =
{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;
@@ -71,6 +103,7 @@ struct read_entry_info
{
const char *devid;
const char *dirname;
+ enum blsuki_cmd_type cmd_type;
grub_file_t file;
};
@@ -82,7 +115,7 @@ struct find_entry_info
grub_fs_t fs;
};
-static grub_blsuki_entry_t *entries;
+static grub_blsuki_entry_t *entries = NULL;
#define FOR_BLSUKI_ENTRIES(var) FOR_LIST_ELEMENTS (var, entries)
@@ -181,7 +214,7 @@ blsuki_add_keyval (grub_blsuki_entry_t *entry, char *key, char *val)
* 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 as defined in the BLS fragment file.
+ * them in sorted order.
*/
static char *
blsuki_get_val (grub_blsuki_entry_t *entry, const char *keyname, int *last)
@@ -310,20 +343,212 @@ bls_parse_keyvals (grub_file_t f, grub_blsuki_entry_t *entry)
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
- * and initializes entry data before parsing keyvals and adding the entry to
- * the list of BLS entries.
+ * 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, filename_len;
- grub_err_t err;
+ 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;
@@ -331,17 +556,31 @@ blsuki_read_entry (const char *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 < BLS_EXT_LEN ||
- grub_strcmp (filename + filename_len - BLS_EXT_LEN, ".conf") != 0)
+ 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, GRUB_FILE_TYPE_CONFIG);
+ f = grub_file_open (p, file_type);
grub_free (p);
if (f == NULL)
goto finish;
@@ -373,7 +612,26 @@ blsuki_read_entry (const char *filename,
goto finish;
}
- err = bls_parse_keyvals (f, entry);
+ 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);
@@ -389,7 +647,7 @@ blsuki_read_entry (const char *filename,
/*
* This function returns a list of values that had the same key in the BLS
- * config file. The number of entries in this list is returned by the len
+ * config file or UKI. The number of entries in this list is returned by the len
* parameter.
*/
static char **
@@ -764,7 +1022,7 @@ bls_create_entry (grub_blsuki_entry_t *entry)
linux_cmd, initrd_cmd ? initrd_cmd : "",
dt_cmd ? dt_cmd : "");
- grub_normal_add_menu_entry (argc, argv, classes, id, users, hotkey, NULL, src, 0, entry);
+ grub_normal_add_menu_entry (argc, argv, classes, id, users, hotkey, NULL, src, 0, NULL, NULL, entry);
finish:
grub_free (linux_cmd);
@@ -776,6 +1034,70 @@ bls_create_entry (grub_blsuki_entry_t *entry)
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
@@ -785,7 +1107,7 @@ bls_create_entry (grub_blsuki_entry_t *entry)
* device.
*/
static grub_err_t
-blsuki_set_find_entry_info (struct find_entry_info *info, const char *dirname, const char *devid)
+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;
@@ -795,10 +1117,23 @@ blsuki_set_find_entry_info (struct find_entry_info *info, const char *dirname, c
if (devid == NULL)
{
+ if (cmd_type == BLSUKI_BLS_CMD)
+ {
#ifdef GRUB_MACHINE_EMU
- devid = "host";
+ devid = "host";
#else
- devid = grub_env_get ("root");
+ 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");
@@ -837,15 +1172,16 @@ blsuki_set_find_entry_info (struct find_entry_info *info, const char *dirname, c
}
/*
- * This function searches for BLS config files based on the data in the info
- * parameter. If the fallback option is enabled, the default location will be
- * checked for BLS config files if the first attempt fails.
+ * 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)
+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;
@@ -862,6 +1198,7 @@ blsuki_find_entry (struct find_entry_info *info, bool enable_fallback)
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);
@@ -874,19 +1211,27 @@ blsuki_find_entry (struct find_entry_info *info, bool enable_fallback)
/*
* 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.
+ * 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)
{
- default_size = sizeof (GRUB_BOOT_DEVICE) + sizeof (GRUB_BLS_CONFIG_PATH) - 1;
+ 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, GRUB_BLS_CONFIG_PATH);
+ tmp = grub_stpcpy (tmp, cmd_dir);
- blsuki_set_find_entry_info (info, default_dir, NULL);
+ 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;
@@ -901,15 +1246,17 @@ blsuki_find_entry (struct find_entry_info *info, bool enable_fallback)
}
static grub_err_t
-blsuki_load_entries (char *path, bool enable_fallback)
+blsuki_load_entries (char *path, bool enable_fallback, enum blsuki_cmd_type cmd_type)
{
- grub_size_t len;
+ 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,
@@ -918,12 +1265,26 @@ blsuki_load_entries (char *path, bool enable_fallback)
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 >= BLS_EXT_LEN && grub_strcmp (path + len - BLS_EXT_LEN, ".conf") == 0)
+ 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)
@@ -952,19 +1313,26 @@ blsuki_load_entries (char *path, bool enable_fallback)
if (dir == NULL)
{
- dir_size = sizeof (GRUB_BOOT_DEVICE) + sizeof (GRUB_BLS_CONFIG_PATH) - 2;
+ 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, GRUB_BLS_CONFIG_PATH);
+ tmp = grub_stpcpy (tmp, cmd_dir);
dir = default_dir;
}
- r = blsuki_set_find_entry_info (&info, dir, devid);
+ r = blsuki_set_find_entry_info (&info, dir, devid, cmd_type);
if (r == GRUB_ERR_NONE)
- r = blsuki_find_entry (&info, enable_fallback);
+ r = blsuki_find_entry (&info, enable_fallback, cmd_type);
if (info.dev != NULL)
grub_device_close (info.dev);
@@ -1002,11 +1370,11 @@ blsuki_is_default_entry (const char *def_entry, grub_blsuki_entry_t *entry, int
}
/*
- * This function creates a GRUB boot menu entry for each BLS entry in the
- * entries list.
+ * 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)
+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;
@@ -1025,7 +1393,12 @@ blsuki_create_entries (bool show_default, bool show_non_default, char *entry_id)
(show_non_default == true && blsuki_is_default_entry (def_entry, entry, idx) == false) ||
(entry_id != NULL && grub_strcmp (entry_id, entry->filename) == 0))
{
- bls_create_entry (entry);
+ 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;
}
@@ -1036,8 +1409,7 @@ blsuki_create_entries (bool show_default, bool show_non_default, char *entry_id)
}
static grub_err_t
-grub_cmd_blscfg (grub_extcmd_context_t ctxt, int argc __attribute__ ((unused)),
- char **args __attribute__ ((unused)))
+blsuki_cmd (grub_extcmd_context_t ctxt, enum blsuki_cmd_type cmd_type)
{
grub_err_t err;
struct grub_arg_list *state = ctxt->state;
@@ -1074,24 +1446,50 @@ grub_cmd_blscfg (grub_extcmd_context_t ctxt, int argc __attribute__ ((unused)),
show_non_default = true;
}
- err = blsuki_load_entries (path, enable_fallback);
+ 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);
+ 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)
{
bls_cmd = grub_register_extcmd ("blscfg", grub_cmd_blscfg, 0,
N_("[-p|--path] [-f|--enable-fallback] DIR [-d|--show-default] [-n|--show-non-default] [-e|--entry] FILE"),
N_("Import Boot Loader Specification snippets."),
bls_opt);
+#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/include/grub/menu.h b/include/grub/menu.h
index 43a3c5809b..0e4978dc3b 100644
--- a/include/grub/menu.h
+++ b/include/grub/menu.h
@@ -39,6 +39,8 @@ struct grub_blsuki_entry
grub_size_t keyvals_size;
int nkeyvals;
char *filename;
+ char *dirname;
+ char *devid;
bool visible;
};
typedef struct grub_blsuki_entry grub_blsuki_entry_t;

View file

@ -0,0 +1,168 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Fri, 15 Nov 2024 15:34:29 +0800
Subject: [PATCH] posix_wrap: Tweaks in preparation for libtasn1
Cc: Vladimir Serbinenko <phcoder@gmail.com>
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Tested-by: Stefan Berger <stefanb@linux.ibm.com>
---
grub-core/lib/posix_wrap/c-ctype.h | 114 +++++++++++++++++++++++++++++++++++++
grub-core/lib/posix_wrap/string.h | 21 +++++++
2 files changed, 135 insertions(+)
create mode 100644 grub-core/lib/posix_wrap/c-ctype.h
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 0000000000..5f8fc8ce3f
--- /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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_POSIX_C_CTYPE_H
+#define GRUB_POSIX_C_CTYPE_H 1
+
+#include <grub/misc.h>
+
+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/string.h b/grub-core/lib/posix_wrap/string.h
index 1adb450b5a..d3e400d500 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

Some files were not shown because too many files have changed in this diff Show more