Add several CVE fixes

- Resolves: CVE-2024-45779 CVE-2024-45778 CVE-2025-1118
- Resolves: CVE-2025-0677 CVE-2024-45782 CVE-2025-0690
- Resolves: CVE-2024-45783 CVE-2025-0624 CVE-2024-45776
- Resolves: CVE-2025-0622 CVE-2024-45774 CVE-2024-45775
- Resolves: CVE-2024-45781 CVE-2024-45780
- Resolves: #RHEL-79700
- Resolves: #RHEL-79341
- Resolves: #RHEL-79875
- Resolves: #RHEL-79849
- Resolves: #RHEL-79707
- Resolves: #RHEL-79857
- Resolves: #RHEL-79709
- Resolves: #RHEL-79846
- Resolves: #RHEL-75737
- Resolves: #RHEL-79713
- Resolves: #RHEL-73785
- Resolves: #RHEL-73787
- Resolves: #RHEL-79704
- Resolves: #RHEL-79702

Signed-off-by: Nicolas Frayer <nfrayer@redhat.com>
This commit is contained in:
Nicolas Frayer 2025-02-13 16:38:23 -06:00
parent 76fac13a2b
commit 6eaa34fe07
101 changed files with 10214 additions and 1 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 981526644..0592aa68f 100644
--- a/include/grub/misc.h
+++ b/include/grub/misc.h
@@ -72,6 +72,45 @@ grub_stpcpy (char *dest, const char *src)
return d - 1;
}
+static inline grub_size_t
+grub_strlcpy (char *dest, const char *src, grub_size_t size)
+{
+ char *d = dest;
+ grub_size_t res = 0;
+ /*
+ * We do not subtract one from size here to avoid dealing with underflowing
+ * the value, which is why to_copy is always checked to be greater than one
+ * throughout this function.
+ */
+ grub_size_t to_copy = size;
+
+ /* Copy size - 1 bytes to dest. */
+ if (to_copy > 1)
+ while ((*d++ = *src++) != '\0' && ++res && --to_copy > 1)
+ ;
+
+ /*
+ * NUL terminate if size != 0. The previous step may have copied a NUL byte
+ * if it reached the end of the string, but we know dest[size - 1] must always
+ * be a NUL byte.
+ */
+ if (size != 0)
+ dest[size - 1] = '\0';
+
+ /* If there is still space in dest, but are here, we reached the end of src. */
+ if (to_copy > 1)
+ return res;
+
+ /*
+ * If we haven't reached the end of the string, iterate through to determine
+ * the strings total length.
+ */
+ while (*src++ != '\0' && ++res)
+ ;
+
+ return res;
+}
+
/* XXX: If grub_memmove is too slow, we must implement grub_memcpy. */
static inline void *
grub_memcpy (void *dest, const void *src, grub_size_t n)

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 34a698b71..47272665e 100644
--- a/grub-core/fs/ufs.c
+++ b/grub-core/fs/ufs.c
@@ -463,7 +463,7 @@ grub_ufs_lookup_symlink (struct grub_ufs_data *data, int ino)
/* Check against zero is paylindromic, no need to swap. */
if (data->inode.nblocks == 0
&& INODE_SIZE (data) <= sizeof (data->inode.symlink))
- grub_strcpy (symlink, (char *) data->inode.symlink);
+ grub_strlcpy (symlink, (char *) data->inode.symlink, sz);
else
{
if (grub_ufs_read_file (data, 0, 0, 0, sz, symlink) < 0)

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 f419965d1..bb7af5f67 100644
--- a/grub-core/fs/hfs.c
+++ b/grub-core/fs/hfs.c
@@ -379,7 +379,7 @@ grub_hfs_mount (grub_disk_t disk)
volume name. */
key.parent_dir = grub_cpu_to_be32_compile_time (1);
key.strlen = data->sblock.volname[0];
- grub_strcpy ((char *) key.str, (char *) (data->sblock.volname + 1));
+ grub_strlcpy ((char *) key.str, (char *) (data->sblock.volname + 1), sizeof (key.str));
if (grub_hfs_find_node (data, (char *) &key, data->cat_root,
0, (char *) &dir, sizeof (dir)) == 0)

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 df6beb544..f7daa9435 100644
--- a/grub-core/fs/f2fs.c
+++ b/grub-core/fs/f2fs.c
@@ -872,6 +872,9 @@ grub_f2fs_mount (grub_disk_t disk)
return data;
fail:
+ if (grub_errno == GRUB_ERR_NONE)
+ grub_error (GRUB_ERR_BAD_FS, "not a F2FS filesystem");
+
grub_free (data);
return NULL;

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 19c7b3367..e7fd98a07 100644
--- a/grub-core/fs/hfsplus.c
+++ b/grub-core/fs/hfsplus.c
@@ -393,7 +393,7 @@ grub_hfsplus_mount (grub_disk_t disk)
fail:
- if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
+ if (grub_errno == GRUB_ERR_OUT_OF_RANGE || grub_errno == GRUB_ERR_NONE)
grub_error (GRUB_ERR_BAD_FS, "not a HFS+ filesystem");
grub_free (data);

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 ac011950a..82cf1a271 100644
--- a/grub-core/fs/iso9660.c
+++ b/grub-core/fs/iso9660.c
@@ -491,6 +491,9 @@ grub_iso9660_mount (grub_disk_t disk)
return data;
fail:
+ if (grub_errno == GRUB_ERR_NONE)
+ grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem");
+
grub_free (data);
return 0;
}

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 82cf1a271..7a59a65a5 100644
--- a/grub-core/fs/iso9660.c
+++ b/grub-core/fs/iso9660.c
@@ -568,9 +568,19 @@ susp_iterate_dir (struct grub_iso9660_susp_entry *entry,
filename type is stored. */
/* FIXME: Fix this slightly improper cast. */
if (entry->data[0] & GRUB_ISO9660_RR_DOT)
- ctx->filename = (char *) ".";
+ {
+ if (ctx->filename_alloc)
+ grub_free (ctx->filename);
+ ctx->filename_alloc = 0;
+ ctx->filename = (char *) ".";
+ }
else if (entry->data[0] & GRUB_ISO9660_RR_DOTDOT)
- ctx->filename = (char *) "..";
+ {
+ if (ctx->filename_alloc)
+ grub_free (ctx->filename);
+ ctx->filename_alloc = 0;
+ ctx->filename = (char *) "..";
+ }
else if (entry->len >= 5)
{
grub_size_t off = 0, csize = 1;

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 731d346f8..eac639e36 100644
--- a/grub-core/fs/ext2.c
+++ b/grub-core/fs/ext2.c
@@ -481,6 +481,8 @@ grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
struct grub_ext4_extent *ext;
int i;
grub_disk_addr_t ret;
+ grub_uint16_t nent;
+ const grub_uint16_t max_inline_ext = sizeof (inode->blocks) / sizeof (*ext) - 1; /* Minus 1 extent header. */
leaf = grub_ext4_find_leaf (data, (struct grub_ext4_extent_header *) inode->blocks.dir_blocks, fileblock);
if (! leaf)
@@ -490,7 +492,13 @@ grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
}
ext = (struct grub_ext4_extent *) (leaf + 1);
- for (i = 0; i < grub_le_to_cpu16 (leaf->entries); i++)
+
+ nent = grub_le_to_cpu16 (leaf->entries);
+
+ if (leaf->depth == 0)
+ nent = grub_min (nent, max_inline_ext);
+
+ for (i = 0; i < nent; i++)
{
if (fileblock < grub_le_to_cpu32 (ext[i].block))
break;

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 deb058ac9..976ad1dc4 100644
--- a/grub-core/fs/ntfs.c
+++ b/grub-core/fs/ntfs.c
@@ -139,6 +139,8 @@ free_attr (struct grub_ntfs_attr *at)
static grub_uint8_t *
find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr)
{
+ grub_uint8_t *mft_end;
+
if (at->flags & GRUB_NTFS_AF_ALST)
{
retry:
@@ -191,7 +193,8 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr)
return NULL;
}
at->attr_cur = at->attr_nxt;
- while (*at->attr_cur != 0xFF)
+ mft_end = at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR);
+ while (at->attr_cur < mft_end && *at->attr_cur != 0xFF)
{
at->attr_nxt += u16at (at->attr_cur, 4);
if (*at->attr_cur == GRUB_NTFS_AT_ATTRIBUTE_LIST)

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 976ad1dc4..562b4f7eb 100644
--- a/grub-core/fs/ntfs.c
+++ b/grub-core/fs/ntfs.c
@@ -119,13 +119,20 @@ static grub_err_t read_data (struct grub_ntfs_attr *at, grub_uint8_t *pa,
grub_disk_read_hook_t read_hook,
void *read_hook_data);
-static void
+static grub_err_t
init_attr (struct grub_ntfs_attr *at, struct grub_ntfs_file *mft)
{
at->mft = mft;
at->flags = (mft == &mft->data->mmft) ? GRUB_NTFS_AF_MMFT : 0;
at->attr_nxt = mft->buf + first_attr_off (mft->buf);
+ at->end = mft->buf + (mft->data->mft_size << GRUB_NTFS_BLK_SHR);
+
+ if (at->attr_nxt > at->end)
+ return grub_error (GRUB_ERR_BAD_FS, "attributes start outside the MFT");
+
at->attr_end = at->emft_buf = at->edat_buf = at->sbuf = NULL;
+
+ return GRUB_ERR_NONE;
}
static void
@@ -239,6 +246,10 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr)
pa_end = at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR);
}
at->flags |= GRUB_NTFS_AF_ALST;
+
+ /* From this point on pa_end is the end of the buffer */
+ at->end = pa_end;
+
while (at->attr_nxt < at->attr_end)
{
if ((*at->attr_nxt == attr) || (attr == 0))
@@ -298,7 +309,9 @@ locate_attr (struct grub_ntfs_attr *at, struct grub_ntfs_file *mft,
{
grub_uint8_t *pa;
- init_attr (at, mft);
+ if (init_attr (at, mft) != GRUB_ERR_NONE)
+ return NULL;
+
pa = find_attr (at, attr);
if (pa == NULL)
return NULL;
@@ -314,7 +327,8 @@ locate_attr (struct grub_ntfs_attr *at, struct grub_ntfs_file *mft,
}
grub_errno = GRUB_ERR_NONE;
free_attr (at);
- init_attr (at, mft);
+ if (init_attr (at, mft) != GRUB_ERR_NONE)
+ return NULL;
pa = find_attr (at, attr);
}
return pa;
@@ -585,7 +599,7 @@ init_file (struct grub_ntfs_file *mft, grub_uint64_t mftno)
mft->attr.attr_end = 0; /* Don't jump to attribute list */
}
else
- init_attr (&mft->attr, mft);
+ return init_attr (&mft->attr, mft);
return 0;
}
@@ -807,7 +821,9 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir,
bmp = NULL;
at = &attr;
- init_attr (at, mft);
+ if (init_attr (at, mft) != GRUB_ERR_NONE)
+ return 0;
+
while (1)
{
cur_pos = find_attr (at, GRUB_NTFS_AT_INDEX_ROOT);
@@ -838,7 +854,9 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir,
bitmap = NULL;
bitmap_len = 0;
free_attr (at);
+ /* No need to check errors here, as it will already be fine */
init_attr (at, mft);
+
while ((cur_pos = find_attr (at, GRUB_NTFS_AT_BITMAP)) != NULL)
{
int ofs;
@@ -1203,6 +1221,7 @@ grub_ntfs_label (grub_device_t device, char **label)
struct grub_ntfs_data *data = 0;
struct grub_fshelp_node *mft = 0;
grub_uint8_t *pa;
+ grub_err_t err;
grub_dl_ref (my_mod);
@@ -1228,7 +1247,10 @@ grub_ntfs_label (grub_device_t device, char **label)
goto fail;
}
- init_attr (&mft->attr, mft);
+ err = init_attr (&mft->attr, mft);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
pa = find_attr (&mft->attr, GRUB_NTFS_AT_VOLUME_NAME);
if (pa >= mft->buf + (mft->data->mft_size << GRUB_NTFS_BLK_SHR))
diff --git a/include/grub/ntfs.h b/include/grub/ntfs.h
index d1a6af696..ec1c4db38 100644
--- a/include/grub/ntfs.h
+++ b/include/grub/ntfs.h
@@ -134,6 +134,7 @@ struct grub_ntfs_attr
grub_uint8_t *attr_cur, *attr_nxt, *attr_end;
grub_uint32_t save_pos;
grub_uint8_t *sbuf;
+ grub_uint8_t *end;
struct grub_ntfs_file *mft;
};

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 562b4f7eb..9311ba9ef 100644
--- a/grub-core/fs/ntfs.c
+++ b/grub-core/fs/ntfs.c
@@ -70,6 +70,25 @@ res_attr_data_len (void *res_attr_ptr)
return u32at (res_attr_ptr, 0x10);
}
+/* Return the next attribute if it exists, otherwise return NULL. */
+static grub_uint8_t *
+next_attribute (grub_uint8_t *curr_attribute, void *end)
+{
+ grub_uint8_t *next = curr_attribute;
+
+ /*
+ * Need to verify we aren't exceeding the end of the buffer by reading the
+ * header for the current attribute
+ */
+ if (curr_attribute + GRUB_NTFS_ATTRIBUTE_HEADER_SIZE >= (grub_uint8_t *) end)
+ return NULL;
+
+ next += u16at (curr_attribute, 4);
+
+ return next;
+}
+
+
grub_ntfscomp_func_t grub_ntfscomp_func;
static grub_err_t
@@ -151,13 +170,13 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr)
if (at->flags & GRUB_NTFS_AF_ALST)
{
retry:
- while (at->attr_nxt < at->attr_end)
+ while (at->attr_nxt)
{
at->attr_cur = at->attr_nxt;
- at->attr_nxt += u16at (at->attr_cur, 4);
+ at->attr_nxt = next_attribute (at->attr_cur, at->attr_end);
if ((*at->attr_cur == attr) || (attr == 0))
{
- grub_uint8_t *new_pos;
+ grub_uint8_t *new_pos, *end;
if (at->flags & GRUB_NTFS_AF_MMFT)
{
@@ -181,15 +200,36 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr)
return NULL;
}
+ /*
+ * Only time emft_bufs is defined is in this function, with this
+ * size.
+ */
+ grub_size_t emft_buf_size =
+ at->mft->data->mft_size << GRUB_NTFS_BLK_SHR;
+
+ /*
+ * Needs to be enough space for the successful case to even
+ * bother.
+ */
+ if (first_attr_off (at->emft_buf) >= (emft_buf_size - 0x18 - 2))
+ {
+ grub_error (GRUB_ERR_BAD_FS,
+ "can\'t find 0x%X in attribute list",
+ (unsigned char) *at->attr_cur);
+ return NULL;
+ }
+
new_pos = &at->emft_buf[first_attr_off (at->emft_buf)];
- while (*new_pos != 0xFF)
+ end = &at->emft_buf[emft_buf_size];
+
+ while (new_pos && *new_pos != 0xFF)
{
if ((*new_pos == *at->attr_cur)
&& (u16at (new_pos, 0xE) == u16at (at->attr_cur, 0x18)))
{
return new_pos;
}
- new_pos += u16at (new_pos, 4);
+ new_pos = next_attribute (new_pos, end);
}
grub_error (GRUB_ERR_BAD_FS,
"can\'t find 0x%X in attribute list",
@@ -203,7 +243,7 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr)
mft_end = at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR);
while (at->attr_cur < mft_end && *at->attr_cur != 0xFF)
{
- at->attr_nxt += u16at (at->attr_cur, 4);
+ at->attr_nxt = next_attribute (at->attr_cur, at->end);
if (*at->attr_cur == GRUB_NTFS_AT_ATTRIBUTE_LIST)
at->attr_end = at->attr_cur;
if ((*at->attr_cur == attr) || (attr == 0))
@@ -250,13 +290,14 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr)
/* From this point on pa_end is the end of the buffer */
at->end = pa_end;
- while (at->attr_nxt < at->attr_end)
+ while (at->attr_nxt)
{
if ((*at->attr_nxt == attr) || (attr == 0))
break;
- at->attr_nxt += u16at (at->attr_nxt, 4);
+ at->attr_nxt = next_attribute (at->attr_nxt, pa_end);
}
- if (at->attr_nxt >= at->attr_end)
+
+ if (at->attr_nxt >= at->attr_end || at->attr_nxt == NULL)
return NULL;
if ((at->flags & GRUB_NTFS_AF_MMFT) && (attr == GRUB_NTFS_AT_DATA))
@@ -277,7 +318,8 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr)
grub_cpu_to_le32 (at->mft->data->mft_start
+ 1));
pa = at->attr_nxt + u16at (pa, 4);
- while (pa < at->attr_end)
+
+ while (pa)
{
if (*pa != attr)
break;
@@ -293,7 +335,7 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr)
u32at (pa, 0x10) * (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR),
at->mft->data->mft_size << GRUB_NTFS_BLK_SHR, 0, 0, 0))
return NULL;
- pa += u16at (pa, 4);
+ pa = next_attribute (pa, pa_end);
}
at->attr_nxt = at->attr_cur;
at->flags &= ~GRUB_NTFS_AF_GPOS;
@@ -530,14 +572,15 @@ read_attr (struct grub_ntfs_attr *at, grub_uint8_t *dest, grub_disk_addr_t ofs,
else
vcn = ofs >> (at->mft->data->log_spc + GRUB_NTFS_BLK_SHR);
pa = at->attr_nxt + u16at (at->attr_nxt, 4);
- while (pa < at->attr_end)
+
+ while (pa)
{
if (*pa != attr)
break;
if (u32at (pa, 8) > vcn)
break;
at->attr_nxt = pa;
- pa += u16at (pa, 4);
+ pa = next_attribute (pa, at->attr_end);
}
}
pp = find_attr (at, attr);
diff --git a/include/grub/ntfs.h b/include/grub/ntfs.h
index ec1c4db38..2c8078403 100644
--- a/include/grub/ntfs.h
+++ b/include/grub/ntfs.h
@@ -89,6 +89,8 @@ enum
#define GRUB_NTFS_COM_SEC (GRUB_NTFS_COM_LEN >> GRUB_NTFS_BLK_SHR)
#define GRUB_NTFS_LOG_COM_SEC (GRUB_NTFS_COM_LOG_LEN - GRUB_NTFS_BLK_SHR)
+#define GRUB_NTFS_ATTRIBUTE_HEADER_SIZE 16
+
enum
{
GRUB_NTFS_AF_ALST = 1,

View File

@ -0,0 +1,245 @@
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: Implement attribute verification
It was possible to read OOB when an attribute had a size that exceeded
the allocated buffer. This resolves that by making sure all attributes
that get read are fully in the allocated space by implementing
a function to validate them.
Defining the offsets in include/grub/ntfs.h but they are only used in
the validation function and not across the rest of the NTFS code.
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/ntfs.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++++
include/grub/ntfs.h | 22 ++++++++
2 files changed, 175 insertions(+)
diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c
index 9311ba9ef..8fdb8f2ff 100644
--- a/grub-core/fs/ntfs.c
+++ b/grub-core/fs/ntfs.c
@@ -70,6 +70,149 @@ res_attr_data_len (void *res_attr_ptr)
return u32at (res_attr_ptr, 0x10);
}
+/*
+ * Check if the attribute is valid and doesn't exceed the allocated region.
+ * This accounts for resident and non-resident data.
+ *
+ * This is based off the documentation from the linux-ntfs project:
+ * https://flatcap.github.io/linux-ntfs/ntfs/concepts/attribute_header.html
+ */
+static bool
+validate_attribute (grub_uint8_t *attr, void *end)
+{
+ grub_size_t attr_size = 0;
+ grub_size_t min_size = 0;
+ grub_size_t spare = (grub_uint8_t *) end - attr;
+ /*
+ * Just used as a temporary variable to try and deal with cases where someone
+ * tries to overlap fields.
+ */
+ grub_size_t curr = 0;
+
+ /* Need verify we can entirely read the attributes header. */
+ if (attr + GRUB_NTFS_ATTRIBUTE_HEADER_SIZE >= (grub_uint8_t *) end)
+ goto fail;
+
+ /*
+ * So, the rest of this code uses a 16bit int for the attribute length but
+ * from reading the all the documentation I could find it says this field is
+ * actually 32bit. But let's be consistent with the rest of the code.
+ *
+ * https://elixir.bootlin.com/linux/v6.10.7/source/fs/ntfs3/ntfs.h#L370
+ */
+ attr_size = u16at (attr, GRUB_NTFS_ATTRIBUTE_LENGTH);
+
+ if (attr_size > spare)
+ goto fail;
+
+ /* Not an error case, just reached the end of the attributes. */
+ if (attr_size == 0)
+ return false;
+
+ /*
+ * Extra validation by trying to calculate a minimum possible size for this
+ * attribute. +8 from the size of the resident data struct which is the
+ * minimum that can be added.
+ */
+ min_size = GRUB_NTFS_ATTRIBUTE_HEADER_SIZE + 8;
+
+ if (min_size > attr_size)
+ goto fail;
+
+ /* Is the data is resident (0) or not (1). */
+ if (attr[GRUB_NTFS_ATTRIBUTE_RESIDENT] == 0)
+ {
+ /* Read the offset and size of the attribute. */
+ curr = u16at (attr, GRUB_NTFS_ATTRIBUTE_RES_OFFSET);
+ curr += u32at (attr, GRUB_NTFS_ATTRIBUTE_RES_LENGTH);
+ if (curr > min_size)
+ min_size = curr;
+ }
+ else
+ {
+ /*
+ * If the data is non-resident, the minimum size is 64 which is where
+ * the data runs start. We already have a minimum size of 24. So, just
+ * adding 40 to get to the real value.
+ */
+ min_size += 40;
+ if (min_size > attr_size)
+ goto fail;
+ /* If the compression unit size is > 0, +8 bytes*/
+ if (u16at (attr, GRUB_NTFS_ATTRIBUTE_COMPRESSION_UNIT_SIZE) > 0)
+ min_size += 8;
+
+ /*
+ * Need to consider the data runs now. Each member of the run has byte
+ * that describes the size of the data length and offset. Each being
+ * 4 bits in the byte.
+ */
+ curr = u16at (attr, GRUB_NTFS_ATTRIBUTE_DATA_RUNS);
+
+ if (curr + 1 > min_size)
+ min_size = curr + 1;
+
+ if (min_size > attr_size)
+ goto fail;
+
+ /*
+ * Each attribute can store multiple data runs which are stored
+ * continuously in the attribute. They exist as one header byte
+ * with up to 14 bytes following it depending on the lengths.
+ * We stop when we hit a header that is just a NUL byte.
+ *
+ * https://flatcap.github.io/linux-ntfs/ntfs/concepts/data_runs.html
+ */
+ while (attr[curr] != 0)
+ {
+ /*
+ * We stop when we hit a header that is just a NUL byte. The data
+ * run header is stored as a single byte where the top 4 bits refer
+ * to the number of bytes used to store the total length of the
+ * data run, and the number of bytes used to store the offset.
+ * These directly follow the header byte, so we use them to update
+ * the minimum size.
+ */
+ min_size += (attr[curr] & 0x7) + ((attr[curr] >> 4) & 0x7);
+ curr += min_size;
+ min_size++;
+ if (min_size > attr_size)
+ goto fail;
+ }
+ }
+
+ /* Name offset, doing this after data residence checks. */
+ if (u16at (attr, GRUB_NTFS_ATTRIBUTE_NAME_OFFSET) != 0)
+ {
+ curr = u16at (attr, GRUB_NTFS_ATTRIBUTE_NAME_OFFSET);
+ /*
+ * Multiple the name length by 2 as its UTF-16. Can be zero if this in an
+ * unamed attribute.
+ */
+ curr += attr[GRUB_NTFS_ATTRIBUTE_NAME_LENGTH] * 2;
+ if (curr > min_size)
+ min_size = curr;
+ }
+
+ /* Padded to 8 bytes. */
+ if (min_size % 8 != 0)
+ min_size += 8 - (min_size % 8);
+
+ /*
+ * At this point min_size should be exactly attr_size but being flexible
+ * here to avoid any issues.
+ */
+ if (min_size > attr_size)
+ goto fail;
+
+ return true;
+
+ fail:
+ grub_dprintf ("ntfs", "spare=%" PRIuGRUB_SIZE " min_size=%" PRIuGRUB_SIZE " attr_size=%" PRIuGRUB_SIZE "\n",
+ spare, min_size, attr_size);
+ return false;
+}
+
/* Return the next attribute if it exists, otherwise return NULL. */
static grub_uint8_t *
next_attribute (grub_uint8_t *curr_attribute, void *end)
@@ -84,6 +227,8 @@ next_attribute (grub_uint8_t *curr_attribute, void *end)
return NULL;
next += u16at (curr_attribute, 4);
+ if (validate_attribute (next, end) == false)
+ return NULL;
return next;
}
@@ -290,6 +435,9 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr)
/* From this point on pa_end is the end of the buffer */
at->end = pa_end;
+ if (validate_attribute (at->attr_nxt, pa_end) == false)
+ return NULL;
+
while (at->attr_nxt)
{
if ((*at->attr_nxt == attr) || (attr == 0))
@@ -319,6 +467,9 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr)
+ 1));
pa = at->attr_nxt + u16at (pa, 4);
+ if (validate_attribute (pa, pa_end) == true)
+ pa = NULL;
+
while (pa)
{
if (*pa != attr)
@@ -572,6 +723,8 @@ read_attr (struct grub_ntfs_attr *at, grub_uint8_t *dest, grub_disk_addr_t ofs,
else
vcn = ofs >> (at->mft->data->log_spc + GRUB_NTFS_BLK_SHR);
pa = at->attr_nxt + u16at (at->attr_nxt, 4);
+ if (validate_attribute (pa, at->attr_end) == false)
+ pa = NULL;
while (pa)
{
diff --git a/include/grub/ntfs.h b/include/grub/ntfs.h
index 2c8078403..77b182acf 100644
--- a/include/grub/ntfs.h
+++ b/include/grub/ntfs.h
@@ -91,6 +91,28 @@ enum
#define GRUB_NTFS_ATTRIBUTE_HEADER_SIZE 16
+/*
+ * To make attribute validation clearer the offsets for each value in the
+ * attribute headers are defined as macros.
+ *
+ * These offsets are all from:
+ * https://flatcap.github.io/linux-ntfs/ntfs/concepts/attribute_header.html
+ */
+
+/* These offsets are part of the attribute header. */
+#define GRUB_NTFS_ATTRIBUTE_LENGTH 4
+#define GRUB_NTFS_ATTRIBUTE_RESIDENT 8
+#define GRUB_NTFS_ATTRIBUTE_NAME_LENGTH 9
+#define GRUB_NTFS_ATTRIBUTE_NAME_OFFSET 10
+
+/* Offsets for values needed for resident data. */
+#define GRUB_NTFS_ATTRIBUTE_RES_LENGTH 16
+#define GRUB_NTFS_ATTRIBUTE_RES_OFFSET 20
+
+/* Offsets for values needed for non-resident data. */
+#define GRUB_NTFS_ATTRIBUTE_DATA_RUNS 32
+#define GRUB_NTFS_ATTRIBUTE_COMPRESSION_UNIT_SIZE 34
+
enum
{
GRUB_NTFS_AF_ALST = 1,

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 e3816d1ec..43be00e99 100644
--- a/grub-core/fs/xfs.c
+++ b/grub-core/fs/xfs.c
@@ -568,6 +568,17 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
do
{
int i;
+ grub_addr_t keys_end, data_end;
+
+ if (grub_mul (sizeof (grub_uint64_t), nrec, &keys_end) ||
+ grub_add ((grub_addr_t) keys, keys_end, &keys_end) ||
+ grub_add ((grub_addr_t) node->data, node->data->data_size, &data_end) ||
+ keys_end > data_end)
+ {
+ grub_error (GRUB_ERR_BAD_FS, "invalid number of XFS root keys");
+ grub_free (leaf);
+ return 0;
+ }
for (i = 0; i < nrec; i++)
{

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 43be00e99..9d3420ece 100644
--- a/grub-core/fs/xfs.c
+++ b/grub-core/fs/xfs.c
@@ -315,6 +315,8 @@ static int grub_xfs_sb_valid(struct grub_xfs_data *data)
}
return 1;
}
+
+ grub_error (GRUB_ERR_BAD_FS, "unsupported XFS filesystem version");
return 0;
}
@@ -984,7 +986,7 @@ grub_xfs_mount (grub_disk_t disk)
return data;
fail:
- if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
+ if (grub_errno == GRUB_ERR_OUT_OF_RANGE || grub_errno == GRUB_ERR_NONE)
grub_error (GRUB_ERR_BAD_FS, "not an XFS filesystem");
grub_free (data);

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 868ce3b63..1dc4339dc 100644
--- a/grub-core/kern/file.c
+++ b/grub-core/kern/file.c
@@ -124,6 +124,9 @@ grub_file_open (const char *name, enum grub_file_type type)
if ((file->fs->fs_open) (file, file_name) != GRUB_ERR_NONE)
goto fail;
+ if (file->data == NULL)
+ goto fail;
+
file->name = grub_strdup (name);
grub_errno = GRUB_ERR_NONE;

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 cafcd0fba..b1c64e77d 100644
--- a/grub-core/fs/affs.c
+++ b/grub-core/fs/affs.c
@@ -699,6 +699,7 @@ static struct grub_fs grub_affs_fs =
GRUB_MOD_INIT(affs)
{
+ grub_affs_fs.mod = mod;
grub_fs_register (&grub_affs_fs);
my_mod = mod;
}
diff --git a/grub-core/fs/bfs.c b/grub-core/fs/bfs.c
index 47dbe2011..17705812d 100644
--- a/grub-core/fs/bfs.c
+++ b/grub-core/fs/bfs.c
@@ -1104,6 +1104,7 @@ GRUB_MOD_INIT (bfs)
{
COMPILE_TIME_ASSERT (1 << LOG_EXTENT_SIZE ==
sizeof (struct grub_bfs_extent));
+ grub_bfs_fs.mod = mod;
grub_fs_register (&grub_bfs_fs);
}
diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
index 47325f6ad..3ed37a4db 100644
--- a/grub-core/fs/btrfs.c
+++ b/grub-core/fs/btrfs.c
@@ -3365,6 +3365,7 @@ subvol_get_env (struct grub_env_var *var __attribute__ ((unused)),
GRUB_MOD_INIT (btrfs)
{
+ grub_btrfs_fs.mod = mod;
grub_fs_register (&grub_btrfs_fs);
cmd_info = grub_register_command("btrfs-info", grub_cmd_btrfs_info,
"DEVICE",
diff --git a/grub-core/fs/cbfs.c b/grub-core/fs/cbfs.c
index 581215ef1..3e527cbf2 100644
--- a/grub-core/fs/cbfs.c
+++ b/grub-core/fs/cbfs.c
@@ -390,6 +390,7 @@ GRUB_MOD_INIT (cbfs)
#if (defined (__i386__) || defined (__x86_64__)) && !defined (GRUB_UTIL) && !defined (GRUB_MACHINE_EMU) && !defined (GRUB_MACHINE_XEN)
init_cbfsdisk ();
#endif
+ grub_cbfs_fs.mod = mod;
grub_fs_register (&grub_cbfs_fs);
}
diff --git a/grub-core/fs/cpio.c b/grub-core/fs/cpio.c
index dab5f9898..1799f7ff5 100644
--- a/grub-core/fs/cpio.c
+++ b/grub-core/fs/cpio.c
@@ -52,6 +52,7 @@ read_number (const grub_uint16_t *arr, grub_size_t size)
GRUB_MOD_INIT (cpio)
{
+ grub_cpio_fs.mod = mod;
grub_fs_register (&grub_cpio_fs);
}
diff --git a/grub-core/fs/cpio_be.c b/grub-core/fs/cpio_be.c
index 846548892..7bed1b848 100644
--- a/grub-core/fs/cpio_be.c
+++ b/grub-core/fs/cpio_be.c
@@ -52,6 +52,7 @@ read_number (const grub_uint16_t *arr, grub_size_t size)
GRUB_MOD_INIT (cpio_be)
{
+ grub_cpio_fs.mod = mod;
grub_fs_register (&grub_cpio_fs);
}
diff --git a/grub-core/fs/ext2.c b/grub-core/fs/ext2.c
index eac639e36..0ee22e675 100644
--- a/grub-core/fs/ext2.c
+++ b/grub-core/fs/ext2.c
@@ -1113,6 +1113,7 @@ static struct grub_fs grub_ext2_fs =
GRUB_MOD_INIT(ext2)
{
+ grub_ext2_fs.mod = mod;
grub_fs_register (&grub_ext2_fs);
my_mod = mod;
}
diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c
index f7daa9435..e5dcbc470 100644
--- a/grub-core/fs/f2fs.c
+++ b/grub-core/fs/f2fs.c
@@ -1353,6 +1353,7 @@ static struct grub_fs grub_f2fs_fs = {
GRUB_MOD_INIT (f2fs)
{
+ grub_f2fs_fs.mod = mod;
grub_fs_register (&grub_f2fs_fs);
my_mod = mod;
}
diff --git a/grub-core/fs/fat.c b/grub-core/fs/fat.c
index ff6200c5b..1cf355af4 100644
--- a/grub-core/fs/fat.c
+++ b/grub-core/fs/fat.c
@@ -1312,6 +1312,7 @@ GRUB_MOD_INIT(fat)
#endif
{
COMPILE_TIME_ASSERT (sizeof (struct grub_fat_dir_entry) == 32);
+ grub_fat_fs.mod = mod;
grub_fs_register (&grub_fat_fs);
my_mod = mod;
}
diff --git a/grub-core/fs/hfs.c b/grub-core/fs/hfs.c
index bb7af5f67..3a9894443 100644
--- a/grub-core/fs/hfs.c
+++ b/grub-core/fs/hfs.c
@@ -1434,6 +1434,7 @@ static struct grub_fs grub_hfs_fs =
GRUB_MOD_INIT(hfs)
{
+ grub_hfs_fs.mod = mod;
if (!grub_is_lockdown ())
grub_fs_register (&grub_hfs_fs);
my_mod = mod;
diff --git a/grub-core/fs/hfsplus.c b/grub-core/fs/hfsplus.c
index e7fd98a07..d5f90007b 100644
--- a/grub-core/fs/hfsplus.c
+++ b/grub-core/fs/hfsplus.c
@@ -1150,6 +1150,7 @@ static struct grub_fs grub_hfsplus_fs =
GRUB_MOD_INIT(hfsplus)
{
+ grub_hfsplus_fs.mod = mod;
grub_fs_register (&grub_hfsplus_fs);
my_mod = mod;
}
diff --git a/grub-core/fs/iso9660.c b/grub-core/fs/iso9660.c
index 7a59a65a5..0c0aae597 100644
--- a/grub-core/fs/iso9660.c
+++ b/grub-core/fs/iso9660.c
@@ -1165,6 +1165,7 @@ static struct grub_fs grub_iso9660_fs =
GRUB_MOD_INIT(iso9660)
{
+ grub_iso9660_fs.mod = mod;
grub_fs_register (&grub_iso9660_fs);
my_mod = mod;
}
diff --git a/grub-core/fs/jfs.c b/grub-core/fs/jfs.c
index 70a2f4947..b0283ac00 100644
--- a/grub-core/fs/jfs.c
+++ b/grub-core/fs/jfs.c
@@ -1005,6 +1005,7 @@ static struct grub_fs grub_jfs_fs =
GRUB_MOD_INIT(jfs)
{
+ grub_jfs_fs.mod = mod;
grub_fs_register (&grub_jfs_fs);
my_mod = mod;
}
diff --git a/grub-core/fs/minix.c b/grub-core/fs/minix.c
index 3cd18c85b..beb1a6378 100644
--- a/grub-core/fs/minix.c
+++ b/grub-core/fs/minix.c
@@ -732,6 +732,7 @@ GRUB_MOD_INIT(minix)
#endif
#endif
{
+ grub_minix_fs.mod = mod;
grub_fs_register (&grub_minix_fs);
my_mod = mod;
}
diff --git a/grub-core/fs/newc.c b/grub-core/fs/newc.c
index 4fb8b2e3d..43b7f8b64 100644
--- a/grub-core/fs/newc.c
+++ b/grub-core/fs/newc.c
@@ -64,6 +64,7 @@ read_number (const char *str, grub_size_t size)
GRUB_MOD_INIT (newc)
{
+ grub_cpio_fs.mod = mod;
grub_fs_register (&grub_cpio_fs);
}
diff --git a/grub-core/fs/nilfs2.c b/grub-core/fs/nilfs2.c
index 3c248a910..c44583ee8 100644
--- a/grub-core/fs/nilfs2.c
+++ b/grub-core/fs/nilfs2.c
@@ -1231,6 +1231,7 @@ GRUB_MOD_INIT (nilfs2)
grub_nilfs2_dat_entry));
COMPILE_TIME_ASSERT (1 << LOG_INODE_SIZE
== sizeof (struct grub_nilfs2_inode));
+ grub_nilfs2_fs.mod = mod;
grub_fs_register (&grub_nilfs2_fs);
my_mod = mod;
}
diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c
index 8fdb8f2ff..03e3e5c6a 100644
--- a/grub-core/fs/ntfs.c
+++ b/grub-core/fs/ntfs.c
@@ -1537,6 +1537,7 @@ static struct grub_fs grub_ntfs_fs =
GRUB_MOD_INIT (ntfs)
{
+ grub_ntfs_fs.mod = mod;
grub_fs_register (&grub_ntfs_fs);
my_mod = mod;
}
diff --git a/grub-core/fs/odc.c b/grub-core/fs/odc.c
index 790000622..8e4e8aeac 100644
--- a/grub-core/fs/odc.c
+++ b/grub-core/fs/odc.c
@@ -52,6 +52,7 @@ read_number (const char *str, grub_size_t size)
GRUB_MOD_INIT (odc)
{
+ grub_cpio_fs.mod = mod;
grub_fs_register (&grub_cpio_fs);
}
diff --git a/grub-core/fs/proc.c b/grub-core/fs/proc.c
index 5f516502d..bcde43349 100644
--- a/grub-core/fs/proc.c
+++ b/grub-core/fs/proc.c
@@ -192,6 +192,7 @@ static struct grub_fs grub_procfs_fs =
GRUB_MOD_INIT (procfs)
{
+ grub_procfs_fs.mod = mod;
grub_disk_dev_register (&grub_procfs_dev);
grub_fs_register (&grub_procfs_fs);
}
diff --git a/grub-core/fs/reiserfs.c b/grub-core/fs/reiserfs.c
index b8253da7f..d9a8bf602 100644
--- a/grub-core/fs/reiserfs.c
+++ b/grub-core/fs/reiserfs.c
@@ -1407,6 +1407,7 @@ static struct grub_fs grub_reiserfs_fs =
GRUB_MOD_INIT(reiserfs)
{
+ grub_reiserfs_fs.mod = mod;
grub_fs_register (&grub_reiserfs_fs);
my_mod = mod;
}
diff --git a/grub-core/fs/romfs.c b/grub-core/fs/romfs.c
index d97b8fbb8..a43546d95 100644
--- a/grub-core/fs/romfs.c
+++ b/grub-core/fs/romfs.c
@@ -475,6 +475,7 @@ static struct grub_fs grub_romfs_fs =
GRUB_MOD_INIT(romfs)
{
+ grub_romfs_fs.mod = mod;
grub_fs_register (&grub_romfs_fs);
}
diff --git a/grub-core/fs/sfs.c b/grub-core/fs/sfs.c
index 983e88008..f0d7cac43 100644
--- a/grub-core/fs/sfs.c
+++ b/grub-core/fs/sfs.c
@@ -779,6 +779,7 @@ static struct grub_fs grub_sfs_fs =
GRUB_MOD_INIT(sfs)
{
+ grub_sfs_fs.mod = mod;
grub_fs_register (&grub_sfs_fs);
my_mod = mod;
}
diff --git a/grub-core/fs/squash4.c b/grub-core/fs/squash4.c
index 6dd731e23..ccfa3eea5 100644
--- a/grub-core/fs/squash4.c
+++ b/grub-core/fs/squash4.c
@@ -1032,6 +1032,7 @@ static struct grub_fs grub_squash_fs =
GRUB_MOD_INIT(squash4)
{
+ grub_squash_fs.mod = mod;
grub_fs_register (&grub_squash_fs);
}
diff --git a/grub-core/fs/tar.c b/grub-core/fs/tar.c
index 386c09022..fd2ec1f74 100644
--- a/grub-core/fs/tar.c
+++ b/grub-core/fs/tar.c
@@ -354,6 +354,7 @@ static struct grub_fs grub_cpio_fs = {
GRUB_MOD_INIT (tar)
{
+ grub_cpio_fs.mod = mod;
grub_fs_register (&grub_cpio_fs);
}
diff --git a/grub-core/fs/udf.c b/grub-core/fs/udf.c
index 2ac5c1d00..3d4b40263 100644
--- a/grub-core/fs/udf.c
+++ b/grub-core/fs/udf.c
@@ -1382,6 +1382,7 @@ static struct grub_fs grub_udf_fs = {
GRUB_MOD_INIT (udf)
{
+ grub_udf_fs.mod = mod;
grub_fs_register (&grub_udf_fs);
my_mod = mod;
}
diff --git a/grub-core/fs/ufs.c b/grub-core/fs/ufs.c
index 47272665e..7f72494cd 100644
--- a/grub-core/fs/ufs.c
+++ b/grub-core/fs/ufs.c
@@ -899,6 +899,7 @@ GRUB_MOD_INIT(ufs1)
#endif
#endif
{
+ grub_ufs_fs.mod = mod;
grub_fs_register (&grub_ufs_fs);
my_mod = mod;
}
diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c
index 9d3420ece..7b0ea577e 100644
--- a/grub-core/fs/xfs.c
+++ b/grub-core/fs/xfs.c
@@ -1220,6 +1220,7 @@ static struct grub_fs grub_xfs_fs =
GRUB_MOD_INIT(xfs)
{
+ grub_xfs_fs.mod = mod;
grub_fs_register (&grub_xfs_fs);
my_mod = mod;
}
diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c
index cf4d2ab18..cbbd86730 100644
--- a/grub-core/fs/zfs/zfs.c
+++ b/grub-core/fs/zfs/zfs.c
@@ -4394,6 +4394,7 @@ static struct grub_fs grub_zfs_fs = {
GRUB_MOD_INIT (zfs)
{
COMPILE_TIME_ASSERT (sizeof (zap_leaf_chunk_t) == ZAP_LEAF_CHUNKSIZE);
+ grub_zfs_fs.mod = mod;
grub_fs_register (&grub_zfs_fs);
#ifndef GRUB_UTIL
my_mod = mod;
diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c
index 1dc4339dc..58fae17ba 100644
--- a/grub-core/kern/file.c
+++ b/grub-core/kern/file.c
@@ -25,6 +25,7 @@
#include <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;
@@ -215,6 +219,9 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len)
grub_err_t
grub_file_close (grub_file_t file)
{
+ if (file->fs->mod)
+ grub_dl_unref (file->fs->mod);
+
grub_dprintf ("file", "Closing `%s' ...\n", file->name);
if (file->fs->fs_close)
(file->fs->fs_close) (file);
diff --git a/include/grub/fs.h b/include/grub/fs.h
index 026bc3bb8..df4c93b16 100644
--- a/include/grub/fs.h
+++ b/include/grub/fs.h
@@ -23,6 +23,7 @@
#include <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,367 @@
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 | 11 ++++++++---
util/grub-mkimage.c | 9 ++++++++-
util/mkimage.c | 15 ++++++++++++++-
11 files changed, 104 insertions(+), 23 deletions(-)
diff --git a/docs/grub.texi b/docs/grub.texi
index 825278a7f..b39cdf275 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -5948,8 +5948,10 @@ the GRUB command line, edit menu entries, and execute any menu entry. If
@samp{superusers} is set, then use of the command line and editing of menu
entries are automatically restricted to superusers. Setting @samp{superusers}
to empty string effectively disables both access to CLI and editing of menu
-entries. Note: The environment variable needs to be exported to also affect
-the section defined by the @samp{submenu} command (@pxref{submenu}).
+entries. Building a grub image with @samp{--disable-cli} option will also
+disable access to CLI and editing of menu entries, as well as disabling rescue
+mode. Note: The environment variable needs to be exported to also affect the
+section defined by the @samp{submenu} command (@pxref{submenu}).
Other users may be allowed to execute specific menu entries by giving a list of
usernames (as above) using the @option{--users} option to the
diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c
index e94a2f78f..e4d4bf625 100644
--- a/grub-core/kern/main.c
+++ b/grub-core/kern/main.c
@@ -30,11 +30,14 @@
#include <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 6be678c0d..53f2d723f 100644
--- a/grub-core/normal/auth.c
+++ b/grub-core/normal/auth.c
@@ -209,6 +209,9 @@ grub_auth_check_authentication (const char *userlist)
char entered[GRUB_AUTH_MAX_PASSLEN];
struct grub_auth_user *user;
+ if (grub_is_cli_disabled ())
+ return GRUB_ACCESS_DENIED;
+
grub_memset (login, 0, sizeof (login));
if (is_authenticated (userlist))
diff --git a/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c
index 18240e76c..fd0d83999 100644
--- a/grub-core/normal/menu_text.c
+++ b/grub-core/normal/menu_text.c
@@ -178,21 +178,24 @@ command-line or ESC to discard edits and return to the GRUB menu."),
grub_free (msg_translated);
- if (nested)
+ if (!grub_is_cli_disabled ())
{
- ret += grub_print_message_indented_real
- (_("Press enter to boot the selected OS, "
- "`e' to edit the commands before booting "
- "or `c' for a command-line. ESC to return previous menu."),
- STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
- }
- else
- {
- ret += grub_print_message_indented_real
- (_("Press enter to boot the selected OS, "
- "`e' to edit the commands before booting "
- "or `c' for a command-line."),
- STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
+ if (nested)
+ {
+ ret += grub_print_message_indented_real
+ (_("Press enter to boot the selected OS, "
+ "`e' to edit the commands before booting "
+ "or `c' for a command-line. ESC to return previous menu."),
+ STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
+ }
+ else
+ {
+ ret += grub_print_message_indented_real
+ (_("Press enter to boot the selected OS, "
+ "`e' to edit the commands before booting "
+ "or `c' for a command-line."),
+ STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
+ }
}
}
return ret;
diff --git a/include/grub/kernel.h b/include/grub/kernel.h
index 98edc0863..f98a780da 100644
--- a/include/grub/kernel.h
+++ b/include/grub/kernel.h
@@ -33,6 +33,7 @@ enum
OBJ_TYPE_DISABLE_SHIM_LOCK,
OBJ_TYPE_GPG_PUBKEY,
OBJ_TYPE_X509_PUBKEY,
+ OBJ_TYPE_DISABLE_CLI
};
/* The module header. */
diff --git a/include/grub/misc.h b/include/grub/misc.h
index 0592aa68f..8c0ffed16 100644
--- a/include/grub/misc.h
+++ b/include/grub/misc.h
@@ -409,6 +409,8 @@ grub_uint64_t EXPORT_FUNC(grub_divmod64) (grub_uint64_t n,
grub_uint64_t d,
grub_uint64_t *r);
+extern bool EXPORT_FUNC(grub_is_cli_disabled) (void);
+
/* Must match softdiv group in gentpl.py. */
#if !defined(GRUB_MACHINE_EMU) && (defined(__arm__) || defined(__ia64__) || \
(defined(__riscv) && (__riscv_xlen == 32)))
diff --git a/include/grub/util/install.h b/include/grub/util/install.h
index 51f3b13ac..b9627182a 100644
--- a/include/grub/util/install.h
+++ b/include/grub/util/install.h
@@ -72,6 +72,8 @@
{ "appended-signature-size", GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,\
"SIZE", 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), \
1}, \
+ { "disable-cli", GRUB_INSTALL_OPTIONS_DISABLE_CLI, 0, 0, \
+ N_("disabled command line interface access"), 0 }, \
{ "verbose", 'v', 0, 0, \
N_("print verbose messages."), 1 }
@@ -134,7 +136,8 @@ enum grub_install_options {
GRUB_INSTALL_OPTIONS_DTB,
GRUB_INSTALL_OPTIONS_SBAT,
GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK,
- GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE
+ GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,
+ GRUB_INSTALL_OPTIONS_DISABLE_CLI
};
extern char *grub_install_source_directory;
@@ -197,7 +200,8 @@ grub_install_generate_image (const char *dir, const char *prefix,
const struct grub_install_image_target_desc *image_target,
int note, size_t appsig_size,
grub_compression_t comp, const char *dtb_file,
- const char *sbat_path, const int disable_shim_lock);
+ const char *sbat_path, const int disable_shim_lock,
+ const int disable_cli);
const struct grub_install_image_target_desc *
grub_install_get_image_target (const char *arg);
diff --git a/util/grub-install-common.c b/util/grub-install-common.c
index c603f5b30..221b889c8 100644
--- a/util/grub-install-common.c
+++ b/util/grub-install-common.c
@@ -464,6 +464,7 @@ static char **x509keys;
static size_t nx509keys;
static grub_compression_t compression;
static size_t appsig_size;
+static int disable_cli;
int
grub_install_parse (int key, char *arg)
@@ -509,6 +510,9 @@ grub_install_parse (int key, char *arg)
* (nx509keys + 1));
x509keys[nx509keys++] = xstrdup (arg);
return 1;
+ case GRUB_INSTALL_OPTIONS_DISABLE_CLI:
+ disable_cli = 1;
+ return 1;
case GRUB_INSTALL_OPTIONS_VERBOSITY:
verbosity++;
@@ -689,12 +693,13 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
" --dtb '%s' "
"--sbat '%s' "
"--format '%s' --compression '%s' "
- "--appended-signature-size %zu %s %s %s\n",
+ "--appended-signature-size %zu %s %s %s %s\n",
dir, prefix,
outname, dtb ? : "", sbat ? : "", mkimage_target,
compnames[compression], appsig_size,
disable_shim_lock ? "--disable-shim-lock" : "",
- note ? "--note" : "", s);
+ note ? "--note" : "",
+ disable_cli ? " --disable-cli" : "", s);
free (s);
tgt = grub_install_get_image_target (mkimage_target);
@@ -707,7 +712,7 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
x509keys, nx509keys,
config_path, tgt,
note, appsig_size, compression, dtb, sbat,
- disable_shim_lock);
+ disable_shim_lock, disable_cli);
while (dc--)
grub_install_pop_module ();
}
diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c
index e1f111278..13bdc6cf0 100644
--- a/util/grub-mkimage.c
+++ b/util/grub-mkimage.c
@@ -84,6 +84,7 @@ static struct argp_option options[] = {
{"compression", 'C', "(xz|none|auto)", 0, N_("choose the compression to use for core image"), 0},
{"sbat", 's', N_("FILE"), 0, N_("SBAT metadata"), 0},
{"disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, N_("disable shim_lock verifier"), 0},
+ {"disable-cli", GRUB_INSTALL_OPTIONS_DISABLE_CLI, 0, 0, N_("disable command line interface access"), 0},
{"verbose", 'v', 0, 0, N_("print verbose messages."), 0},
{"appended-signature-size", 'S', N_("SIZE"), 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), 0},
{ 0, 0, 0, 0, 0, 0 }
@@ -133,6 +134,7 @@ struct arguments
int note;
int disable_shim_lock;
size_t appsig_size;
+ int disable_cli;
const struct grub_install_image_target_desc *image_target;
grub_compression_t comp;
};
@@ -259,6 +261,10 @@ argp_parser (int key, char *arg, struct argp_state *state)
arguments->disable_shim_lock = 1;
break;
+ case GRUB_INSTALL_OPTIONS_DISABLE_CLI:
+ arguments->disable_cli = 1;
+ break;
+
case 'v':
verbosity++;
break;
@@ -347,7 +353,8 @@ main (int argc, char *argv[])
arguments.image_target, arguments.note,
arguments.appsig_size, arguments.comp,
arguments.dtb, arguments.sbat,
- arguments.disable_shim_lock);
+ arguments.disable_shim_lock,
+ arguments.disable_cli);
if (grub_util_file_sync (fp) < 0)
grub_util_error (_("cannot sync `%s': %s"), arguments.output ? : "stdout",
diff --git a/util/mkimage.c b/util/mkimage.c
index c3d33aaac..9ba1a8988 100644
--- a/util/mkimage.c
+++ b/util/mkimage.c
@@ -872,7 +872,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
const struct grub_install_image_target_desc *image_target,
int note, size_t appsig_size, grub_compression_t comp,
const char *dtb_path, const char *sbat_path,
- int disable_shim_lock)
+ int disable_shim_lock, int disable_cli)
{
char *kernel_img, *core_img;
size_t total_module_size, core_size;
@@ -947,6 +947,9 @@ grub_install_generate_image (const char *dir, const char *prefix,
if (disable_shim_lock)
total_module_size += sizeof (struct grub_module_header);
+ if (disable_cli)
+ total_module_size += sizeof (struct grub_module_header);
+
if (config_path)
{
config_size = ALIGN_ADDR (grub_util_get_image_size (config_path) + 1);
@@ -1113,6 +1116,16 @@ grub_install_generate_image (const char *dir, const char *prefix,
offset += sizeof (*header);
}
+ if (disable_cli)
+ {
+ struct grub_module_header *header;
+
+ header = (struct grub_module_header *) (kernel_img + offset);
+ header->type = grub_host_to_target32 (OBJ_TYPE_DISABLE_CLI);
+ header->size = grub_host_to_target32 (sizeof (*header));
+ offset += sizeof (*header);
+ }
+
if (config_path)
{
struct grub_module_header *header;

View File

@ -0,0 +1,184 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Glenn Washburn <development@efficientek.com>
Date: Thu, 9 Dec 2021 11:14:51 -0600
Subject: [PATCH] cryptodisk: Refactor to discard have_it global
The global "have_it" was never used by the crypto-backends, but was used to
determine if a crypto-backend successfully mounted a cryptodisk with a given
UUID. This is not needed however, because grub_device_iterate() will return
1 if and only if grub_cryptodisk_scan_device() returns 1. And
grub_cryptodisk_scan_device() will now only return 1 if a search_uuid has
been specified and a cryptodisk was successfully setup by a crypto-backend or
a cryptodisk of the requested UUID is already open.
To implement this grub_cryptodisk_scan_device_real() is modified to return
a cryptodisk or NULL on failure and having the appropriate grub_errno set to
indicated failure. Note that grub_cryptodisk_scan_device_real() will fail now
with a new errno GRUB_ERR_BAD_MODULE when none of the cryptodisk backend
modules succeed in identifying the source disk.
With this change grub_device_iterate() will return 1 when a crypto device is
successfully decrypted or when the source device has already been successfully
opened. Prior to this change, trying to mount an already successfully opened
device would trigger an error with the message "no such cryptodisk found",
which is at best misleading. The mount should silently succeed in this case,
which is what happens with this patch.
Signed-off-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/disk/cryptodisk.c | 56 ++++++++++++++++++++++++++++-----------------
1 file changed, 35 insertions(+), 21 deletions(-)
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index 90f82b2..9df3d31 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -983,7 +983,7 @@ grub_util_cryptodisk_get_uuid (grub_disk_t disk)
#endif
-static int check_boot, have_it;
+static int check_boot;
static char *search_uuid;
static void
@@ -995,7 +995,7 @@ cryptodisk_close (grub_cryptodisk_t dev)
grub_free (dev);
}
-static grub_err_t
+static grub_cryptodisk_t
grub_cryptodisk_scan_device_real (const char *name, grub_disk_t source)
{
grub_err_t err;
@@ -1005,13 +1005,13 @@ grub_cryptodisk_scan_device_real (const char *name, grub_disk_t source)
dev = grub_cryptodisk_get_by_source_disk (source);
if (dev)
- return GRUB_ERR_NONE;
+ return dev;
FOR_CRYPTODISK_DEVS (cr)
{
dev = cr->scan (source, search_uuid, check_boot);
if (grub_errno)
- return grub_errno;
+ return NULL;
if (!dev)
continue;
@@ -1019,16 +1019,16 @@ grub_cryptodisk_scan_device_real (const char *name, grub_disk_t source)
if (err)
{
cryptodisk_close (dev);
- return err;
+ return NULL;
}
grub_cryptodisk_insert (dev, name, source);
- have_it = 1;
-
- return GRUB_ERR_NONE;
+ return dev;
}
- return GRUB_ERR_NONE;
+
+ grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk module can handle this device");
+ return NULL;
}
#ifdef GRUB_UTIL
@@ -1082,8 +1082,10 @@ static int
grub_cryptodisk_scan_device (const char *name,
void *data __attribute__ ((unused)))
{
- grub_err_t err;
+ int ret = 0;
grub_disk_t source;
+ grub_cryptodisk_t dev;
+ grub_errno = GRUB_ERR_NONE;
/* Try to open disk. */
source = grub_disk_open (name);
@@ -1093,13 +1095,26 @@ grub_cryptodisk_scan_device (const char *name,
return 0;
}
- err = grub_cryptodisk_scan_device_real (name, source);
+ dev = grub_cryptodisk_scan_device_real (name, source);
+ if (dev)
+ {
+ ret = (search_uuid != NULL && grub_strcasecmp (search_uuid, dev->uuid) == 0);
+ goto cleanup;
+ }
- grub_disk_close (source);
-
- if (err)
+ /*
+ * Do not print error when err is GRUB_ERR_BAD_MODULE to avoid many unhelpful
+ * error messages.
+ */
+ if (grub_errno == GRUB_ERR_BAD_MODULE)
+ grub_error_pop ();
+
+ if (grub_errno != GRUB_ERR_NONE)
grub_print_error ();
- return have_it && search_uuid ? 1 : 0;
+
+ cleanup:
+ grub_disk_close (source);
+ return ret;
}
static grub_err_t
@@ -1110,9 +1125,9 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
if (argc < 1 && !state[1].set && !state[2].set)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
- have_it = 0;
if (state[0].set)
{
+ int found_uuid;
grub_cryptodisk_t dev;
dev = grub_cryptodisk_get_by_uuid (args[0]);
@@ -1125,10 +1140,10 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
check_boot = state[2].set;
search_uuid = args[0];
- grub_device_iterate (&grub_cryptodisk_scan_device, NULL);
+ found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, NULL);
search_uuid = NULL;
- if (!have_it)
+ if (!found_uuid)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such cryptodisk found");
return GRUB_ERR_NONE;
}
@@ -1142,7 +1157,6 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
}
else
{
- grub_err_t err;
grub_disk_t disk;
grub_cryptodisk_t dev;
char *diskname;
@@ -1178,13 +1192,13 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
return GRUB_ERR_NONE;
}
- err = grub_cryptodisk_scan_device_real (diskname, disk);
+ dev = grub_cryptodisk_scan_device_real (diskname, disk);
grub_disk_close (disk);
if (disklast)
*disklast = ')';
- return err;
+ return (dev == NULL) ? grub_errno : GRUB_ERR_NONE;
}
}

View File

@ -0,0 +1,29 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Glenn Washburn <development@efficientek.com>
Date: Thu, 9 Dec 2021 11:14:52 -0600
Subject: [PATCH] cryptodisk: Return failure in cryptomount when no cryptodisk
modules are loaded
This displays an error notifying the user that they'll want to load
a backend module to make cryptomount useful.
Signed-off-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/disk/cryptodisk.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index 9df3d31..2749187 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -1125,6 +1125,9 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
if (argc < 1 && !state[1].set && !state[2].set)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
+ if (grub_cryptodisk_list == NULL)
+ return grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk modules loaded");
+
if (state[0].set)
{
int found_uuid;

View File

@ -0,0 +1,55 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Glenn Washburn <development@efficientek.com>
Date: Thu, 9 Dec 2021 11:14:53 -0600
Subject: [PATCH] cryptodisk: Improve error messaging in cryptomount
invocations
Update such that "cryptomount -u UUID" will not print two error messages
when an invalid passphrase is given and the most relevant error message
will be displayed.
Signed-off-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/disk/cryptodisk.c | 21 +++++++++++++++++----
1 file changed, 17 insertions(+), 4 deletions(-)
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index 2749187..3a896c6 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -1109,7 +1109,10 @@ grub_cryptodisk_scan_device (const char *name,
if (grub_errno == GRUB_ERR_BAD_MODULE)
grub_error_pop ();
- if (grub_errno != GRUB_ERR_NONE)
+ if (search_uuid != NULL)
+ /* Push error onto stack to save for cryptomount. */
+ grub_error_push ();
+ else
grub_print_error ();
cleanup:
@@ -1146,9 +1149,19 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, NULL);
search_uuid = NULL;
- if (!found_uuid)
- return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such cryptodisk found");
- return GRUB_ERR_NONE;
+ if (found_uuid)
+ return GRUB_ERR_NONE;
+ else if (grub_errno == GRUB_ERR_NONE)
+ {
+ /*
+ * Try to pop the next error on the stack. If there is not one, then
+ * no device matched the given UUID.
+ */
+ grub_error_pop ();
+ if (grub_errno == GRUB_ERR_NONE)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such cryptodisk found");
+ }
+ return grub_errno;
}
else if (state[1].set || (argc == 0 && state[2].set))
{

View File

@ -0,0 +1,28 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Glenn Washburn <development@efficientek.com>
Date: Thu, 9 Dec 2021 11:14:54 -0600
Subject: [PATCH] cryptodisk: Improve cryptomount -u error message
When a cryptmount is specified with a UUID, but no cryptodisk backends find
a disk with that UUID, return a more detailed message giving telling the
user that they might not have a needed cryptobackend module loaded.
Signed-off-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/disk/cryptodisk.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index 3a896c6..5a9780b 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -1159,7 +1159,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
*/
grub_error_pop ();
if (grub_errno == GRUB_ERR_NONE)
- return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such cryptodisk found");
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such cryptodisk found, perhaps a needed disk or cryptodisk module is not loaded");
}
return grub_errno;
}

View File

@ -0,0 +1,249 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Glenn Washburn <development@efficientek.com>
Date: Thu, 9 Dec 2021 11:14:55 -0600
Subject: [PATCH] cryptodisk: Add infrastructure to pass data from cryptomount
to cryptodisk modules
Previously, the cryptomount arguments were passed by global variable and
function call argument, neither of which are ideal. This change passes data
via a grub_cryptomount_args struct, which can be added to over time as
opposed to continually adding arguments to the cryptodisk scan and
recover_key.
As an example, passing a password as a cryptomount argument is implemented.
However, the backends are not implemented, so testing this will return a not
implemented error.
Also, add comments to cryptomount argument parsing to make it more obvious
which argument states are being handled.
Signed-off-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/disk/cryptodisk.c | 31 +++++++++++++++++++++----------
grub-core/disk/geli.c | 6 +++++-
grub-core/disk/luks.c | 7 ++++++-
grub-core/disk/luks2.c | 7 ++++++-
include/grub/cryptodisk.h | 9 ++++++++-
5 files changed, 46 insertions(+), 14 deletions(-)
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index 5a9780b..14c661a 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -41,6 +41,7 @@ static const struct grub_arg_option options[] =
/* TRANSLATORS: It's still restricted to cryptodisks only. */
{"all", 'a', 0, N_("Mount all."), 0, 0},
{"boot", 'b', 0, N_("Mount all volumes with `boot' flag set."), 0, 0},
+ {"password", 'p', 0, N_("Password to open volumes."), 0, ARG_TYPE_STRING},
{0, 0, 0, 0, 0, 0}
};
@@ -996,7 +997,9 @@ cryptodisk_close (grub_cryptodisk_t dev)
}
static grub_cryptodisk_t
-grub_cryptodisk_scan_device_real (const char *name, grub_disk_t source)
+grub_cryptodisk_scan_device_real (const char *name,
+ grub_disk_t source,
+ grub_cryptomount_args_t cargs)
{
grub_err_t err;
grub_cryptodisk_t dev;
@@ -1015,7 +1018,7 @@ grub_cryptodisk_scan_device_real (const char *name, grub_disk_t source)
if (!dev)
continue;
- err = cr->recover_key (source, dev);
+ err = cr->recover_key (source, dev, cargs);
if (err)
{
cryptodisk_close (dev);
@@ -1080,11 +1083,12 @@ grub_cryptodisk_cheat_mount (const char *sourcedev, const char *cheat)
static int
grub_cryptodisk_scan_device (const char *name,
- void *data __attribute__ ((unused)))
+ void *data)
{
int ret = 0;
grub_disk_t source;
grub_cryptodisk_t dev;
+ grub_cryptomount_args_t cargs = data;
grub_errno = GRUB_ERR_NONE;
/* Try to open disk. */
@@ -1095,7 +1099,7 @@ grub_cryptodisk_scan_device (const char *name,
return 0;
}
- dev = grub_cryptodisk_scan_device_real (name, source);
+ dev = grub_cryptodisk_scan_device_real (name, source, cargs);
if (dev)
{
ret = (search_uuid != NULL && grub_strcasecmp (search_uuid, dev->uuid) == 0);
@@ -1124,6 +1128,7 @@ static grub_err_t
grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
{
struct grub_arg_list *state = ctxt->state;
+ struct grub_cryptomount_args cargs = {0};
if (argc < 1 && !state[1].set && !state[2].set)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
@@ -1131,7 +1136,13 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
if (grub_cryptodisk_list == NULL)
return grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk modules loaded");
- if (state[0].set)
+ if (state[3].set) /* password */
+ {
+ cargs.key_data = (grub_uint8_t *) state[3].arg;
+ cargs.key_len = grub_strlen (state[3].arg);
+ }
+
+ if (state[0].set) /* uuid */
{
int found_uuid;
grub_cryptodisk_t dev;
@@ -1146,7 +1157,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
check_boot = state[2].set;
search_uuid = args[0];
- found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, NULL);
+ found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, &cargs);
search_uuid = NULL;
if (found_uuid)
@@ -1163,11 +1174,11 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
}
return grub_errno;
}
- else if (state[1].set || (argc == 0 && state[2].set))
+ else if (state[1].set || (argc == 0 && state[2].set)) /* -a|-b */
{
search_uuid = NULL;
check_boot = state[2].set;
- grub_device_iterate (&grub_cryptodisk_scan_device, NULL);
+ grub_device_iterate (&grub_cryptodisk_scan_device, &cargs);
search_uuid = NULL;
return GRUB_ERR_NONE;
}
@@ -1208,7 +1219,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
return GRUB_ERR_NONE;
}
- dev = grub_cryptodisk_scan_device_real (diskname, disk);
+ dev = grub_cryptodisk_scan_device_real (diskname, disk, &cargs);
grub_disk_close (disk);
if (disklast)
@@ -1347,7 +1358,7 @@ GRUB_MOD_INIT (cryptodisk)
{
grub_disk_dev_register (&grub_cryptodisk_dev);
cmd = grub_register_extcmd ("cryptomount", grub_cmd_cryptomount, 0,
- N_("SOURCE|-u UUID|-a|-b"),
+ N_("[-p password] <SOURCE|-u UUID|-a|-b>"),
N_("Mount a crypto device."), options);
grub_procfs_register ("luks_script", &luks_script);
}
diff --git a/grub-core/disk/geli.c b/grub-core/disk/geli.c
index 2f34a35..777da3a 100644
--- a/grub-core/disk/geli.c
+++ b/grub-core/disk/geli.c
@@ -398,7 +398,7 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid,
}
static grub_err_t
-recover_key (grub_disk_t source, grub_cryptodisk_t dev)
+recover_key (grub_disk_t source, grub_cryptodisk_t dev, grub_cryptomount_args_t cargs)
{
grub_size_t keysize;
grub_uint8_t digest[GRUB_CRYPTO_MAX_MDLEN];
@@ -414,6 +414,10 @@ recover_key (grub_disk_t source, grub_cryptodisk_t dev)
grub_disk_addr_t sector;
grub_err_t err;
+ /* Keyfiles are not implemented yet */
+ if (cargs->key_data != NULL || cargs->key_len)
+ return GRUB_ERR_NOT_IMPLEMENTED_YET;
+
if (dev->cipher->cipher->blocksize > GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE)
return grub_error (GRUB_ERR_BUG, "cipher block is too long");
diff --git a/grub-core/disk/luks.c b/grub-core/disk/luks.c
index 13103ea..c5858fc 100644
--- a/grub-core/disk/luks.c
+++ b/grub-core/disk/luks.c
@@ -152,7 +152,8 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid,
static grub_err_t
luks_recover_key (grub_disk_t source,
- grub_cryptodisk_t dev)
+ grub_cryptodisk_t dev,
+ grub_cryptomount_args_t cargs)
{
struct grub_luks_phdr header;
grub_size_t keysize;
@@ -165,6 +166,10 @@ luks_recover_key (grub_disk_t source,
grub_size_t max_stripes = 1;
char *tmp;
+ /* Keyfiles are not implemented yet */
+ if (cargs->key_data != NULL || cargs->key_len)
+ return GRUB_ERR_NOT_IMPLEMENTED_YET;
+
err = grub_disk_read (source, 0, 0, sizeof (header), &header);
if (err)
return err;
diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c
index c917a5f..8a9f42d 100644
--- a/grub-core/disk/luks2.c
+++ b/grub-core/disk/luks2.c
@@ -542,7 +542,8 @@ luks2_decrypt_key (grub_uint8_t *out_key,
static grub_err_t
luks2_recover_key (grub_disk_t source,
- grub_cryptodisk_t crypt)
+ grub_cryptodisk_t crypt,
+ grub_cryptomount_args_t cargs)
{
grub_uint8_t candidate_key[GRUB_CRYPTODISK_MAX_KEYLEN];
char passphrase[MAX_PASSPHRASE], cipher[32];
@@ -556,6 +557,10 @@ luks2_recover_key (grub_disk_t source,
grub_json_t *json = NULL, keyslots;
grub_err_t ret;
+ /* Keyfiles are not implemented yet */
+ if (cargs->key_data != NULL || cargs->key_len)
+ return GRUB_ERR_NOT_IMPLEMENTED_YET;
+
ret = luks2_read_header (source, &header);
if (ret)
return ret;
diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h
index dcf17fb..282f8ac 100644
--- a/include/grub/cryptodisk.h
+++ b/include/grub/cryptodisk.h
@@ -66,6 +66,13 @@ typedef gcry_err_code_t
(*grub_cryptodisk_rekey_func_t) (struct grub_cryptodisk *dev,
grub_uint64_t zoneno);
+struct grub_cryptomount_args
+{
+ grub_uint8_t *key_data;
+ grub_size_t key_len;
+};
+typedef struct grub_cryptomount_args *grub_cryptomount_args_t;
+
struct grub_cryptodisk
{
struct grub_cryptodisk *next;
@@ -119,7 +126,7 @@ struct grub_cryptodisk_dev
grub_cryptodisk_t (*scan) (grub_disk_t disk, const char *check_uuid,
int boot_only);
- grub_err_t (*recover_key) (grub_disk_t disk, grub_cryptodisk_t dev);
+ grub_err_t (*recover_key) (grub_disk_t disk, grub_cryptodisk_t dev, grub_cryptomount_args_t cargs);
};
typedef struct grub_cryptodisk_dev *grub_cryptodisk_dev_t;

View File

@ -0,0 +1,339 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Glenn Washburn <development@efficientek.com>
Date: Thu, 9 Dec 2021 11:14:56 -0600
Subject: [PATCH] cryptodisk: Refactor password input out of crypto dev modules
into cryptodisk
The crypto device modules should only be setting up the crypto devices and
not getting user input. This has the added benefit of simplifying the code
such that three essentially duplicate pieces of code are merged into one.
Add documentation of passphrase option for cryptomount as it is now usable.
Signed-off-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
docs/grub.texi | 8 ++++---
grub-core/disk/cryptodisk.c | 56 ++++++++++++++++++++++++++++++++++++---------
grub-core/disk/geli.c | 26 ++++-----------------
grub-core/disk/luks.c | 27 ++++------------------
grub-core/disk/luks2.c | 25 ++++----------------
include/grub/cryptodisk.h | 1 +
6 files changed, 64 insertions(+), 79 deletions(-)
diff --git a/docs/grub.texi b/docs/grub.texi
index b39cdf2..3c7d99e 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -4329,9 +4329,11 @@ Alias for @code{hashsum --hash crc32 arg @dots{}}. See command @command{hashsum}
@node cryptomount
@subsection cryptomount
-@deffn Command cryptomount device|@option{-u} uuid|@option{-a}|@option{-b}
-Setup access to encrypted device. If necessary, passphrase
-is requested interactively. Option @var{device} configures specific grub device
+@deffn Command cryptomount [@option{-p} password] device|@option{-u} uuid|@option{-a}|@option{-b}
+Setup access to encrypted device. If @option{-p} is not given, a passphrase
+is requested interactively. Otherwise, the given @var{password} will be used and
+no passphrase will be requested interactively.
+Option @var{device} configures specific grub device
(@pxref{Naming convention}); option @option{-u} @var{uuid} configures device
with specified @var{uuid}; option @option{-a} configures all detected encrypted
devices; option @option{-b} configures all geli containers that have boot flag set.
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index 14c661a..d12368a 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -1001,9 +1001,11 @@ grub_cryptodisk_scan_device_real (const char *name,
grub_disk_t source,
grub_cryptomount_args_t cargs)
{
- grub_err_t err;
+ grub_err_t ret = GRUB_ERR_NONE;
grub_cryptodisk_t dev;
grub_cryptodisk_dev_t cr;
+ int askpass = 0;
+ char *part = NULL;
dev = grub_cryptodisk_get_by_source_disk (source);
@@ -1017,21 +1019,53 @@ grub_cryptodisk_scan_device_real (const char *name,
return NULL;
if (!dev)
continue;
-
- err = cr->recover_key (source, dev, cargs);
- if (err)
- {
- cryptodisk_close (dev);
- return NULL;
- }
+
+ if (!cargs->key_len)
+ {
+ /* Get the passphrase from the user, if no key data. */
+ askpass = 1;
+ if (source->partition != NULL)
+ part = grub_partition_get_name (source->partition);
+ grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name,
+ source->partition != NULL ? "," : "",
+ part != NULL ? part : "",
+ dev->uuid);
+ grub_free (part);
+
+ cargs->key_data = grub_malloc (GRUB_CRYPTODISK_MAX_PASSPHRASE);
+ if (cargs->key_data == NULL)
+ return NULL;
+
+ if (!grub_password_get ((char *) cargs->key_data, GRUB_CRYPTODISK_MAX_PASSPHRASE))
+ {
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "passphrase not supplied");
+ goto error;
+ }
+ cargs->key_len = grub_strlen ((char *) cargs->key_data);
+ }
+
+ ret = cr->recover_key (source, dev, cargs);
+ if (ret != GRUB_ERR_NONE)
+ goto error;
grub_cryptodisk_insert (dev, name, source);
- return dev;
+ goto cleanup;
}
-
grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk module can handle this device");
- return NULL;
+ goto cleanup;
+
+ error:
+ cryptodisk_close (dev);
+ dev = NULL;
+
+ cleanup:
+ if (askpass)
+ {
+ cargs->key_len = 0;
+ grub_free (cargs->key_data);
+ }
+ return dev;
}
#ifdef GRUB_UTIL
diff --git a/grub-core/disk/geli.c b/grub-core/disk/geli.c
index 777da3a..7299a47 100644
--- a/grub-core/disk/geli.c
+++ b/grub-core/disk/geli.c
@@ -135,8 +135,6 @@ const char *algorithms[] = {
[0x16] = "aes"
};
-#define MAX_PASSPHRASE 256
-
static gcry_err_code_t
geli_rekey (struct grub_cryptodisk *dev, grub_uint64_t zoneno)
{
@@ -406,17 +404,14 @@ recover_key (grub_disk_t source, grub_cryptodisk_t dev, grub_cryptomount_args_t
grub_uint8_t verify_key[GRUB_CRYPTO_MAX_MDLEN];
grub_uint8_t zero[GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE];
grub_uint8_t geli_cipher_key[64];
- char passphrase[MAX_PASSPHRASE] = "";
unsigned i;
gcry_err_code_t gcry_err;
struct grub_geli_phdr header;
- char *tmp;
grub_disk_addr_t sector;
grub_err_t err;
- /* Keyfiles are not implemented yet */
- if (cargs->key_data != NULL || cargs->key_len)
- return GRUB_ERR_NOT_IMPLEMENTED_YET;
+ if (cargs->key_data == NULL || cargs->key_len == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no key data");
if (dev->cipher->cipher->blocksize > GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE)
return grub_error (GRUB_ERR_BUG, "cipher block is too long");
@@ -438,23 +433,12 @@ recover_key (grub_disk_t source, grub_cryptodisk_t dev, grub_cryptomount_args_t
grub_puts_ (N_("Attempting to decrypt master key..."));
- /* Get the passphrase from the user. */
- tmp = NULL;
- if (source->partition)
- tmp = grub_partition_get_name (source->partition);
- grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name,
- source->partition ? "," : "", tmp ? : "",
- dev->uuid);
- grub_free (tmp);
- if (!grub_password_get (passphrase, MAX_PASSPHRASE))
- return grub_error (GRUB_ERR_BAD_ARGUMENT, "Passphrase not supplied");
-
/* Calculate the PBKDF2 of the user supplied passphrase. */
if (grub_le_to_cpu32 (header.niter) != 0)
{
grub_uint8_t pbkdf_key[64];
- gcry_err = grub_crypto_pbkdf2 (dev->hash, (grub_uint8_t *) passphrase,
- grub_strlen (passphrase),
+ gcry_err = grub_crypto_pbkdf2 (dev->hash, cargs->key_data,
+ cargs->key_len,
header.salt,
sizeof (header.salt),
grub_le_to_cpu32 (header.niter),
@@ -477,7 +461,7 @@ recover_key (grub_disk_t source, grub_cryptodisk_t dev, grub_cryptomount_args_t
return grub_crypto_gcry_error (GPG_ERR_OUT_OF_MEMORY);
grub_crypto_hmac_write (hnd, header.salt, sizeof (header.salt));
- grub_crypto_hmac_write (hnd, passphrase, grub_strlen (passphrase));
+ grub_crypto_hmac_write (hnd, cargs->key_data, cargs->key_len);
gcry_err = grub_crypto_hmac_fini (hnd, geomkey);
if (gcry_err)
diff --git a/grub-core/disk/luks.c b/grub-core/disk/luks.c
index c5858fc..39a7af6 100644
--- a/grub-core/disk/luks.c
+++ b/grub-core/disk/luks.c
@@ -29,8 +29,6 @@
GRUB_MOD_LICENSE ("GPLv3+");
-#define MAX_PASSPHRASE 256
-
#define LUKS_KEY_ENABLED 0x00AC71F3
/* On disk LUKS header */
@@ -158,17 +156,14 @@ luks_recover_key (grub_disk_t source,
struct grub_luks_phdr header;
grub_size_t keysize;
grub_uint8_t *split_key = NULL;
- char passphrase[MAX_PASSPHRASE] = "";
grub_uint8_t candidate_digest[sizeof (header.mkDigest)];
unsigned i;
grub_size_t length;
grub_err_t err;
grub_size_t max_stripes = 1;
- char *tmp;
- /* Keyfiles are not implemented yet */
- if (cargs->key_data != NULL || cargs->key_len)
- return GRUB_ERR_NOT_IMPLEMENTED_YET;
+ if (cargs->key_data == NULL || cargs->key_len == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no key data");
err = grub_disk_read (source, 0, 0, sizeof (header), &header);
if (err)
@@ -188,20 +183,6 @@ luks_recover_key (grub_disk_t source,
if (!split_key)
return grub_errno;
- /* Get the passphrase from the user. */
- tmp = NULL;
- if (source->partition)
- tmp = grub_partition_get_name (source->partition);
- grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name,
- source->partition ? "," : "", tmp ? : "",
- dev->uuid);
- grub_free (tmp);
- if (!grub_password_get (passphrase, MAX_PASSPHRASE))
- {
- grub_free (split_key);
- return grub_error (GRUB_ERR_BAD_ARGUMENT, "Passphrase not supplied");
- }
-
/* Try to recover master key from each active keyslot. */
for (i = 0; i < ARRAY_SIZE (header.keyblock); i++)
{
@@ -216,8 +197,8 @@ luks_recover_key (grub_disk_t source,
grub_dprintf ("luks", "Trying keyslot %d\n", i);
/* Calculate the PBKDF2 of the user supplied passphrase. */
- gcry_err = grub_crypto_pbkdf2 (dev->hash, (grub_uint8_t *) passphrase,
- grub_strlen (passphrase),
+ gcry_err = grub_crypto_pbkdf2 (dev->hash, cargs->key_data,
+ cargs->key_len,
header.keyblock[i].passwordSalt,
sizeof (header.keyblock[i].passwordSalt),
grub_be_to_cpu32 (header.keyblock[i].
diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c
index 8a9f42d..0425100 100644
--- a/grub-core/disk/luks2.c
+++ b/grub-core/disk/luks2.c
@@ -35,8 +35,6 @@ GRUB_MOD_LICENSE ("GPLv3+");
#define LUKS_MAGIC_1ST "LUKS\xBA\xBE"
#define LUKS_MAGIC_2ND "SKUL\xBA\xBE"
-#define MAX_PASSPHRASE 256
-
enum grub_luks2_kdf_type
{
LUKS2_KDF_TYPE_ARGON2I,
@@ -546,8 +544,7 @@ luks2_recover_key (grub_disk_t source,
grub_cryptomount_args_t cargs)
{
grub_uint8_t candidate_key[GRUB_CRYPTODISK_MAX_KEYLEN];
- char passphrase[MAX_PASSPHRASE], cipher[32];
- char *json_header = NULL, *part = NULL, *ptr;
+ char cipher[32], *json_header = NULL, *ptr;
grub_size_t candidate_key_len = 0, json_idx, size;
grub_luks2_header_t header;
grub_luks2_keyslot_t keyslot;
@@ -557,9 +554,8 @@ luks2_recover_key (grub_disk_t source,
grub_json_t *json = NULL, keyslots;
grub_err_t ret;
- /* Keyfiles are not implemented yet */
- if (cargs->key_data != NULL || cargs->key_len)
- return GRUB_ERR_NOT_IMPLEMENTED_YET;
+ if (cargs->key_data == NULL || cargs->key_len == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no key data");
ret = luks2_read_header (source, &header);
if (ret)
@@ -586,18 +582,6 @@ luks2_recover_key (grub_disk_t source,
goto err;
}
- /* Get the passphrase from the user. */
- if (source->partition)
- part = grub_partition_get_name (source->partition);
- grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name,
- source->partition ? "," : "", part ? : "",
- crypt->uuid);
- if (!grub_password_get (passphrase, MAX_PASSPHRASE))
- {
- ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Passphrase not supplied");
- goto err;
- }
-
if (grub_json_getvalue (&keyslots, json, "keyslots") ||
grub_json_getsize (&size, &keyslots))
{
@@ -722,7 +706,7 @@ luks2_recover_key (grub_disk_t source,
}
ret = luks2_decrypt_key (candidate_key, source, crypt, &keyslot,
- (const grub_uint8_t *) passphrase, grub_strlen (passphrase));
+ cargs->key_data, cargs->key_len);
if (ret)
{
grub_dprintf ("luks2", "Decryption with keyslot \"%" PRIuGRUB_UINT64_T "\" failed: %s\n",
@@ -774,7 +758,6 @@ luks2_recover_key (grub_disk_t source,
}
err:
- grub_free (part);
grub_free (json_header);
grub_json_free (json);
return ret;
diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h
index 282f8ac..5bd9706 100644
--- a/include/grub/cryptodisk.h
+++ b/include/grub/cryptodisk.h
@@ -59,6 +59,7 @@ typedef enum
#define GRUB_CRYPTODISK_GF_LOG_BYTES (GRUB_CRYPTODISK_GF_LOG_SIZE - 3)
#define GRUB_CRYPTODISK_GF_BYTES (1U << GRUB_CRYPTODISK_GF_LOG_BYTES)
#define GRUB_CRYPTODISK_MAX_KEYLEN 128
+#define GRUB_CRYPTODISK_MAX_PASSPHRASE 256
struct grub_cryptodisk;

View File

@ -0,0 +1,27 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Glenn Washburn <development@efficientek.com>
Date: Thu, 9 Dec 2021 11:14:50 -0600
Subject: [PATCH] luks2: Add debug message to align with luks and geli modules
Signed-off-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/disk/luks2.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c
index 0425100..caed4d4 100644
--- a/grub-core/disk/luks2.c
+++ b/grub-core/disk/luks2.c
@@ -368,7 +368,10 @@ luks2_scan (grub_disk_t disk, const char *check_uuid, int check_boot)
uuid[j] = '\0';
if (check_uuid && grub_strcasecmp (check_uuid, uuid) != 0)
- return NULL;
+ {
+ grub_dprintf ("luks2", "%s != %s\n", uuid, check_uuid);
+ return NULL;
+ }
cryptodisk = grub_zalloc (sizeof (*cryptodisk));
if (!cryptodisk)

View File

@ -0,0 +1,245 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Glenn Washburn <development@efficientek.com>
Date: Thu, 9 Dec 2021 11:14:57 -0600
Subject: [PATCH] cryptodisk: Move global variables into grub_cryptomount_args
struct
Note that cargs.search_uuid does not need to be initialized in various parts
of the cryptomount argument parsing, just once when cargs is declared with
a struct initializer. The previous code used a global variable which would
retain the value across cryptomount invocations.
Signed-off-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/disk/cryptodisk.c | 24 +++++++++---------------
grub-core/disk/geli.c | 9 ++++-----
grub-core/disk/luks.c | 9 ++++-----
grub-core/disk/luks2.c | 8 ++++----
include/grub/cryptodisk.h | 9 +++++++--
5 files changed, 28 insertions(+), 31 deletions(-)
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index d12368a..7ca8804 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -984,9 +984,6 @@ grub_util_cryptodisk_get_uuid (grub_disk_t disk)
#endif
-static int check_boot;
-static char *search_uuid;
-
static void
cryptodisk_close (grub_cryptodisk_t dev)
{
@@ -1014,7 +1011,7 @@ grub_cryptodisk_scan_device_real (const char *name,
FOR_CRYPTODISK_DEVS (cr)
{
- dev = cr->scan (source, search_uuid, check_boot);
+ dev = cr->scan (source, cargs);
if (grub_errno)
return NULL;
if (!dev)
@@ -1077,6 +1074,7 @@ grub_cryptodisk_cheat_mount (const char *sourcedev, const char *cheat)
grub_cryptodisk_t dev;
grub_cryptodisk_dev_t cr;
grub_disk_t source;
+ struct grub_cryptomount_args cargs = {0};
/* Try to open disk. */
source = grub_disk_open (sourcedev);
@@ -1093,7 +1091,7 @@ grub_cryptodisk_cheat_mount (const char *sourcedev, const char *cheat)
FOR_CRYPTODISK_DEVS (cr)
{
- dev = cr->scan (source, search_uuid, check_boot);
+ dev = cr->scan (source, &cargs);
if (grub_errno)
return grub_errno;
if (!dev)
@@ -1136,7 +1134,7 @@ grub_cryptodisk_scan_device (const char *name,
dev = grub_cryptodisk_scan_device_real (name, source, cargs);
if (dev)
{
- ret = (search_uuid != NULL && grub_strcasecmp (search_uuid, dev->uuid) == 0);
+ ret = (cargs->search_uuid != NULL && grub_strcasecmp (cargs->search_uuid, dev->uuid) == 0);
goto cleanup;
}
@@ -1147,7 +1145,7 @@ grub_cryptodisk_scan_device (const char *name,
if (grub_errno == GRUB_ERR_BAD_MODULE)
grub_error_pop ();
- if (search_uuid != NULL)
+ if (cargs->search_uuid != NULL)
/* Push error onto stack to save for cryptomount. */
grub_error_push ();
else
@@ -1189,10 +1187,9 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
return GRUB_ERR_NONE;
}
- check_boot = state[2].set;
- search_uuid = args[0];
+ cargs.check_boot = state[2].set;
+ cargs.search_uuid = args[0];
found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, &cargs);
- search_uuid = NULL;
if (found_uuid)
return GRUB_ERR_NONE;
@@ -1210,10 +1207,8 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
}
else if (state[1].set || (argc == 0 && state[2].set)) /* -a|-b */
{
- search_uuid = NULL;
- check_boot = state[2].set;
+ cargs.check_boot = state[2].set;
grub_device_iterate (&grub_cryptodisk_scan_device, &cargs);
- search_uuid = NULL;
return GRUB_ERR_NONE;
}
else
@@ -1224,8 +1219,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
char *disklast = NULL;
grub_size_t len;
- search_uuid = NULL;
- check_boot = state[2].set;
+ cargs.check_boot = state[2].set;
diskname = args[0];
len = grub_strlen (diskname);
if (len && diskname[0] == '(' && diskname[len - 1] == ')')
diff --git a/grub-core/disk/geli.c b/grub-core/disk/geli.c
index 7299a47..23789c4 100644
--- a/grub-core/disk/geli.c
+++ b/grub-core/disk/geli.c
@@ -240,8 +240,7 @@ grub_util_get_geli_uuid (const char *dev)
#endif
static grub_cryptodisk_t
-configure_ciphers (grub_disk_t disk, const char *check_uuid,
- int boot_only)
+configure_ciphers (grub_disk_t disk, grub_cryptomount_args_t cargs)
{
grub_cryptodisk_t newdev;
struct grub_geli_phdr header;
@@ -289,7 +288,7 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid,
return NULL;
}
- if (boot_only && !(grub_le_to_cpu32 (header.flags) & GRUB_GELI_FLAGS_BOOT))
+ if (cargs->check_boot && !(grub_le_to_cpu32 (header.flags) & GRUB_GELI_FLAGS_BOOT))
{
grub_dprintf ("geli", "not a boot volume\n");
return NULL;
@@ -302,9 +301,9 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid,
return NULL;
}
- if (check_uuid && grub_strcasecmp (check_uuid, uuid) != 0)
+ if (cargs->search_uuid != NULL && grub_strcasecmp (cargs->search_uuid, uuid) != 0)
{
- grub_dprintf ("geli", "%s != %s\n", uuid, check_uuid);
+ grub_dprintf ("geli", "%s != %s\n", uuid, cargs->search_uuid);
return NULL;
}
diff --git a/grub-core/disk/luks.c b/grub-core/disk/luks.c
index 39a7af6..f0feb38 100644
--- a/grub-core/disk/luks.c
+++ b/grub-core/disk/luks.c
@@ -63,8 +63,7 @@ gcry_err_code_t AF_merge (const gcry_md_spec_t * hash, grub_uint8_t * src,
grub_size_t blocknumbers);
static grub_cryptodisk_t
-configure_ciphers (grub_disk_t disk, const char *check_uuid,
- int check_boot)
+configure_ciphers (grub_disk_t disk, grub_cryptomount_args_t cargs)
{
grub_cryptodisk_t newdev;
const char *iptr;
@@ -76,7 +75,7 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid,
char hashspec[sizeof (header.hashSpec) + 1];
grub_err_t err;
- if (check_boot)
+ if (cargs->check_boot)
return NULL;
/* Read the LUKS header. */
@@ -103,9 +102,9 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid,
}
*optr = 0;
- if (check_uuid && grub_strcasecmp (check_uuid, uuid) != 0)
+ if (cargs->search_uuid != NULL && grub_strcasecmp (cargs->search_uuid, uuid) != 0)
{
- grub_dprintf ("luks", "%s != %s\n", uuid, check_uuid);
+ grub_dprintf ("luks", "%s != %s\n", uuid, cargs->search_uuid);
return NULL;
}
diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c
index caed4d4..bf741d7 100644
--- a/grub-core/disk/luks2.c
+++ b/grub-core/disk/luks2.c
@@ -346,14 +346,14 @@ luks2_read_header (grub_disk_t disk, grub_luks2_header_t *outhdr)
}
static grub_cryptodisk_t
-luks2_scan (grub_disk_t disk, const char *check_uuid, int check_boot)
+luks2_scan (grub_disk_t disk, grub_cryptomount_args_t cargs)
{
grub_cryptodisk_t cryptodisk;
grub_luks2_header_t header;
char uuid[sizeof (header.uuid) + 1];
grub_size_t i, j;
- if (check_boot)
+ if (cargs->check_boot)
return NULL;
if (luks2_read_header (disk, &header))
@@ -367,9 +367,9 @@ luks2_scan (grub_disk_t disk, const char *check_uuid, int check_boot)
uuid[j++] = header.uuid[i];
uuid[j] = '\0';
- if (check_uuid && grub_strcasecmp (check_uuid, uuid) != 0)
+ if (cargs->search_uuid != NULL && grub_strcasecmp (cargs->search_uuid, uuid) != 0)
{
- grub_dprintf ("luks2", "%s != %s\n", uuid, check_uuid);
+ grub_dprintf ("luks2", "%s != %s\n", uuid, cargs->search_uuid);
return NULL;
}
diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h
index 5bd9706..c6524c9 100644
--- a/include/grub/cryptodisk.h
+++ b/include/grub/cryptodisk.h
@@ -69,7 +69,13 @@ typedef gcry_err_code_t
struct grub_cryptomount_args
{
+ /* scan: Flag to indicate that only bootable volumes should be decrypted */
+ grub_uint32_t check_boot : 1;
+ /* scan: Only volumes matching this UUID should be decrpyted */
+ char *search_uuid;
+ /* recover_key: Key data used to decrypt voume */
grub_uint8_t *key_data;
+ /* recover_key: Length of key_data */
grub_size_t key_len;
};
typedef struct grub_cryptomount_args *grub_cryptomount_args_t;
@@ -125,8 +131,7 @@ struct grub_cryptodisk_dev
struct grub_cryptodisk_dev *next;
struct grub_cryptodisk_dev **prev;
- grub_cryptodisk_t (*scan) (grub_disk_t disk, const char *check_uuid,
- int boot_only);
+ grub_cryptodisk_t (*scan) (grub_disk_t disk, grub_cryptomount_args_t cargs);
grub_err_t (*recover_key) (grub_disk_t disk, grub_cryptodisk_t dev, grub_cryptomount_args_t cargs);
};
typedef struct grub_cryptodisk_dev *grub_cryptodisk_dev_t;

View File

@ -0,0 +1,36 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Glenn Washburn <development@efficientek.com>
Date: Thu, 9 Dec 2021 11:14:58 -0600
Subject: [PATCH] cryptodisk: Improve handling of partition name in cryptomount
password prompt
Call grub_partition_get_name() unconditionally to initialize the part
variable. Then part will only be NULL when grub_partition_get_name() errors.
Note that when source->partition is NULL, then grub_partition_get_name()
returns an allocated empty string. So no comma or partition will be printed,
as desired.
Signed-off-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/disk/cryptodisk.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index 7ca8804..4970973 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -1021,11 +1021,10 @@ grub_cryptodisk_scan_device_real (const char *name,
{
/* Get the passphrase from the user, if no key data. */
askpass = 1;
- if (source->partition != NULL)
- part = grub_partition_get_name (source->partition);
+ part = grub_partition_get_name (source->partition);
grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name,
source->partition != NULL ? "," : "",
- part != NULL ? part : "",
+ part != NULL ? part : N_("UNKNOWN"),
dev->uuid);
grub_free (part);

View File

@ -0,0 +1,72 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Glenn Washburn <development@efficientek.com>
Date: Sat, 1 Jan 2022 15:48:25 -0600
Subject: [PATCH] cryptodisk: Fix Coverity use after free bug
The Coverity output is:
*** CID 366905: Memory - illegal accesses (USE_AFTER_FREE)
/grub-core/disk/cryptodisk.c: 1064 in grub_cryptodisk_scan_device_real()
1058 cleanup:
1059 if (askpass)
1060 {
1061 cargs->key_len = 0;
1062 grub_free (cargs->key_data);
1063 }
>>> CID 366905: Memory - illegal accesses (USE_AFTER_FREE)
>>> Using freed pointer "dev".
1064 return dev;
1065 }
1066
1067 #ifdef GRUB_UTIL
1068 #include <grub/util/misc.h>
1069 grub_err_t
Here the "dev" variable can point to a freed cryptodisk device if the
function grub_cryptodisk_insert() fails. This can happen only on a OOM
condition, but when this happens grub_cryptodisk_insert() calls grub_free on
the passed device. Since grub_cryptodisk_scan_device_real() assumes that
grub_cryptodisk_insert() is always successful, it will return the device,
though the device was freed.
Change grub_cryptodisk_insert() to not free the passed device on failure.
Then on grub_cryptodisk_insert() failure, free the device pointer. This is
done by going to the label "error", which will call cryptodisk_close() to
free the device and set the device pointer to NULL, so that a pointer to
freed memory is not returned.
Fixes: CID 366905
Signed-off-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/disk/cryptodisk.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index 4970973..e7c4795 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -889,10 +889,7 @@ grub_cryptodisk_insert (grub_cryptodisk_t newdev, const char *name,
{
newdev->source = grub_strdup (name);
if (!newdev->source)
- {
- grub_free (newdev);
- return grub_errno;
- }
+ return grub_errno;
newdev->id = last_cryptodisk_id++;
newdev->source_id = source->id;
@@ -1044,7 +1041,9 @@ grub_cryptodisk_scan_device_real (const char *name,
if (ret != GRUB_ERR_NONE)
goto error;
- grub_cryptodisk_insert (dev, name, source);
+ ret = grub_cryptodisk_insert (dev, name, source);
+ if (ret != GRUB_ERR_NONE)
+ goto error;
goto cleanup;
}

View File

@ -0,0 +1,155 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: John Lane <john@lane.uk.net>
Date: Fri, 20 May 2022 14:32:17 -0500
Subject: [PATCH] disk/cryptodisk: Add options to cryptomount to support
keyfiles
Add the options --key-file, --keyfile-offset, and --keyfile-size to
cryptomount and code to put read the requested key file data and pass
via the cargs struct. Note, key file data is for all intents and purposes
equivalent to a password given to cryptomount. So there is no need to
enable support for key files in the various crypto backends (e.g. LUKS1)
because the key data is passed just as if it were a password.
Signed-off-by: John Lane <john@lane.uk.net>
Signed-off-by: Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
Signed-off-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/disk/cryptodisk.c | 81 ++++++++++++++++++++++++++++++++++++++++++++-
include/grub/cryptodisk.h | 2 ++
include/grub/file.h | 2 ++
3 files changed, 84 insertions(+), 1 deletion(-)
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index e7c4795..0706afa 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -42,6 +42,9 @@ static const struct grub_arg_option options[] =
{"all", 'a', 0, N_("Mount all."), 0, 0},
{"boot", 'b', 0, N_("Mount all volumes with `boot' flag set."), 0, 0},
{"password", 'p', 0, N_("Password to open volumes."), 0, ARG_TYPE_STRING},
+ {"key-file", 'k', 0, N_("Key file"), 0, ARG_TYPE_STRING},
+ {"keyfile-offset", 'O', 0, N_("Key file offset (bytes)"), 0, ARG_TYPE_INT},
+ {"keyfile-size", 'S', 0, N_("Key file data size (bytes)"), 0, ARG_TYPE_INT},
{0, 0, 0, 0, 0, 0}
};
@@ -1172,6 +1175,80 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
cargs.key_len = grub_strlen (state[3].arg);
}
+ if (state[4].set) /* keyfile */
+ {
+ const char *p = NULL;
+ grub_file_t keyfile;
+ unsigned long long keyfile_offset = 0, keyfile_size = 0;
+
+ if (state[5].set) /* keyfile-offset */
+ {
+ grub_errno = GRUB_ERR_NONE;
+ keyfile_offset = grub_strtoull (state[5].arg, &p, 0);
+
+ if (state[5].arg[0] == '\0' || *p != '\0')
+ return grub_error (grub_errno,
+ N_("non-numeric or invalid keyfile offset `%s'"),
+ state[5].arg);
+ }
+
+ if (state[6].set) /* keyfile-size */
+ {
+ grub_errno = GRUB_ERR_NONE;
+ keyfile_size = grub_strtoull (state[6].arg, &p, 0);
+
+ if (state[6].arg[0] == '\0' || *p != '\0')
+ return grub_error (grub_errno,
+ N_("non-numeric or invalid keyfile size `%s'"),
+ state[6].arg);
+
+ if (keyfile_size == 0)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("key file size is 0"));
+
+ if (keyfile_size > GRUB_CRYPTODISK_MAX_KEYFILE_SIZE)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("key file size exceeds maximum (%d)"),
+ GRUB_CRYPTODISK_MAX_KEYFILE_SIZE);
+ }
+
+ keyfile = grub_file_open (state[4].arg,
+ GRUB_FILE_TYPE_CRYPTODISK_ENCRYPTION_KEY);
+ if (keyfile == NULL)
+ return grub_errno;
+
+ if (keyfile_offset > keyfile->size)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("Keyfile offset, %llu, is greater than"
+ "keyfile size, %" PRIuGRUB_UINT64_T),
+ keyfile_offset, keyfile->size);
+
+ if (grub_file_seek (keyfile, (grub_off_t) keyfile_offset) == (grub_off_t) -1)
+ return grub_errno;
+
+ if (keyfile_size != 0)
+ {
+ if (keyfile_size > (keyfile->size - keyfile_offset))
+ return grub_error (GRUB_ERR_FILE_READ_ERROR,
+ N_("keyfile is too small: requested %llu bytes,"
+ " but the file only has %" PRIuGRUB_UINT64_T
+ " bytes left at offset %llu"),
+ keyfile_size,
+ (grub_off_t) (keyfile->size - keyfile_offset),
+ keyfile_offset);
+
+ cargs.key_len = keyfile_size;
+ }
+ else
+ cargs.key_len = keyfile->size - keyfile_offset;
+
+ cargs.key_data = grub_malloc (cargs.key_len);
+ if (cargs.key_data == NULL)
+ return GRUB_ERR_OUT_OF_MEMORY;
+
+ if (grub_file_read (keyfile, cargs.key_data, cargs.key_len) != (grub_ssize_t) cargs.key_len)
+ return grub_error (GRUB_ERR_FILE_READ_ERROR, (N_("failed to read key file")));
+ }
+
if (state[0].set) /* uuid */
{
int found_uuid;
@@ -1384,7 +1461,9 @@ GRUB_MOD_INIT (cryptodisk)
{
grub_disk_dev_register (&grub_cryptodisk_dev);
cmd = grub_register_extcmd ("cryptomount", grub_cmd_cryptomount, 0,
- N_("[-p password] <SOURCE|-u UUID|-a|-b>"),
+ N_("[ [-p password] | [-k keyfile"
+ " [-O keyoffset] [-S keysize] ] ]"
+ " <SOURCE|-u UUID|-a|-b>"),
N_("Mount a crypto device."), options);
grub_procfs_register ("luks_script", &luks_script);
}
diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h
index c6524c9..467065f 100644
--- a/include/grub/cryptodisk.h
+++ b/include/grub/cryptodisk.h
@@ -61,6 +61,8 @@ typedef enum
#define GRUB_CRYPTODISK_MAX_KEYLEN 128
#define GRUB_CRYPTODISK_MAX_PASSPHRASE 256
+#define GRUB_CRYPTODISK_MAX_KEYFILE_SIZE 8192
+
struct grub_cryptodisk;
typedef gcry_err_code_t
diff --git a/include/grub/file.h b/include/grub/file.h
index 96827a4..2e9fff7 100644
--- a/include/grub/file.h
+++ b/include/grub/file.h
@@ -92,6 +92,8 @@ enum grub_file_type
GRUB_FILE_TYPE_FONT,
/* File holding encryption key for encrypted ZFS. */
GRUB_FILE_TYPE_ZFS_ENCRYPTION_KEY,
+ /* File holding the encryption key. */
+ GRUB_FILE_TYPE_CRYPTODISK_ENCRYPTION_KEY,
/* File we open n grub-fstest. */
GRUB_FILE_TYPE_FSTEST,
/* File we open n grub-mount. */

View File

@ -0,0 +1,140 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Glenn Washburn <development@efficientek.com>
Date: Fri, 20 May 2022 14:32:18 -0500
Subject: [PATCH] disk/cryptodisk: Use enum constants as indexes into
cryptomount option array
Signed-off-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/disk/cryptodisk.c | 49 +++++++++++++++++++++++++++------------------
1 file changed, 30 insertions(+), 19 deletions(-)
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index 0706afa..9db5f65 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -35,6 +35,17 @@ GRUB_MOD_LICENSE ("GPLv3+");
grub_cryptodisk_dev_t grub_cryptodisk_list;
+enum
+ {
+ OPTION_UUID,
+ OPTION_ALL,
+ OPTION_BOOT,
+ OPTION_PASSWORD,
+ OPTION_KEYFILE,
+ OPTION_KEYFILE_OFFSET,
+ OPTION_KEYFILE_SIZE
+ };
+
static const struct grub_arg_option options[] =
{
{"uuid", 'u', 0, N_("Mount by UUID."), 0, 0},
@@ -1163,44 +1174,44 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
struct grub_arg_list *state = ctxt->state;
struct grub_cryptomount_args cargs = {0};
- if (argc < 1 && !state[1].set && !state[2].set)
+ if (argc < 1 && !state[OPTION_ALL].set && !state[OPTION_BOOT].set)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
if (grub_cryptodisk_list == NULL)
return grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk modules loaded");
- if (state[3].set) /* password */
+ if (state[OPTION_PASSWORD].set) /* password */
{
- cargs.key_data = (grub_uint8_t *) state[3].arg;
- cargs.key_len = grub_strlen (state[3].arg);
+ cargs.key_data = (grub_uint8_t *) state[OPTION_PASSWORD].arg;
+ cargs.key_len = grub_strlen (state[OPTION_PASSWORD].arg);
}
- if (state[4].set) /* keyfile */
+ if (state[OPTION_KEYFILE].set) /* keyfile */
{
const char *p = NULL;
grub_file_t keyfile;
unsigned long long keyfile_offset = 0, keyfile_size = 0;
- if (state[5].set) /* keyfile-offset */
+ if (state[OPTION_KEYFILE_OFFSET].set) /* keyfile-offset */
{
grub_errno = GRUB_ERR_NONE;
- keyfile_offset = grub_strtoull (state[5].arg, &p, 0);
+ keyfile_offset = grub_strtoull (state[OPTION_KEYFILE_OFFSET].arg, &p, 0);
- if (state[5].arg[0] == '\0' || *p != '\0')
+ if (state[OPTION_KEYFILE_OFFSET].arg[0] == '\0' || *p != '\0')
return grub_error (grub_errno,
N_("non-numeric or invalid keyfile offset `%s'"),
- state[5].arg);
+ state[OPTION_KEYFILE_OFFSET].arg);
}
- if (state[6].set) /* keyfile-size */
+ if (state[OPTION_KEYFILE_SIZE].set) /* keyfile-size */
{
grub_errno = GRUB_ERR_NONE;
- keyfile_size = grub_strtoull (state[6].arg, &p, 0);
+ keyfile_size = grub_strtoull (state[OPTION_KEYFILE_SIZE].arg, &p, 0);
- if (state[6].arg[0] == '\0' || *p != '\0')
+ if (state[OPTION_KEYFILE_SIZE].arg[0] == '\0' || *p != '\0')
return grub_error (grub_errno,
N_("non-numeric or invalid keyfile size `%s'"),
- state[6].arg);
+ state[OPTION_KEYFILE_SIZE].arg);
if (keyfile_size == 0)
return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("key file size is 0"));
@@ -1211,7 +1222,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
GRUB_CRYPTODISK_MAX_KEYFILE_SIZE);
}
- keyfile = grub_file_open (state[4].arg,
+ keyfile = grub_file_open (state[OPTION_KEYFILE].arg,
GRUB_FILE_TYPE_CRYPTODISK_ENCRYPTION_KEY);
if (keyfile == NULL)
return grub_errno;
@@ -1249,7 +1260,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
return grub_error (GRUB_ERR_FILE_READ_ERROR, (N_("failed to read key file")));
}
- if (state[0].set) /* uuid */
+ if (state[OPTION_UUID].set) /* uuid */
{
int found_uuid;
grub_cryptodisk_t dev;
@@ -1262,7 +1273,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
return GRUB_ERR_NONE;
}
- cargs.check_boot = state[2].set;
+ cargs.check_boot = state[OPTION_BOOT].set;
cargs.search_uuid = args[0];
found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, &cargs);
@@ -1280,9 +1291,9 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
}
return grub_errno;
}
- else if (state[1].set || (argc == 0 && state[2].set)) /* -a|-b */
+ else if (state[OPTION_ALL].set || (argc == 0 && state[OPTION_BOOT].set)) /* -a|-b */
{
- cargs.check_boot = state[2].set;
+ cargs.check_boot = state[OPTION_BOOT].set;
grub_device_iterate (&grub_cryptodisk_scan_device, &cargs);
return GRUB_ERR_NONE;
}
@@ -1294,7 +1305,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
char *disklast = NULL;
grub_size_t len;
- cargs.check_boot = state[2].set;
+ cargs.check_boot = state[OPTION_BOOT].set;
diskname = args[0];
len = grub_strlen (diskname);
if (len && diskname[0] == '(' && diskname[len - 1] == ')')

View File

@ -0,0 +1,259 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Glenn Washburn <development@efficientek.com>
Date: Wed, 8 Jun 2022 10:34:03 -0500
Subject: [PATCH] cryptodisk: Add support for using detached header files
Using the disk read hook mechanism, setup a read hook on the source disk
which will read from the given header file during the scan and recovery
cryptodisk backend functions. Disk read hooks are executed after the data
has been read from the disk. This is okay, because the read hook is given
the read buffer before its sent back to the caller. In this case, the hook
can then overwrite the data read from the disk device with data from the
header file sent in as the read hook data. This is transparent to the
read caller. Since the callers of this function have just opened the
source disk, there are no current read hooks, so there's no need to
save/restore them nor consider if they should be called or not.
This hook assumes that the header is at the start of the volume, which
is not the case for some formats (e.g. GELI). So GELI will return an
error if a detached header is specified. It also can only be used
with formats where the detached header file can be written to the
first blocks of the volume and the volume could still be unlocked.
So the header file can not be formatted differently from the on-disk
header. If these assumpts are not met, detached header file processing
must be specially handled in the cryptodisk backend module.
The hook will be called potentially many times by a backend. This is fine
because of the assumptions mentioned and the read hook reads from absolute
offsets and is stateless.
Also add a --header (short -H) option to cryptomount which takes a file
argument.
Signed-off-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Patrick Steinhardt <ps@pks.im>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/disk/cryptodisk.c | 92 +++++++++++++++++++++++++++++++++++++++++++--
grub-core/disk/geli.c | 4 ++
include/grub/cryptodisk.h | 2 +
include/grub/file.h | 2 +
4 files changed, 96 insertions(+), 4 deletions(-)
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index 9db5f65..3d8472e 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -43,7 +43,8 @@ enum
OPTION_PASSWORD,
OPTION_KEYFILE,
OPTION_KEYFILE_OFFSET,
- OPTION_KEYFILE_SIZE
+ OPTION_KEYFILE_SIZE,
+ OPTION_HEADER
};
static const struct grub_arg_option options[] =
@@ -56,9 +57,16 @@ static const struct grub_arg_option options[] =
{"key-file", 'k', 0, N_("Key file"), 0, ARG_TYPE_STRING},
{"keyfile-offset", 'O', 0, N_("Key file offset (bytes)"), 0, ARG_TYPE_INT},
{"keyfile-size", 'S', 0, N_("Key file data size (bytes)"), 0, ARG_TYPE_INT},
+ {"header", 'H', 0, N_("Read header from file"), 0, ARG_TYPE_STRING},
{0, 0, 0, 0, 0, 0}
};
+struct cryptodisk_read_hook_ctx
+{
+ grub_file_t hdr_file;
+};
+typedef struct cryptodisk_read_hook_ctx *cryptodisk_read_hook_ctx_t;
+
/* Our irreducible polynom is x^128+x^7+x^2+x+1. Lowest byte of it is: */
#define GF_POLYNOM 0x87
static inline int GF_PER_SECTOR (const struct grub_cryptodisk *dev)
@@ -1004,6 +1012,30 @@ cryptodisk_close (grub_cryptodisk_t dev)
grub_free (dev);
}
+static grub_err_t
+cryptodisk_read_hook (grub_disk_addr_t sector, unsigned offset,
+ unsigned length, char *buf, void *data)
+{
+ cryptodisk_read_hook_ctx_t ctx = data;
+
+ if (ctx->hdr_file == NULL)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("header file not found"));
+
+ if (grub_file_seek (ctx->hdr_file,
+ (sector * GRUB_DISK_SECTOR_SIZE) + offset)
+ == (grub_off_t) -1)
+ return grub_errno;
+
+ if (grub_file_read (ctx->hdr_file, buf, length) != (grub_ssize_t) length)
+ {
+ if (grub_errno == GRUB_ERR_NONE)
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("header file too small"));
+ return grub_errno;
+ }
+
+ return GRUB_ERR_NONE;
+}
+
static grub_cryptodisk_t
grub_cryptodisk_scan_device_real (const char *name,
grub_disk_t source,
@@ -1012,6 +1044,7 @@ grub_cryptodisk_scan_device_real (const char *name,
grub_err_t ret = GRUB_ERR_NONE;
grub_cryptodisk_t dev;
grub_cryptodisk_dev_t cr;
+ struct cryptodisk_read_hook_ctx read_hook_data = {0};
int askpass = 0;
char *part = NULL;
@@ -1020,11 +1053,46 @@ grub_cryptodisk_scan_device_real (const char *name,
if (dev)
return dev;
+ if (cargs->hdr_file != NULL)
+ {
+ /*
+ * Set read hook to read header from a file instead of the source disk.
+ * Disk read hooks are executed after the data has been read from the
+ * disk. This is okay, because the read hook is given the read buffer
+ * before its sent back to the caller. In this case, the hook can then
+ * overwrite the data read from the disk device with data from the
+ * header file sent in as the read hook data. This is transparent to the
+ * read caller. Since the callers of this function have just opened the
+ * source disk, there are no current read hooks, so there's no need to
+ * save/restore them nor consider if they should be called or not.
+ *
+ * This hook assumes that the header is at the start of the volume, which
+ * is not the case for some formats (eg. GELI). It also can only be used
+ * with formats where the detached header file can be written to the
+ * first blocks of the volume and the volume could still be unlocked.
+ * So the header file can not be formatted differently from the on-disk
+ * header. If these assumpts are not met, detached header file processing
+ * must be specially handled in the cryptodisk backend module.
+ *
+ * This hook needs only be set once and will be called potentially many
+ * times by a backend. This is fine because of the assumptions mentioned
+ * and the read hook reads from absolute offsets and is stateless.
+ */
+ read_hook_data.hdr_file = cargs->hdr_file;
+ source->read_hook = cryptodisk_read_hook;
+ source->read_hook_data = (void *) &read_hook_data;
+ }
+
FOR_CRYPTODISK_DEVS (cr)
{
+ /*
+ * Loop through each cryptodisk backend that is registered (ie. loaded).
+ * If the scan returns NULL, then the backend being tested does not
+ * recognize the source disk, so move on to the next backend.
+ */
dev = cr->scan (source, cargs);
if (grub_errno)
- return NULL;
+ goto error_no_close;
if (!dev)
continue;
@@ -1041,7 +1109,7 @@ grub_cryptodisk_scan_device_real (const char *name,
cargs->key_data = grub_malloc (GRUB_CRYPTODISK_MAX_PASSPHRASE);
if (cargs->key_data == NULL)
- return NULL;
+ goto error_no_close;
if (!grub_password_get ((char *) cargs->key_data, GRUB_CRYPTODISK_MAX_PASSPHRASE))
{
@@ -1066,9 +1134,13 @@ grub_cryptodisk_scan_device_real (const char *name,
error:
cryptodisk_close (dev);
+ error_no_close:
dev = NULL;
cleanup:
+ if (cargs->hdr_file != NULL)
+ source->read_hook = NULL;
+
if (askpass)
{
cargs->key_len = 0;
@@ -1260,6 +1332,18 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
return grub_error (GRUB_ERR_FILE_READ_ERROR, (N_("failed to read key file")));
}
+ if (state[OPTION_HEADER].set) /* header */
+ {
+ if (state[OPTION_UUID].set)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("cannot use UUID lookup with detached header"));
+
+ cargs.hdr_file = grub_file_open (state[OPTION_HEADER].arg,
+ GRUB_FILE_TYPE_CRYPTODISK_DETACHED_HEADER);
+ if (cargs.hdr_file == NULL)
+ return grub_errno;
+ }
+
if (state[OPTION_UUID].set) /* uuid */
{
int found_uuid;
@@ -1473,7 +1557,7 @@ GRUB_MOD_INIT (cryptodisk)
grub_disk_dev_register (&grub_cryptodisk_dev);
cmd = grub_register_extcmd ("cryptomount", grub_cmd_cryptomount, 0,
N_("[ [-p password] | [-k keyfile"
- " [-O keyoffset] [-S keysize] ] ]"
+ " [-O keyoffset] [-S keysize] ] ] [-H file]"
" <SOURCE|-u UUID|-a|-b>"),
N_("Mount a crypto device."), options);
grub_procfs_register ("luks_script", &luks_script);
diff --git a/grub-core/disk/geli.c b/grub-core/disk/geli.c
index 23789c4..52dd504 100644
--- a/grub-core/disk/geli.c
+++ b/grub-core/disk/geli.c
@@ -252,6 +252,10 @@ configure_ciphers (grub_disk_t disk, grub_cryptomount_args_t cargs)
grub_disk_addr_t sector;
grub_err_t err;
+ /* Detached headers are not implemented yet */
+ if (cargs->hdr_file != NULL)
+ return NULL;
+
if (2 * GRUB_MD_SHA256->mdlen + 1 > GRUB_CRYPTODISK_MAX_UUID_LENGTH)
return NULL;
diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h
index 467065f..d94df68 100644
--- a/include/grub/cryptodisk.h
+++ b/include/grub/cryptodisk.h
@@ -20,6 +20,7 @@
#define GRUB_CRYPTODISK_HEADER 1
#include <grub/disk.h>
+#include <grub/file.h>
#include <grub/crypto.h>
#include <grub/list.h>
#ifdef GRUB_UTIL
@@ -79,6 +80,7 @@ struct grub_cryptomount_args
grub_uint8_t *key_data;
/* recover_key: Length of key_data */
grub_size_t key_len;
+ grub_file_t hdr_file;
};
typedef struct grub_cryptomount_args *grub_cryptomount_args_t;
diff --git a/include/grub/file.h b/include/grub/file.h
index 2e9fff7..d678de0 100644
--- a/include/grub/file.h
+++ b/include/grub/file.h
@@ -94,6 +94,8 @@ enum grub_file_type
GRUB_FILE_TYPE_ZFS_ENCRYPTION_KEY,
/* File holding the encryption key. */
GRUB_FILE_TYPE_CRYPTODISK_ENCRYPTION_KEY,
+ /* File holding the encryption metadata header */
+ GRUB_FILE_TYPE_CRYPTODISK_DETACHED_HEADER,
/* File we open n grub-fstest. */
GRUB_FILE_TYPE_FSTEST,
/* File we open n grub-mount. */

View File

@ -0,0 +1,51 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Glenn Washburn <development@efficientek.com>
Date: Sun, 7 Aug 2022 00:18:52 -0500
Subject: [PATCH] disk/cryptodisk: Support encrypted volumes using detached
headers on a partition
Update the read hook to take into account encrypted volumes on a partition.
GRUB disk read hooks supply an absolute sector number at which the read is
started from. If the encrypted volume is in a partition, the sector number
given to the read hook will be offset by the number of the sector at the
start of the partition. The read hook then needs to subtract the partition
start from the supplied sector to get the correct start sector for the read
into the detached header file.
Reported-by: brutser <brutser@perso.be>
Signed-off-by: Glenn Washburn <development@efficientek.com>
Tested-by: brutser <brutser@perso.be>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/disk/cryptodisk.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index 3d8472e..42370db 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -64,6 +64,7 @@ static const struct grub_arg_option options[] =
struct cryptodisk_read_hook_ctx
{
grub_file_t hdr_file;
+ grub_disk_addr_t part_start;
};
typedef struct cryptodisk_read_hook_ctx *cryptodisk_read_hook_ctx_t;
@@ -1022,7 +1023,7 @@ cryptodisk_read_hook (grub_disk_addr_t sector, unsigned offset,
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("header file not found"));
if (grub_file_seek (ctx->hdr_file,
- (sector * GRUB_DISK_SECTOR_SIZE) + offset)
+ ((sector - ctx->part_start) * GRUB_DISK_SECTOR_SIZE) + offset)
== (grub_off_t) -1)
return grub_errno;
@@ -1078,6 +1079,7 @@ grub_cryptodisk_scan_device_real (const char *name,
* times by a backend. This is fine because of the assumptions mentioned
* and the read hook reads from absolute offsets and is stateless.
*/
+ read_hook_data.part_start = grub_partition_get_start (source->partition);
read_hook_data.hdr_file = cargs->hdr_file;
source->read_hook = cryptodisk_read_hook;
source->read_hook_data = (void *) &read_hook_data;

View File

@ -0,0 +1,200 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Glenn Washburn <development@efficientek.com>
Date: Fri, 19 Aug 2022 18:06:15 -0500
Subject: [PATCH] disk/cryptodisk: Allows UUIDs to be compared in a
dash-insensitive manner
A user can now specify UUID strings with dashes, instead of having to remove
dashes. This is backwards-compatibility preserving and also fixes a source
of user confusion over the inconsistency with how UUIDs are specified
between file system UUIDs and cryptomount UUIDs. Since cryptsetup, the
reference implementation for LUKS, displays and generates UUIDs with dashes
there has been additional confusion when using the UUID strings from
cryptsetup as exact input into GRUB does not find the expected cryptodisk.
A new function grub_uuidcasecmp() is added that is general enough to be used
other places where UUIDs are being compared.
Signed-off-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Patrick Steinhardt <ps@pks.im>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/disk/cryptodisk.c | 4 ++--
grub-core/disk/geli.c | 2 +-
grub-core/disk/luks.c | 21 ++++-----------------
grub-core/disk/luks2.c | 15 ++++-----------
include/grub/misc.h | 30 ++++++++++++++++++++++++++++++
5 files changed, 41 insertions(+), 31 deletions(-)
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index 42370db..17b5034 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -702,7 +702,7 @@ grub_cryptodisk_open (const char *name, grub_disk_t disk)
if (grub_memcmp (name, "cryptouuid/", sizeof ("cryptouuid/") - 1) == 0)
{
for (dev = cryptodisk_list; dev != NULL; dev = dev->next)
- if (grub_strcasecmp (name + sizeof ("cryptouuid/") - 1, dev->uuid) == 0)
+ if (grub_uuidcasecmp (name + sizeof ("cryptouuid/") - 1, dev->uuid, sizeof (dev->uuid)) == 0)
break;
}
else
@@ -929,7 +929,7 @@ grub_cryptodisk_get_by_uuid (const char *uuid)
{
grub_cryptodisk_t dev;
for (dev = cryptodisk_list; dev != NULL; dev = dev->next)
- if (grub_strcasecmp (dev->uuid, uuid) == 0)
+ if (grub_uuidcasecmp (dev->uuid, uuid, sizeof (dev->uuid)) == 0)
return dev;
return NULL;
}
diff --git a/grub-core/disk/geli.c b/grub-core/disk/geli.c
index 52dd504..bd18b19 100644
--- a/grub-core/disk/geli.c
+++ b/grub-core/disk/geli.c
@@ -305,7 +305,7 @@ configure_ciphers (grub_disk_t disk, grub_cryptomount_args_t cargs)
return NULL;
}
- if (cargs->search_uuid != NULL && grub_strcasecmp (cargs->search_uuid, uuid) != 0)
+ if (cargs->search_uuid != NULL && grub_uuidcasecmp (cargs->search_uuid, uuid, sizeof (uuid)) != 0)
{
grub_dprintf ("geli", "%s != %s\n", uuid, cargs->search_uuid);
return NULL;
diff --git a/grub-core/disk/luks.c b/grub-core/disk/luks.c
index f0feb38..f6a0cbc 100644
--- a/grub-core/disk/luks.c
+++ b/grub-core/disk/luks.c
@@ -66,10 +66,7 @@ static grub_cryptodisk_t
configure_ciphers (grub_disk_t disk, grub_cryptomount_args_t cargs)
{
grub_cryptodisk_t newdev;
- const char *iptr;
struct grub_luks_phdr header;
- char *optr;
- char uuid[sizeof (header.uuid) + 1];
char ciphername[sizeof (header.cipherName) + 1];
char ciphermode[sizeof (header.cipherMode) + 1];
char hashspec[sizeof (header.hashSpec) + 1];
@@ -92,19 +89,9 @@ configure_ciphers (grub_disk_t disk, grub_cryptomount_args_t cargs)
|| grub_be_to_cpu16 (header.version) != 1)
return NULL;
- grub_memset (uuid, 0, sizeof (uuid));
- optr = uuid;
- for (iptr = header.uuid; iptr < &header.uuid[ARRAY_SIZE (header.uuid)];
- iptr++)
+ if (cargs->search_uuid != NULL && grub_uuidcasecmp (cargs->search_uuid, header.uuid, sizeof (header.uuid)) != 0)
{
- if (*iptr != '-')
- *optr++ = *iptr;
- }
- *optr = 0;
-
- if (cargs->search_uuid != NULL && grub_strcasecmp (cargs->search_uuid, uuid) != 0)
- {
- grub_dprintf ("luks", "%s != %s\n", uuid, cargs->search_uuid);
+ grub_dprintf ("luks", "%s != %s\n", header.uuid, cargs->search_uuid);
return NULL;
}
@@ -123,7 +110,7 @@ configure_ciphers (grub_disk_t disk, grub_cryptomount_args_t cargs)
newdev->source_disk = NULL;
newdev->log_sector_size = GRUB_LUKS1_LOG_SECTOR_SIZE;
newdev->total_sectors = grub_disk_native_sectors (disk) - newdev->offset_sectors;
- grub_memcpy (newdev->uuid, uuid, sizeof (uuid));
+ grub_memcpy (newdev->uuid, header.uuid, sizeof (header.uuid));
newdev->modname = "luks";
/* Configure the hash used for the AF splitter and HMAC. */
@@ -143,7 +130,7 @@ configure_ciphers (grub_disk_t disk, grub_cryptomount_args_t cargs)
return NULL;
}
- COMPILE_TIME_ASSERT (sizeof (newdev->uuid) >= sizeof (uuid));
+ COMPILE_TIME_ASSERT (sizeof (newdev->uuid) >= sizeof (header.uuid));
return newdev;
}
diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c
index bf741d7..ac3ab09 100644
--- a/grub-core/disk/luks2.c
+++ b/grub-core/disk/luks2.c
@@ -350,8 +350,6 @@ luks2_scan (grub_disk_t disk, grub_cryptomount_args_t cargs)
{
grub_cryptodisk_t cryptodisk;
grub_luks2_header_t header;
- char uuid[sizeof (header.uuid) + 1];
- grub_size_t i, j;
if (cargs->check_boot)
return NULL;
@@ -362,14 +360,9 @@ luks2_scan (grub_disk_t disk, grub_cryptomount_args_t cargs)
return NULL;
}
- for (i = 0, j = 0; i < sizeof (header.uuid); i++)
- if (header.uuid[i] != '-')
- uuid[j++] = header.uuid[i];
- uuid[j] = '\0';
-
- if (cargs->search_uuid != NULL && grub_strcasecmp (cargs->search_uuid, uuid) != 0)
+ if (cargs->search_uuid != NULL && grub_uuidcasecmp (cargs->search_uuid, header.uuid, sizeof (header.uuid)) != 0)
{
- grub_dprintf ("luks2", "%s != %s\n", uuid, cargs->search_uuid);
+ grub_dprintf ("luks2", "%s != %s\n", header.uuid, cargs->search_uuid);
return NULL;
}
@@ -377,8 +370,8 @@ luks2_scan (grub_disk_t disk, grub_cryptomount_args_t cargs)
if (!cryptodisk)
return NULL;
- COMPILE_TIME_ASSERT (sizeof (cryptodisk->uuid) >= sizeof (uuid));
- grub_memcpy (cryptodisk->uuid, uuid, sizeof (uuid));
+ COMPILE_TIME_ASSERT (sizeof (cryptodisk->uuid) >= sizeof (header.uuid));
+ grub_memcpy (cryptodisk->uuid, header.uuid, sizeof (header.uuid));
cryptodisk->modname = "luks2";
return cryptodisk;
diff --git a/include/grub/misc.h b/include/grub/misc.h
index 8c0ffed..fae4910 100644
--- a/include/grub/misc.h
+++ b/include/grub/misc.h
@@ -290,6 +290,36 @@ grub_strncasecmp (const char *s1, const char *s2, grub_size_t n)
- (int) grub_tolower ((grub_uint8_t) *s2);
}
+/*
+ * Do a case insensitive compare of two UUID strings by ignoring all dashes.
+ * Note that the parameter n, is the number of significant characters to
+ * compare, where significant characters are any except the dash.
+ */
+static inline int
+grub_uuidcasecmp (const char *uuid1, const char *uuid2, grub_size_t n)
+{
+ if (n == 0)
+ return 0;
+
+ while (*uuid1 && *uuid2 && --n)
+ {
+ /* Skip forward to non-dash on both UUIDs. */
+ while ('-' == *uuid1)
+ ++uuid1;
+
+ while ('-' == *uuid2)
+ ++uuid2;
+
+ if (grub_tolower ((grub_uint8_t) *uuid1) != grub_tolower ((grub_uint8_t) *uuid2))
+ break;
+
+ uuid1++;
+ uuid2++;
+ }
+
+ return (int) grub_tolower ((grub_uint8_t) *uuid1) - (int) grub_tolower ((grub_uint8_t) *uuid2);
+}
+
/*
* Note that these differ from the C standard's definitions of strtol,
* strtoul(), and strtoull() by the addition of two const qualifiers on the end

View File

@ -0,0 +1,36 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alec Brown <alec.r.brown@oracle.com>
Date: Fri, 14 Oct 2022 17:47:08 -0400
Subject: [PATCH] disk/cryptodisk: Fix unintentional integer overflow
In the function grub_cryptodisk_endecrypt(), a for loop is incrementing the
variable i by (1U << log_sector_size). The variable i is of type grub_size_t
which is a 64-bit unsigned integer on x86_64 architecture. On the other hand, 1U
is a 32-bit unsigned integer. By performing a left shift on a 32-bit value and
assigning it to a 64-bit variable, the 64-bit variable may have incorrect values
in the high 32-bits if the shift has an overflow. To avoid this, we replace 1U
with (grub_size_t)1.
Fixes: CID 307788
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
Reviewed-by: Patrick Steinhardt <ps@pks.im>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/disk/cryptodisk.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index 17b5034..e23c618 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -262,7 +262,7 @@ grub_cryptodisk_endecrypt (struct grub_cryptodisk *dev,
return (do_encrypt ? grub_crypto_ecb_encrypt (dev->cipher, data, data, len)
: grub_crypto_ecb_decrypt (dev->cipher, data, data, len));
- for (i = 0; i < len; i += (1U << log_sector_size))
+ for (i = 0; i < len; i += ((grub_size_t) 1 << log_sector_size))
{
grub_size_t sz = ((dev->cipher->cipher->blocksize
+ sizeof (grub_uint32_t) - 1)

View File

@ -0,0 +1,73 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Fabian Vogt <fvogt@suse.de>
Date: Thu, 12 Jan 2023 17:05:07 -0600
Subject: [PATCH] disk/cryptodisk: When cheatmounting, use the sector info of
the cheat device
When using grub-probe with cryptodisk, the mapped block device from the host
is used directly instead of decrypting the source device in GRUB code.
In that case, the sector size and count of the host device needs to be used.
This is especially important when using LUKS2, which does not assign
total_sectors and log_sector_size when scanning, but only later when the
segments in the JSON area are evaluated. With an unset log_sector_size,
grub_device_open() complains.
This fixes grub-probe failing with
"error: sector sizes of 1 bytes aren't supported yet.".
Signed-off-by: Fabian Vogt <fvogt@suse.de>
Reviewed-by: Patrick Steinhardt <ps@pks.im>
Tested-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Patrick Steinhardt <ps@pks.im>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/disk/cryptodisk.c | 20 ++++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index e23c618..2384792 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -718,16 +718,31 @@ grub_cryptodisk_open (const char *name, grub_disk_t disk)
if (!dev)
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "No such device");
- disk->log_sector_size = dev->log_sector_size;
-
#ifdef GRUB_UTIL
if (dev->cheat)
{
+ grub_uint64_t cheat_dev_size;
+ unsigned int cheat_log_sector_size;
+
if (!GRUB_UTIL_FD_IS_VALID (dev->cheat_fd))
dev->cheat_fd = grub_util_fd_open (dev->cheat, GRUB_UTIL_FD_O_RDONLY);
if (!GRUB_UTIL_FD_IS_VALID (dev->cheat_fd))
return grub_error (GRUB_ERR_IO, N_("cannot open `%s': %s"),
dev->cheat, grub_util_fd_strerror ());
+
+ /* Use the sector size and count of the cheat device. */
+ cheat_dev_size = grub_util_get_fd_size (dev->cheat_fd, dev->cheat, &cheat_log_sector_size);
+ if (cheat_dev_size == -1)
+ {
+ const char *errmsg = grub_util_fd_strerror ();
+ grub_util_fd_close (dev->cheat_fd);
+ dev->cheat_fd = GRUB_UTIL_FD_INVALID;
+ return grub_error (GRUB_ERR_IO, N_("failed to query size of device `%s': %s"),
+ dev->cheat, errmsg);
+ }
+
+ dev->log_sector_size = cheat_log_sector_size;
+ dev->total_sectors = cheat_dev_size >> cheat_log_sector_size;
}
#endif
@@ -741,6 +756,7 @@ grub_cryptodisk_open (const char *name, grub_disk_t disk)
}
disk->data = dev;
+ disk->log_sector_size = dev->log_sector_size;
disk->total_sectors = dev->total_sectors;
disk->max_agglomerate = GRUB_DISK_MAX_MAX_AGGLOMERATE;
disk->id = dev->id;

View File

@ -0,0 +1,34 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Glenn Washburn <development@efficientek.com>
Date: Fri, 18 Aug 2023 12:27:22 -0500
Subject: [PATCH] disk/cryptodisk: Fix missing change when updating to use
grub_uuidcasecmp()
This was causing the cryptomount command to return failure even though
the crypto device was successfully added. Of course, this meant that any
script using the return code would behave unexpectedly.
Fixes: 3cf2e848bc03 (disk/cryptodisk: Allows UUIDs to be compared in a dash-insensitive manner)
Suggested-by: Olaf Hering <olaf@aepfle.de>
Signed-off-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Patrich Steinhardt <ps@pks.im>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/disk/cryptodisk.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index 2384792..bbe39a8 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -1236,7 +1236,8 @@ grub_cryptodisk_scan_device (const char *name,
dev = grub_cryptodisk_scan_device_real (name, source, cargs);
if (dev)
{
- ret = (cargs->search_uuid != NULL && grub_strcasecmp (cargs->search_uuid, dev->uuid) == 0);
+ ret = (cargs->search_uuid != NULL
+ && grub_uuidcasecmp (cargs->search_uuid, dev->uuid, sizeof (dev->uuid)) == 0);
goto cleanup;
}

View File

@ -0,0 +1,34 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Glenn Washburn <development@efficientek.com>
Date: Fri, 14 Jul 2023 15:49:17 -0500
Subject: [PATCH] disk/cryptodisk: Optimize luks_script_get()
Use the return value of grub_snprintf() to move the string pointer forward,
instead of incrementing the string pointer iteratively until a NULL byte is
reached. Move the space out of the format string argument, a small
optimization, but also makes the spacing clearer. Also, use the new
PRIxGRUB_OFFSET instead of PRIuGRUB_UINT64_T to accurately reflect the
format string for this type.
Signed-off-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/disk/cryptodisk.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index bbe39a8..751fe9b 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -1504,9 +1504,8 @@ luks_script_get (grub_size_t *sz)
ptr = grub_stpcpy (ptr, "luks_mount ");
ptr = grub_stpcpy (ptr, i->uuid);
*ptr++ = ' ';
- grub_snprintf (ptr, 21, "%" PRIuGRUB_UINT64_T " ", i->offset_sectors);
- while (*ptr)
- ptr++;
+ ptr += grub_snprintf (ptr, 21, "%" PRIxGRUB_OFFSET, i->offset_sectors);
+ *ptr++ = ' ';
for (iptr = i->cipher->cipher->name; *iptr; iptr++)
*ptr++ = grub_tolower (*iptr);
switch (i->mode)

View File

@ -0,0 +1,69 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Glenn Washburn <development@efficientek.com>
Date: Fri, 14 Jul 2023 15:49:18 -0500
Subject: [PATCH] disk/cryptodisk: Add support for LUKS2 in (proc)/luks_script
The sector size in bytes is added to each line and it is allowed to be
6 decimal digits long, which covers the most common cases of 512 and 4096
byte sectors with space for two additional digits as future-proofing. The
size allocation is updated to reflect this additional field. Also make
clearer the size allocation calculation.
Signed-off-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/disk/cryptodisk.c | 24 +++++++++++++++++++-----
1 file changed, 19 insertions(+), 5 deletions(-)
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index 751fe9b..49af8a9 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -1479,12 +1479,22 @@ luks_script_get (grub_size_t *sz)
*sz = 0;
for (i = cryptodisk_list; i != NULL; i = i->next)
- if (grub_strcmp (i->modname, "luks") == 0)
+ if (grub_strcmp (i->modname, "luks") == 0 ||
+ grub_strcmp (i->modname, "luks2") == 0)
{
- size += sizeof ("luks_mount ");
+ size += grub_strlen (i->modname);
+ size += sizeof ("_mount");
size += grub_strlen (i->uuid);
size += grub_strlen (i->cipher->cipher->name);
- size += 54;
+ /*
+ * Add space in the line for (in order) spaces, cipher mode, cipher IV
+ * mode, sector offset, sector size and the trailing newline. This is
+ * an upper bound on the size of this data. There are 15 extra bytes
+ * in an earlier version of this code that are unaccounted for. It is
+ * left in the calculations in case it is needed. At worst, its short-
+ * lived wasted space.
+ */
+ size += 5 + 5 + 8 + 20 + 6 + 1 + 15;
if (i->essiv_hash)
size += grub_strlen (i->essiv_hash->name);
size += i->keysize * 2;
@@ -1497,15 +1507,19 @@ luks_script_get (grub_size_t *sz)
ptr = ret;
for (i = cryptodisk_list; i != NULL; i = i->next)
- if (grub_strcmp (i->modname, "luks") == 0)
+ if (grub_strcmp (i->modname, "luks") == 0 ||
+ grub_strcmp (i->modname, "luks2") == 0)
{
unsigned j;
const char *iptr;
- ptr = grub_stpcpy (ptr, "luks_mount ");
+ ptr = grub_stpcpy (ptr, i->modname);
+ ptr = grub_stpcpy (ptr, "_mount ");
ptr = grub_stpcpy (ptr, i->uuid);
*ptr++ = ' ';
ptr += grub_snprintf (ptr, 21, "%" PRIxGRUB_OFFSET, i->offset_sectors);
*ptr++ = ' ';
+ ptr += grub_snprintf (ptr, 7, "%u", 1 << i->log_sector_size);
+ *ptr++ = ' ';
for (iptr = i->cipher->cipher->name; *iptr; iptr++)
*ptr++ = grub_tolower (*iptr);
switch (i->mode)

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 3c7d99e..d3faecb 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -6312,6 +6312,35 @@ sign-file SHA256 grub.key certificate.der core.elf.unsigned core.elf.signed
As with UEFI secure boot, it is necessary to build in the required modules,
or sign them separately.
+@subsection Command line and menuentry editor protection
+
+The TPM key protector provides full disk encryption support on servers or
+virtual machine images, meanwhile keeping the boot process unattended. This
+prevents service disruptions by eliminating the need for manual password input
+during startup, improving system uptime and continuity. It is achieved by TPM,
+which verifies the integrity of boot components by checking cryptographic
+hashes against securely stored values, to confirm the disks are unlocked in a
+trusted state.
+
+However, for users to access the system interactively, some form of
+authentication is still required, as the disks are not unlocked by an
+authorized user. This raised concerns about using an unprotected
+@samp{command-line interface} (@pxref{Command-line interface}), as anyone could
+execute commands to access decrypted data. To address this issue, the LUKS
+password is used to ensure that only authorized users are granted access to the
+interface. Additionally, the @samp{menu entry editor} (@pxref{Menu entry
+editor}) is also safeguarded by the LUKS password, as modifying a boot entry is
+effectively the same as altering the @file{grub.cfg} file read from encrypted
+files.
+
+It is worth mentioning that the built-in password support, as described in
+@samp{Authentication and Authorization in GRUB} (@pxref{Authentication and
+authorisation}), can also be used to protect the command-line interface from
+unauthorized access. However, it is not recommended to rely on this approach as
+it is an optional step. Setting it up requires additional manual intervention,
+which increases the risk of password leakage during the process. Moreover, the
+superuser list must be well maintained, and the password used cannot be
+synchronized with LUKS key rotation.
@node Platform limitations
@chapter Platform limitations
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index 49af8a9..9c456c2 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -1144,7 +1144,9 @@ grub_cryptodisk_scan_device_real (const char *name,
ret = grub_cryptodisk_insert (dev, name, source);
if (ret != GRUB_ERR_NONE)
goto error;
-
+#ifndef GRUB_UTIL
+ grub_cli_set_auth_needed ();
+#endif
goto cleanup;
}
grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk module can handle this device");
@@ -1576,6 +1578,89 @@ luks_script_get (grub_size_t *sz)
return ret;
}
+#ifdef GRUB_MACHINE_EFI
+grub_err_t
+grub_cryptodisk_challenge_password (void)
+{
+ grub_cryptodisk_t cr_dev;
+
+ for (cr_dev = cryptodisk_list; cr_dev != NULL; cr_dev = cr_dev->next)
+ {
+ grub_cryptodisk_dev_t cr;
+ grub_disk_t source = NULL;
+ grub_err_t ret = GRUB_ERR_NONE;
+ grub_cryptodisk_t dev = NULL;
+ char *part = NULL;
+ struct grub_cryptomount_args cargs = {0};
+
+ cargs.check_boot = 0;
+ cargs.search_uuid = cr_dev->uuid;
+
+ source = grub_disk_open (cr_dev->source);
+
+ if (source == NULL)
+ {
+ ret = grub_errno;
+ goto error_out;
+ }
+
+ FOR_CRYPTODISK_DEVS (cr)
+ {
+ dev = cr->scan (source, &cargs);
+ if (grub_errno)
+ {
+ ret = grub_errno;
+ goto error_out;
+ }
+ if (dev == NULL)
+ continue;
+ break;
+ }
+
+ if (dev == NULL)
+ {
+ ret = grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk module can handle this device");
+ goto error_out;
+ }
+
+ part = grub_partition_get_name (source->partition);
+ grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name,
+ source->partition != NULL ? "," : "",
+ part != NULL ? part : N_("UNKNOWN"), cr_dev->uuid);
+ grub_free (part);
+
+ cargs.key_data = grub_malloc (GRUB_CRYPTODISK_MAX_PASSPHRASE);
+ if (cargs.key_data == NULL)
+ {
+ ret = grub_errno;
+ goto error_out;
+ }
+
+ if (!grub_password_get ((char *) cargs.key_data, GRUB_CRYPTODISK_MAX_PASSPHRASE))
+ {
+ ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "passphrase not supplied");
+ goto error_out;
+ }
+ cargs.key_len = grub_strlen ((char *) cargs.key_data);
+ ret = cr->recover_key (source, dev, &cargs);
+
+ error_out:
+ grub_disk_close (source);
+ if (dev != NULL)
+ cryptodisk_close (dev);
+ if (cargs.key_data)
+ {
+ grub_memset (cargs.key_data, 0, cargs.key_len);
+ grub_free (cargs.key_data);
+ }
+
+ return ret;
+ }
+
+ return GRUB_ERR_NONE;
+}
+#endif /* GRUB_MACHINE_EFI */
+
struct grub_procfs_entry luks_script =
{
.name = "luks_script",
diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c
index e4d4bf6..0a4a8d8 100644
--- a/grub-core/kern/main.c
+++ b/grub-core/kern/main.c
@@ -37,6 +37,7 @@
#endif
static bool cli_disabled = false;
+static bool cli_need_auth = false;
grub_addr_t
grub_modules_get_end (void)
@@ -308,6 +309,17 @@ grub_is_cli_disabled (void)
return cli_disabled;
}
+bool
+grub_is_cli_need_auth (void)
+{
+ return cli_need_auth;
+}
+
+void grub_cli_set_auth_needed (void)
+{
+ cli_need_auth = true;
+}
+
static void
check_is_cli_disabled (void)
{
diff --git a/grub-core/normal/auth.c b/grub-core/normal/auth.c
index 53f2d72..075aba4 100644
--- a/grub-core/normal/auth.c
+++ b/grub-core/normal/auth.c
@@ -25,6 +25,10 @@
#include <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 bac7b8a..6f6e4a8 100644
--- a/grub-core/normal/main.c
+++ b/grub-core/normal/main.c
@@ -556,9 +556,13 @@ grub_cmdline_run (int nested, int force_auth)
}
while (err && force_auth);
+ if (err == GRUB_ERR_NONE)
+ err = grub_auth_check_cli_access ();
+
if (err)
{
grub_print_error ();
+ grub_wait_after_message ();
grub_errno = GRUB_ERR_NONE;
return;
}
diff --git a/grub-core/normal/menu_entry.c b/grub-core/normal/menu_entry.c
index 50eef91..150a800 100644
--- a/grub-core/normal/menu_entry.c
+++ b/grub-core/normal/menu_entry.c
@@ -1255,9 +1255,13 @@ grub_menu_entry_run (grub_menu_entry_t entry)
err = grub_auth_check_authentication (NULL);
+ if (err == GRUB_ERR_NONE)
+ err = grub_auth_check_cli_access ();
+
if (err)
{
grub_print_error ();
+ grub_wait_after_message ();
grub_errno = GRUB_ERR_NONE;
return;
}
diff --git a/include/grub/auth.h b/include/grub/auth.h
index 7473344..21d5190 100644
--- a/include/grub/auth.h
+++ b/include/grub/auth.h
@@ -33,5 +33,6 @@ grub_err_t grub_auth_unregister_authentication (const char *user);
grub_err_t grub_auth_authenticate (const char *user);
grub_err_t grub_auth_deauthenticate (const char *user);
grub_err_t grub_auth_check_authentication (const char *userlist);
+grub_err_t grub_auth_check_cli_access (void);
#endif /* ! GRUB_AUTH_HEADER */
diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h
index d94df68..d2572f8 100644
--- a/include/grub/cryptodisk.h
+++ b/include/grub/cryptodisk.h
@@ -187,4 +187,7 @@ grub_util_get_geli_uuid (const char *dev);
grub_cryptodisk_t grub_cryptodisk_get_by_uuid (const char *uuid);
grub_cryptodisk_t grub_cryptodisk_get_by_source_disk (grub_disk_t disk);
+#ifdef GRUB_MACHINE_EFI
+grub_err_t grub_cryptodisk_challenge_password (void);
+#endif
#endif
diff --git a/include/grub/misc.h b/include/grub/misc.h
index fae4910..77d9f56 100644
--- a/include/grub/misc.h
+++ b/include/grub/misc.h
@@ -440,6 +440,8 @@ grub_uint64_t EXPORT_FUNC(grub_divmod64) (grub_uint64_t n,
grub_uint64_t *r);
extern bool EXPORT_FUNC(grub_is_cli_disabled) (void);
+extern bool EXPORT_FUNC(grub_is_cli_need_auth) (void);
+extern void EXPORT_FUNC(grub_cli_set_auth_needed) (void);
/* Must match softdiv group in gentpl.py. */
#if !defined(GRUB_MACHINE_EMU) && (defined(__arm__) || defined(__ia64__) || \

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 99f4792..93026c5 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+");
@@ -56,6 +57,8 @@ delete_loopback (const char *name)
if (! dev)
return grub_error (GRUB_ERR_BAD_DEVICE, "device not found");
+ if (dev->refcnt > 0)
+ return grub_error (GRUB_ERR_STILL_REFERENCED, "device still referenced");
/* Remove the device from the list. */
*prev = dev->next;
@@ -109,6 +112,7 @@ grub_cmd_loopback (grub_extcmd_context_t ctxt, int argc, char **args)
newdev->file = file;
newdev->id = last_id++;
+ newdev->refcnt = 0;
/* Add the new entry to the list. */
newdev->next = loopback_list;
@@ -150,6 +154,9 @@ grub_loopback_open (const char *name, grub_disk_t disk)
if (! dev)
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device");
+ if (grub_add (dev->refcnt, 1, &dev->refcnt))
+ grub_fatal ("Reference count overflow");
+
/* Use the filesize for the disk size, round up to a complete sector. */
if (dev->file->size != GRUB_FILE_SIZE_UNKNOWN)
disk->total_sectors = ((dev->file->size + GRUB_DISK_SECTOR_SIZE - 1)
@@ -167,6 +174,15 @@ grub_loopback_open (const char *name, grub_disk_t disk)
return 0;
}
+static void
+grub_loopback_close (grub_disk_t disk)
+{
+ struct grub_loopback *dev = disk->data;
+
+ if (grub_sub (dev->refcnt, 1, &dev->refcnt))
+ grub_fatal ("Reference count underflow");
+}
+
static grub_err_t
grub_loopback_read (grub_disk_t disk, grub_disk_addr_t sector,
grub_size_t size, char *buf)
@@ -209,6 +225,7 @@ static struct grub_disk_dev grub_loopback_dev =
.id = GRUB_DISK_DEVICE_LOOPBACK_ID,
.disk_iterate = grub_loopback_iterate,
.disk_open = grub_loopback_open,
+ .disk_close = grub_loopback_close,
.disk_read = grub_loopback_read,
.disk_write = grub_loopback_write,
.next = 0
diff --git a/include/grub/err.h b/include/grub/err.h
index c0f90ef..4b903df 100644
--- a/include/grub/err.h
+++ b/include/grub/err.h
@@ -72,7 +72,8 @@ typedef enum
GRUB_ERR_NET_PACKET_TOO_BIG,
GRUB_ERR_NET_NO_DOMAIN,
GRUB_ERR_EOF,
- GRUB_ERR_BAD_SIGNATURE
+ GRUB_ERR_BAD_SIGNATURE,
+ GRUB_ERR_STILL_REFERENCED
}
grub_err_t;
diff --git a/include/grub/loopback.h b/include/grub/loopback.h
index 3b9a9e3..915ef65 100644
--- a/include/grub/loopback.h
+++ b/include/grub/loopback.h
@@ -25,6 +25,7 @@ struct grub_loopback
grub_file_t file;
struct grub_loopback *next;
unsigned long id;
+ grub_uint64_t refcnt;
};
#endif /* ! GRUB_LOOPBACK_HEADER */

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 05a28ab..60f6ad2 100644
--- a/grub-core/kern/disk.c
+++ b/grub-core/kern/disk.c
@@ -28,6 +28,10 @@
#define GRUB_CACHE_TIMEOUT 2
+/* Disk reads may trigger other disk reads. So, limit recursion depth. */
+#define MAX_READ_RECURSION_DEPTH 16
+static unsigned int read_recursion_depth = 0;
+
/* The last time the disk was used. */
static grub_uint64_t grub_last_time = 0;
@@ -417,6 +421,8 @@ grub_err_t
grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
grub_off_t offset, grub_size_t size, void *buf)
{
+ grub_err_t err = GRUB_ERR_NONE;
+
/* First of all, check if the region is within the disk. */
if (grub_disk_adjust_range (disk, &sector, &offset, size) != GRUB_ERR_NONE)
{
@@ -427,12 +433,17 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
return grub_errno;
}
+ if (++read_recursion_depth >= MAX_READ_RECURSION_DEPTH)
+ {
+ grub_error (GRUB_ERR_RECURSION_DEPTH, "grub_disk_read(): Maximum recursion depth exceeded");
+ goto error;
+ }
+
/* First read until first cache boundary. */
if (offset || (sector & (GRUB_DISK_CACHE_SIZE - 1)))
{
grub_disk_addr_t start_sector;
grub_size_t pos;
- grub_err_t err;
grub_size_t len;
start_sector = sector & ~((grub_disk_addr_t) GRUB_DISK_CACHE_SIZE - 1);
@@ -444,7 +455,7 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
err = grub_disk_read_small (disk, start_sector,
offset + pos, len, buf);
if (err)
- return err;
+ goto error;
buf = (char *) buf + len;
size -= len;
offset += len;
@@ -457,7 +468,6 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
{
char *data = NULL;
grub_disk_addr_t agglomerate;
- grub_err_t err;
/* agglomerate read until we find a first cached entry. */
for (agglomerate = 0; agglomerate
@@ -493,7 +503,7 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
- disk->log_sector_size),
buf);
if (err)
- return err;
+ goto error;
for (i = 0; i < agglomerate; i ++)
grub_disk_cache_store (disk->dev->id, disk->id,
@@ -527,13 +537,16 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
/* And now read the last part. */
if (size)
{
- grub_err_t err;
err = grub_disk_read_small (disk, sector, 0, size, buf);
if (err)
- return err;
+ goto error;
}
- return grub_errno;
+ err = grub_errno;
+
+ error:
+ read_recursion_depth--;
+ return err;
}
grub_uint64_t
diff --git a/include/grub/err.h b/include/grub/err.h
index 4b903df..905a6df 100644
--- a/include/grub/err.h
+++ b/include/grub/err.h
@@ -73,7 +73,8 @@ typedef enum
GRUB_ERR_NET_NO_DOMAIN,
GRUB_ERR_EOF,
GRUB_ERR_BAD_SIGNATURE,
- GRUB_ERR_STILL_REFERENCED
+ GRUB_ERR_STILL_REFERENCED,
+ GRUB_ERR_RECURSION_DEPTH
}
grub_err_t;

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 3068c4dca..f3f125e75 100644
--- a/grub-core/kern/partition.c
+++ b/grub-core/kern/partition.c
@@ -28,6 +28,9 @@
grub_partition_map_t grub_partition_map_list;
+#define MAX_RECURSION_DEPTH 32
+static unsigned int recursion_depth = 0;
+
/*
* Checks that disk->partition contains part. This function assumes that the
* start of part is relative to the start of disk->partition. Returns 1 if
@@ -208,7 +211,12 @@ part_iterate (grub_disk_t dsk, const grub_partition_t partition, void *data)
FOR_PARTITION_MAPS(partmap)
{
grub_err_t err;
- err = partmap->iterate (dsk, part_iterate, ctx);
+ recursion_depth++;
+ if (recursion_depth <= MAX_RECURSION_DEPTH)
+ err = partmap->iterate (dsk, part_iterate, ctx);
+ else
+ err = grub_error (GRUB_ERR_RECURSION_DEPTH, "maximum recursion depth exceeded");
+ recursion_depth--;
if (err)
grub_errno = GRUB_ERR_NONE;
if (ctx->ret)

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 0c6dd9c52..c383eb87c 100644
--- a/grub-core/script/execute.c
+++ b/grub-core/script/execute.c
@@ -36,10 +36,18 @@
is sizeof (int) * 3, and one extra for a possible -ve sign. */
#define ERRNO_DIGITS_MAX (sizeof (int) * 3 + 1)
+/*
+ * A limit on recursion, to avoid colliding with the heap. UEFI defines a baseline
+ * stack size of 128 KiB. So, assuming at most 1-2 KiB per iteration this should
+ * keep us safe.
+ */
+#define MAX_RECURSION_DEPTH 64
+
static unsigned long is_continue;
static unsigned long active_loops;
static unsigned long active_breaks;
static unsigned long function_return;
+static unsigned long recursion_depth;
#define GRUB_SCRIPT_SCOPE_MALLOCED 1
#define GRUB_SCRIPT_SCOPE_ARGS_MALLOCED 2
@@ -850,7 +858,13 @@ grub_script_execute_cmd (struct grub_script_cmd *cmd)
if (cmd == 0)
return 0;
+ recursion_depth++;
+
+ if (recursion_depth >= MAX_RECURSION_DEPTH)
+ return grub_error (GRUB_ERR_RECURSION_DEPTH, N_("maximum recursion depth exceeded"));
+
ret = cmd->exec (cmd);
+ recursion_depth--;
grub_snprintf (errnobuf, sizeof (errnobuf), "%d", ret);
grub_env_set ("?", errnobuf);

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 1001c611d..fd78f09b0 100644
--- a/grub-core/net/net.c
+++ b/grub-core/net/net.c
@@ -2166,6 +2166,8 @@ GRUB_MOD_FINI(net)
grub_register_variable_hook ("net_default_server", 0, 0);
grub_register_variable_hook ("pxe_default_server", 0, 0);
+ grub_register_variable_hook ("net_default_ip", 0, 0);
+ grub_register_variable_hook ("net_default_mac", 0, 0);
grub_bootp_fini ();
grub_dns_fini ();

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 fd78f09b0..251286227 100644
--- a/grub-core/net/net.c
+++ b/grub-core/net/net.c
@@ -1051,6 +1051,39 @@ grub_net_add_ipv6_local (struct grub_net_network_level_interface *inter,
return 0;
}
+void
+grub_net_network_level_interface_unregister (struct grub_net_network_level_interface *inter)
+{
+ char *name;
+
+ {
+ char buf[GRUB_NET_MAX_STR_HWADDR_LEN];
+
+ grub_net_hwaddr_to_str (&inter->hwaddress, buf);
+ name = grub_xasprintf ("net_%s_mac", inter->name);
+ if (name != NULL)
+ grub_register_variable_hook (name, NULL, NULL);
+ grub_free (name);
+ }
+
+ {
+ char buf[GRUB_NET_MAX_STR_ADDR_LEN];
+
+ grub_net_addr_to_str (&inter->address, buf);
+ name = grub_xasprintf ("net_%s_ip", inter->name);
+ if (name != NULL)
+ grub_register_variable_hook (name, NULL, NULL);
+ grub_free (name);
+ }
+
+ inter->card->num_ifaces--;
+ *inter->prev = inter->next;
+ if (inter->next)
+ inter->next->prev = inter->prev;
+ inter->next = 0;
+ inter->prev = 0;
+}
+
grub_err_t
grub_net_add_ipv4_local (struct grub_net_network_level_interface *inter,
int mask)
diff --git a/include/grub/net.h b/include/grub/net.h
index 9e4898cc6..43eba9216 100644
--- a/include/grub/net.h
+++ b/include/grub/net.h
@@ -618,16 +618,7 @@ void grub_bootp_fini (void);
void grub_dns_init (void);
void grub_dns_fini (void);
-static inline void
-grub_net_network_level_interface_unregister (struct grub_net_network_level_interface *inter)
-{
- inter->card->num_ifaces--;
- *inter->prev = inter->next;
- if (inter->next)
- inter->next->prev = inter->prev;
- inter->next = 0;
- inter->prev = 0;
-}
+void grub_net_network_level_interface_unregister (struct grub_net_network_level_interface *inter);
void
grub_net_tcp_retransmit (void);

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 251286227..6c0bd00b4 100644
--- a/grub-core/net/net.c
+++ b/grub-core/net/net.c
@@ -1971,14 +1971,15 @@ grub_config_search_through (char *config, char *suffix,
}
grub_err_t
-grub_net_search_config_file (char *config)
+grub_net_search_config_file (char *config, grub_size_t config_buf_len)
{
- grub_size_t config_len;
+ grub_size_t config_len, suffix_len;
char *suffix;
config_len = grub_strlen (config);
config[config_len] = '-';
suffix = config + config_len + 1;
+ suffix_len = config_buf_len - (config_len + 1);
struct grub_net_network_level_interface *inf;
FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
@@ -2004,7 +2005,7 @@ grub_net_search_config_file (char *config)
if (client_uuid)
{
- grub_strcpy (suffix, client_uuid);
+ grub_strlcpy (suffix, client_uuid, suffix_len);
if (grub_config_search_through (config, suffix, 1, 0) == 0)
return GRUB_ERR_NONE;
}
diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
index 6f6e4a813..49b947292 100644
--- a/grub-core/normal/main.c
+++ b/grub-core/normal/main.c
@@ -360,7 +360,7 @@ grub_try_normal_prefix (const char *prefix)
return err;
grub_snprintf (config, config_len, "%s/grub.cfg", prefix);
- err = grub_net_search_config_file (config);
+ err = grub_net_search_config_file (config, config_len);
}
if (err != GRUB_ERR_NONE)
diff --git a/include/grub/net.h b/include/grub/net.h
index 43eba9216..1101b0397 100644
--- a/include/grub/net.h
+++ b/include/grub/net.h
@@ -648,7 +648,7 @@ void
grub_net_remove_dns_server (const struct grub_net_network_level_address *s);
grub_err_t
-grub_net_search_config_file (char *config);
+grub_net_search_config_file (char *config, grub_size_t config_buf_len);
extern char *grub_net_default_server;

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 a95766dcb..ecfcc13d9 100644
--- a/grub-core/net/tftp.c
+++ b/grub-core/net/tftp.c
@@ -266,17 +266,19 @@ tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)),
* forward slashes to a single forward slash.
*/
static void
-grub_normalize_filename (char *normalized, const char *filename)
+grub_normalize_filename (char *normalized, const char *filename, int c)
{
char *dest = normalized;
const char *src = filename;
- while (*src != '\0')
+ while (*src != '\0' && c > 0)
{
if (src[0] == '/' && src[1] == '/')
src++;
- else
+ else {
+ c--;
*dest++ = *src++;
+ }
}
*dest = '\0';
}
@@ -287,7 +289,7 @@ tftp_open (struct grub_file *file, const char *filename)
struct tftphdr *tftph;
char *rrq;
int i;
- int rrqlen;
+ int rrqlen, rrqsize;
int hdrlen;
grub_uint8_t open_data[1500];
struct grub_net_buff nb;
@@ -315,37 +317,45 @@ tftp_open (struct grub_file *file, const char *filename)
tftph = (struct tftphdr *) nb.data;
- rrq = (char *) tftph->u.rrq;
- rrqlen = 0;
-
tftph->opcode = grub_cpu_to_be16_compile_time (TFTP_RRQ);
+ rrq = (char *) tftph->u.rrq;
+ rrqsize = sizeof (tftph->u.rrq);
+
/*
* Copy and normalize the filename to work-around issues on some TFTP
* servers when file names are being matched for remapping.
*/
- grub_normalize_filename (rrq, filename);
- rrqlen += grub_strlen (rrq) + 1;
+ grub_normalize_filename (rrq, filename, rrqsize);
+
+ rrqlen = grub_strlen (rrq) + 1;
rrq += grub_strlen (rrq) + 1;
- grub_strcpy (rrq, "octet");
+ /* Verify there is enough space for the remaining components. */
rrqlen += grub_strlen ("octet") + 1;
+ rrqlen += grub_strlen ("blksize") + 1;
+ rrqlen += grub_strlen ("1024") + 1;
+ rrqlen += grub_strlen ("tsize") + 1;
+ rrqlen += grub_strlen ("0") + 1;
+
+ if (rrqlen >= rrqsize) {
+ grub_free (data);
+ return grub_error (GRUB_ERR_BAD_FILENAME, N_("filename too long"));
+ }
+
+ grub_strcpy (rrq, "octet");
rrq += grub_strlen ("octet") + 1;
grub_strcpy (rrq, "blksize");
- rrqlen += grub_strlen ("blksize") + 1;
rrq += grub_strlen ("blksize") + 1;
grub_strcpy (rrq, "1024");
- rrqlen += grub_strlen ("1024") + 1;
rrq += grub_strlen ("1024") + 1;
grub_strcpy (rrq, "tsize");
- rrqlen += grub_strlen ("tsize") + 1;
rrq += grub_strlen ("tsize") + 1;
grub_strcpy (rrq, "0");
- rrqlen += grub_strlen ("0") + 1;
rrq += grub_strlen ("0") + 1;
hdrlen = sizeof (tftph->opcode) + rrqlen;

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 2da04094b..c7aaac362 100644
--- a/grub-core/video/readers/jpeg.c
+++ b/grub-core/video/readers/jpeg.c
@@ -332,6 +332,10 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data)
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
+ if (data->image_height != 0 || data->image_width != 0)
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ "jpeg: cannot have duplicate SOF0 markers");
+
if (grub_jpeg_get_byte (data) != 8)
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"jpeg: only 8-bit precision is supported");

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 f3cdb9e0b..944e5600a 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. */
@@ -604,7 +605,7 @@ grub_dl_resolve_dependencies (grub_dl_t mod, Elf_Ehdr *e)
return GRUB_ERR_NONE;
}
-int
+grub_uint64_t
grub_dl_ref (grub_dl_t mod)
{
grub_dl_dep_t dep;
@@ -615,10 +616,13 @@ grub_dl_ref (grub_dl_t mod)
for (dep = mod->dep; dep; dep = dep->next)
grub_dl_ref (dep->mod);
- return ++mod->ref_count;
+ if (grub_add (mod->ref_count, 1, &mod->ref_count))
+ grub_fatal ("Module reference count overflow");
+
+ return mod->ref_count;
}
-int
+grub_uint64_t
grub_dl_unref (grub_dl_t mod)
{
grub_dl_dep_t dep;
@@ -629,10 +633,13 @@ grub_dl_unref (grub_dl_t mod)
for (dep = mod->dep; dep; dep = dep->next)
grub_dl_unref (dep->mod);
- return --mod->ref_count;
+ if (grub_sub (mod->ref_count, 1, &mod->ref_count))
+ grub_fatal ("Module reference count underflow");
+
+ return mod->ref_count;
}
-int
+grub_uint64_t
grub_dl_ref_count (grub_dl_t mod)
{
if (mod == NULL)
diff --git a/include/grub/dl.h b/include/grub/dl.h
index 6bc2560bf..fdf55d4ee 100644
--- a/include/grub/dl.h
+++ b/include/grub/dl.h
@@ -177,7 +177,7 @@ typedef struct grub_dl_dep *grub_dl_dep_t;
struct grub_dl
{
char *name;
- int ref_count;
+ grub_uint64_t ref_count;
int persistent;
grub_dl_dep_t dep;
grub_dl_segment_t segment;
@@ -206,9 +206,9 @@ grub_dl_t EXPORT_FUNC(grub_dl_load) (const char *name);
grub_dl_t grub_dl_load_core (void *addr, grub_size_t size);
grub_dl_t EXPORT_FUNC(grub_dl_load_core_noinit) (void *addr, grub_size_t size);
int EXPORT_FUNC(grub_dl_unload) (grub_dl_t mod);
-extern int EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod);
-extern int EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod);
-extern int EXPORT_FUNC(grub_dl_ref_count) (grub_dl_t mod);
+extern grub_uint64_t EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod);
+extern grub_uint64_t EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod);
+extern grub_uint64_t EXPORT_FUNC(grub_dl_ref_count) (grub_dl_t mod);
extern grub_dl_t EXPORT_VAR(grub_dl_head);
diff --git a/util/misc.c b/util/misc.c
index d545212d9..0f928e5b4 100644
--- a/util/misc.c
+++ b/util/misc.c
@@ -190,14 +190,14 @@ grub_xputs_real (const char *str)
void (*grub_xputs) (const char *str) = grub_xputs_real;
-int
+grub_uint64_t
grub_dl_ref (grub_dl_t mod)
{
(void) mod;
return 0;
}
-int
+grub_uint64_t
grub_dl_unref (grub_dl_t mod)
{
(void) mod;

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 944e5600a..f2806f8cf 100644
--- a/grub-core/kern/dl.c
+++ b/grub-core/kern/dl.c
@@ -672,6 +672,9 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
grub_dl_segment_t seg;
grub_err_t err;
+ if (!(s->sh_flags & SHF_INFO_LINK))
+ continue;
+
seg = grub_dl_find_segment(mod, s->sh_info);
if (!seg)
continue;

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 8e98c73cc..783c82713 100644
--- a/grub-core/commands/ls.c
+++ b/grub-core/commands/ls.c
@@ -241,7 +241,11 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human)
grub_file_close (file);
- p = grub_strrchr (dirname, '/') + 1;
+ p = grub_strrchr (dirname, '/');
+ if (p == NULL)
+ goto fail;
+ ++p;
+
dirname = grub_strndup (dirname, p - dirname);
if (! dirname)
goto fail;

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 b81ac0ae4..4a6a5f9a0 100644
--- a/grub-core/commands/pgp.c
+++ b/grub-core/commands/pgp.c
@@ -982,6 +982,8 @@ GRUB_MOD_INIT(pgp)
GRUB_MOD_FINI(pgp)
{
+ grub_register_variable_hook ("check_signatures", NULL, NULL);
+ grub_env_unset ("check_signatures");
grub_verifier_unregister (&grub_pubkey_verifier);
grub_unregister_extcmd (cmd);
grub_unregister_extcmd (cmd_trust);

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 49b947292..c96b6609d 100644
--- a/grub-core/normal/main.c
+++ b/grub-core/normal/main.c
@@ -689,7 +689,9 @@ GRUB_MOD_FINI(normal)
grub_xputs = grub_xputs_saved;
grub_set_history (0);
- grub_register_variable_hook ("pager", 0, 0);
+ grub_register_variable_hook ("pager", NULL, NULL);
+ grub_register_variable_hook ("color_normal", NULL, NULL);
+ grub_register_variable_hook ("color_highlight", NULL, NULL);
grub_fs_autoload_hook = 0;
grub_unregister_command (cmd_clear);
}

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 7ec81ca0b..16169e81f 100644
--- a/grub-core/gettext/gettext.c
+++ b/grub-core/gettext/gettext.c
@@ -542,6 +542,10 @@ GRUB_MOD_INIT (gettext)
GRUB_MOD_FINI (gettext)
{
+ grub_register_variable_hook ("locale_dir", NULL, NULL);
+ grub_register_variable_hook ("secondary_locale_dir", NULL, NULL);
+ grub_register_variable_hook ("lang", NULL, NULL);
+
grub_gettext_delete_list (&main_context);
grub_gettext_delete_list (&secondary_context);

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 16169e81f..868524839 100644
--- a/grub-core/gettext/gettext.c
+++ b/grub-core/gettext/gettext.c
@@ -323,8 +323,8 @@ grub_mofile_open (struct grub_gettext_context *ctx,
for (ctx->grub_gettext_max_log = 0; ctx->grub_gettext_max >> ctx->grub_gettext_max_log;
ctx->grub_gettext_max_log++);
- ctx->grub_gettext_msg_list = grub_zalloc (ctx->grub_gettext_max
- * sizeof (ctx->grub_gettext_msg_list[0]));
+ ctx->grub_gettext_msg_list = grub_calloc (ctx->grub_gettext_max,
+ sizeof (ctx->grub_gettext_msg_list[0]));
if (!ctx->grub_gettext_msg_list)
{
grub_file_close (fd);

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 868524839..0e51b5d28 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,106 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Glenn Washburn <development@efficientek.com>
Date: Sun, 21 Mar 2021 15:22:19 -0500
Subject: [PATCH] commands/read: Add silent mode to read command to suppress
input echo
This conforms to the behavior of the -s option of the Bash read command.
docs/grub: Document the -s option for the read command.
Signed-off-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
docs/grub.texi | 5 +++--
grub-core/commands/read.c | 28 ++++++++++++++++++----------
2 files changed, 21 insertions(+), 12 deletions(-)
diff --git a/docs/grub.texi b/docs/grub.texi
index bbcd1c931..913c3bff3 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -5041,10 +5041,11 @@ and the system will reboot.
@node read
@subsection read
-@deffn Command read [var]
+@deffn Command read [-s] [var]
Read a line of input from the user. If an environment variable @var{var} is
given, set that environment variable to the line of input that was read,
-with no terminating newline.
+with no terminating newline. If the parameter @option{-s} is used, enable
+silent mode where input is not printed to the terminal.
@end deffn
diff --git a/grub-core/commands/read.c b/grub-core/commands/read.c
index fe3e88b15..c2969ccda 100644
--- a/grub-core/commands/read.c
+++ b/grub-core/commands/read.c
@@ -23,13 +23,19 @@
#include <grub/env.h>
#include <grub/term.h>
#include <grub/types.h>
-#include <grub/command.h>
+#include <grub/extcmd.h>
#include <grub/i18n.h>
GRUB_MOD_LICENSE ("GPLv3+");
+static const struct grub_arg_option options[] =
+ {
+ {"silent", 's', 0, N_("Do not echo input"), 0, 0},
+ {0, 0, 0, 0, 0, 0}
+ };
+
static char *
-grub_getline (void)
+grub_getline (int silent)
{
int i;
char *line;
@@ -48,7 +54,7 @@ grub_getline (void)
break;
line[i] = c;
- if (grub_isprint (c))
+ if (!silent && grub_isprint (c))
grub_printf ("%c", c);
i++;
tmp = grub_realloc (line, 1 + i + sizeof('\0'));
@@ -65,9 +71,11 @@ grub_getline (void)
}
static grub_err_t
-grub_cmd_read (grub_command_t cmd __attribute__ ((unused)), int argc, char **args)
+grub_cmd_read (grub_extcmd_context_t ctxt, int argc, char **args)
{
- char *line = grub_getline ();
+ struct grub_arg_list *state = ctxt->state;
+ char *line = grub_getline (state[0].set);
+
if (! line)
return grub_errno;
if (argc > 0)
@@ -77,16 +85,16 @@ grub_cmd_read (grub_command_t cmd __attribute__ ((unused)), int argc, char **arg
return 0;
}
-static grub_command_t cmd;
+static grub_extcmd_t cmd;
GRUB_MOD_INIT(read)
{
- cmd = grub_register_command ("read", grub_cmd_read,
- N_("[ENVVAR]"),
- N_("Set variable with user input."));
+ cmd = grub_register_extcmd ("read", grub_cmd_read, 0,
+ N_("[-s] [ENVVAR]"),
+ N_("Set variable with user input."), options);
}
GRUB_MOD_FINI(read)
{
- grub_unregister_command (cmd);
+ grub_unregister_extcmd (cmd);
}

View File

@ -0,0 +1,47 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Li Gen <ligenlive@gmail.com>
Date: Thu, 25 Aug 2022 19:59:09 -0500
Subject: [PATCH] commands/read: Fix overflow in grub_getline()
Store returned value from grub_getkey() in int instead of char to
prevent throwing away the extended bits. This was a problem because,
for instance, the left arrow key press would return
(GRUB_TERM_EXTENDED | 0x4b), which would have the GRUB_TERM_EXTENDED
thrown away leaving 0x4b or 'K'. These extended keys should either
work as intended or do nothing. This change has them do nothing,
instead of inserting a key not pressed by the user.
Signed-off-by: Li Gen <ligenlive@gmail.com>
Signed-off-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/commands/read.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/grub-core/commands/read.c b/grub-core/commands/read.c
index c2969ccda..597c90706 100644
--- a/grub-core/commands/read.c
+++ b/grub-core/commands/read.c
@@ -40,7 +40,7 @@ grub_getline (int silent)
int i;
char *line;
char *tmp;
- char c;
+ int c;
i = 0;
line = grub_malloc (1 + i + sizeof('\0'));
@@ -53,8 +53,11 @@ grub_getline (int silent)
if ((c == '\n') || (c == '\r'))
break;
- line[i] = c;
- if (!silent && grub_isprint (c))
+ if (!grub_isprint (c))
+ continue;
+
+ line[i] = (char) c;
+ if (!silent)
grub_printf ("%c", c);
i++;
tmp = grub_realloc (line, 1 + i + sizeof('\0'));

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 17705812d..760c6229a 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+");
@@ -1104,8 +1105,11 @@ GRUB_MOD_INIT (bfs)
{
COMPILE_TIME_ASSERT (1 << LOG_EXTENT_SIZE ==
sizeof (struct grub_bfs_extent));
- grub_bfs_fs.mod = mod;
- grub_fs_register (&grub_bfs_fs);
+ if (!grub_is_lockdown ())
+ {
+ grub_bfs_fs.mod = mod;
+ grub_fs_register (&grub_bfs_fs);
+ }
}
#ifdef MODE_AFS
@@ -1114,5 +1118,6 @@ GRUB_MOD_FINI (afs)
GRUB_MOD_FINI (bfs)
#endif
{
- grub_fs_unregister (&grub_bfs_fs);
+ if (!grub_is_lockdown ())
+ grub_fs_unregister (&grub_bfs_fs);
}

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 b1c64e77d..0133528ea 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+");
@@ -699,12 +700,16 @@ static struct grub_fs grub_affs_fs =
GRUB_MOD_INIT(affs)
{
- grub_affs_fs.mod = mod;
- grub_fs_register (&grub_affs_fs);
+ if (!grub_is_lockdown ())
+ {
+ grub_affs_fs.mod = mod;
+ grub_fs_register (&grub_affs_fs);
+ }
my_mod = mod;
}
GRUB_MOD_FINI(affs)
{
- grub_fs_unregister (&grub_affs_fs);
+ if (!grub_is_lockdown ())
+ grub_fs_unregister (&grub_affs_fs);
}
diff --git a/grub-core/fs/cbfs.c b/grub-core/fs/cbfs.c
index 3e527cbf2..90c07ddf8 100644
--- a/grub-core/fs/cbfs.c
+++ b/grub-core/fs/cbfs.c
@@ -26,6 +26,7 @@
#include <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 beb1a6378..fc7fa80d9 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+");
@@ -732,8 +733,11 @@ GRUB_MOD_INIT(minix)
#endif
#endif
{
- grub_minix_fs.mod = mod;
- grub_fs_register (&grub_minix_fs);
+ if (!grub_is_lockdown ())
+ {
+ grub_minix_fs.mod = mod;
+ grub_fs_register (&grub_minix_fs);
+ }
my_mod = mod;
}
@@ -755,5 +759,6 @@ GRUB_MOD_FINI(minix)
#endif
#endif
{
- grub_fs_unregister (&grub_minix_fs);
+ if (!grub_is_lockdown ())
+ grub_fs_unregister (&grub_minix_fs);
}
diff --git a/grub-core/fs/nilfs2.c b/grub-core/fs/nilfs2.c
index c44583ee8..dd10c08f3 100644
--- a/grub-core/fs/nilfs2.c
+++ b/grub-core/fs/nilfs2.c
@@ -34,6 +34,7 @@
#include <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 03e3e5c6a..96f038c54 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+");
@@ -1537,12 +1538,16 @@ static struct grub_fs grub_ntfs_fs =
GRUB_MOD_INIT (ntfs)
{
- grub_ntfs_fs.mod = mod;
- grub_fs_register (&grub_ntfs_fs);
+ if (!grub_is_lockdown ())
+ {
+ grub_ntfs_fs.mod = mod;
+ grub_fs_register (&grub_ntfs_fs);
+ }
my_mod = mod;
}
GRUB_MOD_FINI (ntfs)
{
- grub_fs_unregister (&grub_ntfs_fs);
+ if (!grub_is_lockdown ())
+ grub_fs_unregister (&grub_ntfs_fs);
}
diff --git a/grub-core/fs/reiserfs.c b/grub-core/fs/reiserfs.c
index d9a8bf602..84aadfae9 100644
--- a/grub-core/fs/reiserfs.c
+++ b/grub-core/fs/reiserfs.c
@@ -39,6 +39,7 @@
#include <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 a43546d95..6ee469911 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 3d4b40263..c0c31ae9c 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>
@@ -1382,12 +1383,16 @@ static struct grub_fs grub_udf_fs = {
GRUB_MOD_INIT (udf)
{
- grub_udf_fs.mod = mod;
- grub_fs_register (&grub_udf_fs);
+ if (!grub_is_lockdown ())
+ {
+ grub_udf_fs.mod = mod;
+ grub_fs_register (&grub_udf_fs);
+ }
my_mod = mod;
}
GRUB_MOD_FINI (udf)
{
- grub_fs_unregister (&grub_udf_fs);
+ if (!grub_is_lockdown ())
+ grub_fs_unregister (&grub_udf_fs);
}
diff --git a/grub-core/fs/ufs.c b/grub-core/fs/ufs.c
index 7f72494cd..22b669b4c 100644
--- a/grub-core/fs/ufs.c
+++ b/grub-core/fs/ufs.c
@@ -25,6 +25,7 @@
#include <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,603 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Maxim Fomin <maxim@fomin.one>
Date: Wed, 28 Dec 2022 17:20:00 +0000
Subject: [PATCH] disk/plainmount: Support plain encryption mode
This patch adds support for plain encryption mode, plain dm-crypt, via
new module/command named "plainmount".
Signed-off-by: Maxim Fomin <maxim@fomin.one>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Reviewed-by: Glenn Washburn <development@efficientek.com>
---
docs/grub.texi | 80 ++++++++
grub-core/Makefile.core.def | 5 +
grub-core/disk/plainmount.c | 458 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 543 insertions(+)
create mode 100644 grub-core/disk/plainmount.c
diff --git a/docs/grub.texi b/docs/grub.texi
index 913c3bff3..50c37d6ff 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -4052,6 +4052,7 @@ you forget a command, you can run the command @command{help}
* parttool:: Modify partition table entries
* password:: Set a clear-text password
* password_pbkdf2:: Set a hashed password
+* plainmount:: Open device encrypted in plain mode
* play:: Play a tune
* probe:: Retrieve device info
* rdmsr:: Read values from model-specific registers
@@ -4344,6 +4345,14 @@ function is supported, as Argon2 is not yet supported.
Also, note that, unlike filesystem UUIDs, UUIDs for encrypted devices must be
specified without dash separators.
+
+Successfully decrypted disks are named as (cryptoX) and have increasing numeration
+suffix for each new decrypted disk. If the encrypted disk hosts some higher level
+of abstraction (like LVM2 or MDRAID) it will be created under a separate device
+namespace in addition to the cryptodisk namespace.
+
+Support for plain encryption mode (plain dm-crypt) is provided via separate
+@command{@pxref{plainmount}} command.
@end deffn
@node cutmem
@@ -4990,6 +4999,77 @@ to generate password hashes. @xref{Security}.
@end deffn
+@node plainmount
+@subsection plainmount
+
+@deffn Command plainmount device @option{-c} cipher @option{-s} key size [@option{-h} hash]
+[@option{-S} sector size] [@option{-p} password] [@option{-u} uuid]
+[[@option{-d} keyfile] [@option{-O} keyfile offset]]
+
+
+Setup access to the encrypted device in plain mode. Offset of the encrypted
+data at the device is specified in terms of 512 byte sectors using the blocklist
+syntax and loopback device. The following example shows how to specify 1MiB
+offset:
+
+@example
+loopback node (hd0,gpt1)2048+
+plainmount node @var{...}
+@end example
+
+The @command{plainmount} command can be used to open LUKS encrypted volume
+if its master key and parameters (key size, cipher, offset, etc) are known.
+
+There are two ways to specify a password: a keyfile and a secret passphrase.
+The keyfile path parameter has higher priority than the secret passphrase
+parameter and is specified with the option @option{-d}. Password data obtained
+from keyfiles is not hashed and is used directly as a cipher key. An optional
+offset of password data in the keyfile can be specified with the option
+@option{-O} or directly with the option @option{-d} and GRUB blocklist syntax,
+if the keyfile data can be accessed from a device and is 512 byte aligned.
+The following example shows both methods to specify password data in the
+keyfile at offset 1MiB:
+
+@example
+plainmount -d (hd0,gpt1)2048+ @var{...}
+plainmount -d (hd0,gpt1)+ -O 1048576 @var{...}
+@end example
+
+If no keyfile is specified then the password is set to the string specified
+by option @option{-p} or is requested interactively from the console. In both
+cases the provided password is hashed with the algorithm specified by the
+option @option{-h}. This option is mandatory if no keyfile is specified, but
+it can be set to @samp{plain} which means that no hashing is done and such
+password is used directly as a key.
+
+Cipher @option{-c} and keysize @option{-s} options specify the cipher algorithm
+and the key size respectively and are mandatory options. Cipher must be specified
+with the mode separated by a dash (for example, @samp{aes-xts-plain64}). Key size
+option @option{-s} is the key size of the cipher in bits, not to be confused with
+the offset of the key data in a keyfile specified with the @option{-O} option. It
+must not exceed 1024 bits, so a 32 byte key would be specified as 256 bits
+
+The optional parameter @option{-S} specifies encrypted device sector size. It
+must be at least 512 bytes long (default value) and a power of 2. @footnote{Current
+implementation of cryptsetup supports only 512/1024/2048/4096 byte sectors}.
+Disk sector size is configured when creating the encrypted volume. Attempting
+to decrypt volumes with a different sector size than it was created with will
+not result in an error, but will decrypt to random bytes and thus prevent
+accessing the volume (in some cases the filesystem driver can detect the presence
+of a filesystem, but nevertheless will refuse to mount it).
+
+By default new plainmount devices will be given a UUID starting with
+'109fea84-a6b7-34a8-4bd1-1c506305a401' where the last digits are incremented
+by one for each plainmounted device beyond the first up to 2^10 devices.
+
+All encryption arguments (cipher, hash, key size, disk offset and disk sector
+size) must match the parameters used to create the volume. If any of them does
+not match the actual arguments used during the initial encryption, plainmount
+will create virtual device with the garbage data and GRUB will report unknown
+filesystem for such device.
+@end deffn
+
+
@node play
@subsection play
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 505c3b63d..b8e29c788 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -1239,6 +1239,11 @@ module = {
common = disk/cryptodisk.c;
};
+module = {
+ name = plainmount;
+ common = disk/plainmount.c;
+};
+
module = {
name = json;
common = lib/json/json.c;
diff --git a/grub-core/disk/plainmount.c b/grub-core/disk/plainmount.c
new file mode 100644
index 000000000..47e64805f
--- /dev/null
+++ b/grub-core/disk/plainmount.c
@@ -0,0 +1,458 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* plaimount.c - Open device encrypted in plain mode. */
+
+#include <grub/cryptodisk.h>
+#include <grub/dl.h>
+#include <grub/err.h>
+#include <grub/extcmd.h>
+#include <grub/partition.h>
+#include <grub/file.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+#define PLAINMOUNT_DEFAULT_SECTOR_SIZE 512
+#define PLAINMOUNT_DEFAULT_UUID "109fea84-a6b7-34a8-4bd1-1c506305a400"
+
+
+enum PLAINMOUNT_OPTION
+ {
+ OPTION_HASH,
+ OPTION_CIPHER,
+ OPTION_KEY_SIZE,
+ OPTION_SECTOR_SIZE,
+ OPTION_PASSWORD,
+ OPTION_KEYFILE,
+ OPTION_KEYFILE_OFFSET,
+ OPTION_UUID
+ };
+
+static const struct grub_arg_option options[] =
+ {
+ /* TRANSLATORS: It's still restricted to this module only. */
+ {"hash", 'h', 0, N_("Password hash"), 0, ARG_TYPE_STRING},
+ {"cipher", 'c', 0, N_("Password cipher"), 0, ARG_TYPE_STRING},
+ {"key-size", 's', 0, N_("Key size (in bits)"), 0, ARG_TYPE_INT},
+ {"sector-size", 'S', 0, N_("Device sector size"), 0, ARG_TYPE_INT},
+ {"password", 'p', 0, N_("Password (key)"), 0, ARG_TYPE_STRING},
+ {"keyfile", 'd', 0, N_("Keyfile path"), 0, ARG_TYPE_STRING},
+ {"keyfile-offset", 'O', 0, N_("Keyfile offset"), 0, ARG_TYPE_INT},
+ {"uuid", 'u', 0, N_("Set device UUID"), 0, ARG_TYPE_STRING},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+/* Cryptodisk setkey() function wrapper */
+static grub_err_t
+plainmount_setkey (grub_cryptodisk_t dev, grub_uint8_t *key,
+ grub_size_t size)
+{
+ gcry_err_code_t code = grub_cryptodisk_setkey (dev, key, size);
+ if (code != GPG_ERR_NO_ERROR)
+ {
+ grub_dprintf ("plainmount", "failed to set cipher key with code: %d\n", code);
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("cannot set specified key"));
+ }
+ return GRUB_ERR_NONE;
+}
+
+/* Configure cryptodisk uuid */
+static void plainmount_set_uuid (grub_cryptodisk_t dev, const char *user_uuid)
+{
+ grub_size_t pos = 0;
+
+ /* Size of user_uuid is checked in main func */
+ if (user_uuid != NULL)
+ grub_strcpy (dev->uuid, user_uuid);
+ else
+ {
+ /*
+ * Set default UUID. Last digits start from 1 and are incremented for
+ * each new plainmount device by snprintf().
+ */
+ grub_snprintf (dev->uuid, sizeof (dev->uuid) - 1, "%36lx", dev->id + 1);
+ while (dev->uuid[++pos] == ' ');
+ grub_memcpy (dev->uuid, PLAINMOUNT_DEFAULT_UUID, pos);
+ }
+ COMPILE_TIME_ASSERT (sizeof (dev->uuid) >= sizeof (PLAINMOUNT_DEFAULT_UUID));
+}
+
+/* Configure cryptodevice sector size (-S option) */
+static grub_err_t
+plainmount_configure_sectors (grub_cryptodisk_t dev, grub_disk_t disk,
+ grub_size_t sector_size)
+{
+ dev->total_sectors = grub_disk_native_sectors (disk);
+ if (dev->total_sectors == GRUB_DISK_SIZE_UNKNOWN)
+ return grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot determine disk %s size"),
+ disk->name);
+
+ /* Convert size to sectors */
+ dev->log_sector_size = grub_log2ull (sector_size);
+ dev->total_sectors = grub_convert_sector (dev->total_sectors,
+ GRUB_DISK_SECTOR_BITS,
+ dev->log_sector_size);
+ if (dev->total_sectors == 0)
+ return grub_error (GRUB_ERR_BAD_DEVICE,
+ N_("cannot set specified sector size on disk %s"),
+ disk->name);
+
+ grub_dprintf ("plainmount", "log_sector_size=%d, total_sectors=%"
+ PRIuGRUB_UINT64_T"\n", dev->log_sector_size, dev->total_sectors);
+ return GRUB_ERR_NONE;
+}
+
+/* Hashes a password into a key and stores it with the cipher. */
+static grub_err_t
+plainmount_configure_password (grub_cryptodisk_t dev, const char *hash,
+ grub_uint8_t *key_data, grub_size_t key_size,
+ grub_size_t password_size)
+{
+ grub_uint8_t *derived_hash, *dh;
+ char *p;
+ unsigned int round, i, len, size;
+ grub_size_t alloc_size;
+ grub_err_t err = GRUB_ERR_NONE;
+
+ /* Support none (plain) hash */
+ if (grub_strcmp (hash, "plain") == 0)
+ {
+ dev->hash = NULL;
+ return err;
+ }
+
+ /* Hash argument was checked at main func */
+ dev->hash = grub_crypto_lookup_md_by_name (hash);
+ len = dev->hash->mdlen;
+
+ alloc_size = grub_max (password_size, key_size);
+ /*
+ * Allocate buffer for the password and for an added prefix character
+ * for each hash round ('alloc_size' may not be a multiple of 'len').
+ */
+ p = grub_zalloc (alloc_size + (alloc_size / len) + 1);
+ derived_hash = grub_zalloc (GRUB_CRYPTODISK_MAX_KEYLEN * 2);
+ if (p == NULL || derived_hash == NULL)
+ {
+ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
+ goto fail;
+ }
+ dh = derived_hash;
+
+ /*
+ * Hash password. Adapted from cryptsetup.
+ * https://gitlab.com/cryptsetup/cryptsetup/-/blob/main/lib/crypt_plain.c
+ */
+ for (round = 0, size = alloc_size; size; round++, dh += len, size -= len)
+ {
+ for (i = 0; i < round; i++)
+ p[i] = 'A';
+
+ grub_memcpy (p + i, (char*) key_data, password_size);
+
+ if (len > size)
+ len = size;
+
+ grub_crypto_hash (dev->hash, dh, p, password_size + round);
+ }
+ grub_memcpy (key_data, derived_hash, key_size);
+
+ fail:
+ grub_free (p);
+ grub_free (derived_hash);
+ return err;
+}
+
+/* Read key material from keyfile */
+static grub_err_t
+plainmount_configure_keyfile (char *keyfile, grub_uint8_t *key_data,
+ grub_size_t key_size, grub_size_t keyfile_offset)
+{
+ grub_file_t g_keyfile = grub_file_open (keyfile, GRUB_FILE_TYPE_NONE);
+ if (g_keyfile == NULL)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("cannot open keyfile %s"),
+ keyfile);
+
+ if (grub_file_seek (g_keyfile, keyfile_offset) == (grub_off_t) - 1)
+ return grub_error (GRUB_ERR_FILE_READ_ERROR,
+ N_("cannot seek keyfile at offset %"PRIuGRUB_SIZE),
+ keyfile_offset);
+
+ if (key_size > (g_keyfile->size - keyfile_offset))
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Specified key size (%"
+ PRIuGRUB_SIZE") is too small for keyfile size (%"
+ PRIuGRUB_UINT64_T") and offset (%"PRIuGRUB_SIZE")"),
+ key_size, g_keyfile->size, keyfile_offset);
+
+ if (grub_file_read (g_keyfile, key_data, key_size) != (grub_ssize_t) key_size)
+ return grub_error (GRUB_ERR_FILE_READ_ERROR, N_("error reading key file"));
+ return GRUB_ERR_NONE;
+}
+
+/* Plainmount command entry point */
+static grub_err_t
+grub_cmd_plainmount (grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ struct grub_arg_list *state = ctxt->state;
+ grub_cryptodisk_t dev = NULL;
+ grub_disk_t disk = NULL;
+ const gcry_md_spec_t *gcry_hash;
+ char *diskname, *disklast = NULL, *cipher, *mode, *hash, *keyfile, *uuid;
+ grub_size_t len, key_size, sector_size, keyfile_offset = 0, password_size = 0;
+ grub_err_t err;
+ const char *p;
+ grub_uint8_t *key_data;
+
+ if (argc < 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("device name required"));
+
+ /* Check whether required arguments are specified */
+ if (!state[OPTION_CIPHER].set || !state[OPTION_KEY_SIZE].set)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "cipher and key size must be set");
+ if (!state[OPTION_HASH].set && !state[OPTION_KEYFILE].set)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "hash algorithm must be set");
+
+ /* Check hash */
+ if (!state[OPTION_KEYFILE].set)
+ {
+ gcry_hash = grub_crypto_lookup_md_by_name (state[OPTION_HASH].arg);
+ if (!gcry_hash)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("couldn't load hash %s"),
+ state[OPTION_HASH].arg);
+
+ if (gcry_hash->mdlen > GRUB_CRYPTODISK_MAX_KEYLEN)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("hash length %"PRIuGRUB_SIZE" exceeds maximum %d bits"),
+ gcry_hash->mdlen * GRUB_CHAR_BIT,
+ GRUB_CRYPTODISK_MAX_KEYLEN * GRUB_CHAR_BIT);
+ }
+
+ /* Check cipher mode */
+ if (!grub_strchr (state[OPTION_CIPHER].arg,'-'))
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("invalid cipher mode, must be of format cipher-mode"));
+
+ /* Check password size */
+ if (state[OPTION_PASSWORD].set && grub_strlen (state[OPTION_PASSWORD].arg) >
+ GRUB_CRYPTODISK_MAX_PASSPHRASE)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("password exceeds maximium size"));
+
+ /* Check uuid length */
+ if (state[OPTION_UUID].set && grub_strlen (state[OPTION_UUID].arg) >
+ GRUB_CRYPTODISK_MAX_UUID_LENGTH - 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("specified UUID exceeds maximum size"));
+ if (state[OPTION_UUID].set && grub_strlen (state[OPTION_UUID].arg) == 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("specified UUID too short"));
+
+ /* Parse plainmount arguments */
+ grub_errno = GRUB_ERR_NONE;
+ keyfile_offset = state[OPTION_KEYFILE_OFFSET].set ?
+ grub_strtoull (state[OPTION_KEYFILE_OFFSET].arg, &p, 0) : 0;
+ if (state[OPTION_KEYFILE_OFFSET].set &&
+ (state[OPTION_KEYFILE_OFFSET].arg[0] == '\0' || *p != '\0' ||
+ grub_errno != GRUB_ERR_NONE))
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unrecognized keyfile offset"));
+
+ sector_size = state[OPTION_SECTOR_SIZE].set ?
+ grub_strtoull (state[OPTION_SECTOR_SIZE].arg, &p, 0) :
+ PLAINMOUNT_DEFAULT_SECTOR_SIZE;
+ if (state[OPTION_SECTOR_SIZE].set && (state[OPTION_SECTOR_SIZE].arg[0] == '\0' ||
+ *p != '\0' || grub_errno != GRUB_ERR_NONE))
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unrecognized sector size"));
+
+ /* Check key size */
+ key_size = grub_strtoull (state[OPTION_KEY_SIZE].arg, &p, 0);
+ if (state[OPTION_KEY_SIZE].arg[0] == '\0' || *p != '\0' ||
+ grub_errno != GRUB_ERR_NONE)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unrecognized key size"));
+ if ((key_size % GRUB_CHAR_BIT) != 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("key size is not multiple of %d bits"), GRUB_CHAR_BIT);
+ key_size = key_size / GRUB_CHAR_BIT;
+ if (key_size > GRUB_CRYPTODISK_MAX_KEYLEN)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("key size %"PRIuGRUB_SIZE" exceeds maximum %d bits"),
+ key_size * GRUB_CHAR_BIT,
+ GRUB_CRYPTODISK_MAX_KEYLEN * GRUB_CHAR_BIT);
+
+ /* Check disk sector size */
+ if (sector_size < GRUB_DISK_SECTOR_SIZE)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("sector size -S must be at least %d"),
+ GRUB_DISK_SECTOR_SIZE);
+ if ((sector_size & (sector_size - 1)) != 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("sector size -S %"PRIuGRUB_SIZE" is not power of 2"),
+ sector_size);
+
+ /* Allocate all stuff here */
+ hash = state[OPTION_HASH].set ? grub_strdup (state[OPTION_HASH].arg) : NULL;
+ cipher = grub_strdup (state[OPTION_CIPHER].arg);
+ keyfile = state[OPTION_KEYFILE].set ?
+ grub_strdup (state[OPTION_KEYFILE].arg) : NULL;
+ dev = grub_zalloc (sizeof *dev);
+ key_data = grub_zalloc (GRUB_CRYPTODISK_MAX_PASSPHRASE);
+ uuid = state[OPTION_UUID].set ? grub_strdup (state[OPTION_UUID].arg) : NULL;
+ if ((state[OPTION_HASH].set && hash == NULL) || cipher == NULL || dev == NULL ||
+ (state[OPTION_KEYFILE].set && keyfile == NULL) || key_data == NULL ||
+ (state[OPTION_UUID].set && uuid == NULL))
+ {
+ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
+ goto fail;
+ }
+
+ /* Copy user password from -p option */
+ if (state[OPTION_PASSWORD].set)
+ {
+ /*
+ * Password from the '-p' option is limited to C-string.
+ * Arbitrary data keys are supported via keyfiles.
+ */
+ password_size = grub_strlen (state[OPTION_PASSWORD].arg);
+ grub_strcpy ((char*) key_data, state[OPTION_PASSWORD].arg);
+ }
+
+ /* Set cipher mode (tested above) */
+ mode = grub_strchr (cipher,'-');
+ *mode++ = '\0';
+
+ /* Check cipher */
+ err = grub_cryptodisk_setcipher (dev, cipher, mode);
+ if (err != GRUB_ERR_NONE)
+ {
+ if (err == GRUB_ERR_FILE_NOT_FOUND)
+ err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid cipher %s"), cipher);
+ else if (err == GRUB_ERR_BAD_ARGUMENT)
+ err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid mode %s"), mode);
+ else
+ err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid cipher %s or mode %s"),
+ cipher, mode);
+ goto fail;
+ }
+
+ /* Open SOURCE disk */
+ diskname = args[0];
+ len = grub_strlen (diskname);
+ if (len && diskname[0] == '(' && diskname[len - 1] == ')')
+ {
+ disklast = &diskname[len - 1];
+ *disklast = '\0';
+ diskname++;
+ }
+ disk = grub_disk_open (diskname);
+ if (disk == NULL)
+ {
+ if (disklast)
+ *disklast = ')';
+ err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("cannot open disk %s"), diskname);
+ goto fail;
+ }
+
+ /* Get password from console */
+ if (!state[OPTION_KEYFILE].set && key_data[0] == '\0')
+ {
+ char *part = grub_partition_get_name (disk->partition);
+ grub_printf_ (N_("Enter passphrase for %s%s%s: "), disk->name,
+ disk->partition != NULL ? "," : "",
+ part != NULL ? part : N_("UNKNOWN"));
+ grub_free (part);
+
+ if (!grub_password_get ((char*) key_data, GRUB_CRYPTODISK_MAX_PASSPHRASE - 1))
+ {
+ err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("error reading password"));
+ goto fail;
+ }
+ /*
+ * Password from interactive console is limited to C-string.
+ * Arbitrary data keys are supported via keyfiles.
+ */
+ password_size = grub_strlen ((char*) key_data);
+ }
+
+ /* Warn if hash and keyfile are both provided */
+ if (state[OPTION_KEYFILE].set && state[OPTION_HASH].arg)
+ grub_printf_ (N_("warning: hash is ignored if keyfile is specified\n"));
+
+ /* Warn if -p option is specified with keyfile */
+ if (state[OPTION_PASSWORD].set && state[OPTION_KEYFILE].set)
+ grub_printf_ (N_("warning: password specified with -p option "
+ "is ignored if keyfile is provided\n"));
+
+ /* Warn of -O is provided without keyfile */
+ if (state[OPTION_KEYFILE_OFFSET].set && !state[OPTION_KEYFILE].set)
+ grub_printf_ (N_("warning: keyfile offset option -O "
+ "specified without keyfile option -d\n"));
+
+ grub_dprintf ("plainmount", "parameters: cipher=%s, hash=%s, key_size=%"
+ PRIuGRUB_SIZE ", keyfile=%s, keyfile offset=%" PRIuGRUB_SIZE "\n",
+ cipher, hash, key_size, keyfile, keyfile_offset);
+
+ err = plainmount_configure_sectors (dev, disk, sector_size);
+ if (err != GRUB_ERR_NONE)
+ goto fail;
+
+ /* Configure keyfile or password */
+ if (state[OPTION_KEYFILE].set)
+ err = plainmount_configure_keyfile (keyfile, key_data, key_size, keyfile_offset);
+ else
+ err = plainmount_configure_password (dev, hash, key_data, key_size, password_size);
+ if (err != GRUB_ERR_NONE)
+ goto fail;
+
+ err = plainmount_setkey (dev, key_data, key_size);
+ if (err != GRUB_ERR_NONE)
+ goto fail;
+
+ err = grub_cryptodisk_insert (dev, diskname, disk);
+ if (err != GRUB_ERR_NONE)
+ goto fail;
+
+ dev->modname = "plainmount";
+ dev->source_disk = disk;
+ plainmount_set_uuid (dev, uuid);
+
+ fail:
+ grub_free (hash);
+ grub_free (cipher);
+ grub_free (keyfile);
+ grub_free (key_data);
+ grub_free (uuid);
+ if (err != GRUB_ERR_NONE && disk != NULL)
+ grub_disk_close (disk);
+ if (err != GRUB_ERR_NONE)
+ grub_free (dev);
+ return err;
+}
+
+static grub_extcmd_t cmd;
+GRUB_MOD_INIT (plainmount)
+{
+ cmd = grub_register_extcmd ("plainmount", grub_cmd_plainmount, 0,
+ N_("-c cipher -s key-size [-h hash] [-S sector-size]"
+ " [-o offset] [-p password] [-u uuid] "
+ " [[-d keyfile] [-O keyfile offset]] <SOURCE>"),
+ N_("Open partition encrypted in plain mode."),
+ options);
+}
+
+GRUB_MOD_FINI (plainmount)
+{
+ grub_unregister_extcmd (cmd);
+}

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 9c456c2..bd5eaf0 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 7cdffe3..4c0b568 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>
@@ -1016,7 +1017,7 @@ grub_diskfilter_make_raid (grub_size_t uuidlen, char *uuid, int nmemb,
{
struct grub_diskfilter_vg *array;
int i;
- grub_size_t j;
+ grub_size_t j, sz;
grub_uint64_t totsize;
struct grub_diskfilter_pv *pv;
grub_err_t err;
@@ -1110,7 +1111,11 @@ grub_diskfilter_make_raid (grub_size_t uuidlen, char *uuid, int nmemb,
}
array->lvs->vg = array;
- array->lvs->idname = grub_malloc (sizeof ("mduuid/") + 2 * uuidlen);
+ if (grub_mul (uuidlen, 2, &sz) ||
+ grub_add (sz, sizeof ("mduuid/"), &sz))
+ goto fail;
+
+ array->lvs->idname = grub_malloc (sz);
if (!array->lvs->idname)
goto fail;
diff --git a/grub-core/disk/ieee1275/obdisk.c b/grub-core/disk/ieee1275/obdisk.c
index ec413c3..8e4bbf1 100644
--- a/grub-core/disk/ieee1275/obdisk.c
+++ b/grub-core/disk/ieee1275/obdisk.c
@@ -26,6 +26,7 @@
#include <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 5534684..2099963 100644
--- a/grub-core/disk/ieee1275/ofdisk.c
+++ b/grub-core/disk/ieee1275/ofdisk.c
@@ -24,6 +24,7 @@
#include <grub/ieee1275/ofdisk.h>
#include <grub/i18n.h>
#include <grub/time.h>
+#include <grub/safemath.h>
static char *last_devpath;
static grub_ieee1275_ihandle_t last_ihandle;
@@ -80,6 +81,7 @@ ofdisk_hash_add_real (char *devpath)
struct ofdisk_hash_ent **head = &ofdisk_hash[ofdisk_hash_fn(devpath)];
const char *iptr;
char *optr;
+ grub_size_t sz;
p = grub_zalloc (sizeof (*p));
if (!p)
@@ -87,8 +89,14 @@ ofdisk_hash_add_real (char *devpath)
p->devpath = devpath;
- p->grub_devpath = grub_malloc (sizeof ("ieee1275/")
- + 2 * grub_strlen (p->devpath));
+ if (grub_mul (grub_strlen (p->devpath), 2, &sz) ||
+ grub_add (sz, sizeof ("ieee1275/"), &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining size of device path"));
+ return NULL;
+ }
+
+ p->grub_devpath = grub_malloc (sz);
if (!p->grub_devpath)
{
@@ -98,7 +106,13 @@ ofdisk_hash_add_real (char *devpath)
if (! grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_PARTITION_0))
{
- p->open_path = grub_malloc (grub_strlen (p->devpath) + 3);
+ if (grub_add (grub_strlen (p->devpath), 3, &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining size of an open path"));
+ return NULL;
+ }
+
+ p->open_path = grub_malloc (sz);
if (!p->open_path)
{
grub_free (p->grub_devpath);
@@ -224,7 +238,7 @@ dev_iterate (const struct grub_ieee1275_devalias *alias)
args;
char *buf, *bufptr;
unsigned i;
-
+ grub_size_t sz;
RETRY_IEEE1275_OFDISK_OPEN(alias->path, &ihandle)
if (! ihandle)
@@ -245,7 +259,14 @@ dev_iterate (const struct grub_ieee1275_devalias *alias)
return;
}
- buf = grub_malloc (grub_strlen (alias->path) + 32);
+ if (grub_add (grub_strlen (alias->path), 32, &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while creating buffer for vscsi");
+ grub_ieee1275_close (ihandle);
+ return;
+ }
+
+ buf = grub_malloc (sz);
if (!buf)
return;
bufptr = grub_stpcpy (buf, alias->path);
@@ -289,9 +310,15 @@ dev_iterate (const struct grub_ieee1275_devalias *alias)
grub_uint64_t *table;
grub_uint16_t table_size;
grub_ieee1275_ihandle_t ihandle;
+ grub_size_t sz;
- buf = grub_malloc (grub_strlen (alias->path) +
- sizeof ("/disk@7766554433221100"));
+ if (grub_add (grub_strlen (alias->path), sizeof ("/disk@7766554433221100"), &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while creating buffer for sas_ioa");
+ return;
+ }
+
+ buf = grub_malloc (sz);
if (!buf)
return;
bufptr = grub_stpcpy (buf, alias->path);
@@ -431,9 +458,17 @@ grub_ofdisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
static char *
compute_dev_path (const char *name)
{
- char *devpath = grub_malloc (grub_strlen (name) + 3);
+ char *devpath;
char *p, c;
+ grub_size_t sz;
+ if (grub_add (grub_strlen (name), 3, &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining size of device path"));
+ return NULL;
+ }
+
+ devpath = grub_malloc (sz);
if (!devpath)
return NULL;
@@ -660,6 +695,7 @@ insert_bootpath (void)
char *bootpath;
grub_ssize_t bootpath_size;
char *type;
+ grub_size_t sz;
if (grub_ieee1275_get_property_length (grub_ieee1275_chosen, "bootpath",
&bootpath_size)
@@ -670,7 +706,13 @@ insert_bootpath (void)
return;
}
- bootpath = (char *) grub_malloc ((grub_size_t) bootpath_size + 64);
+ if (grub_add (bootpath_size, 64, &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining bootpath size"));
+ return;
+ }
+
+ bootpath = (char *) grub_malloc (sz);
if (! bootpath)
{
grub_print_error ();
diff --git a/grub-core/disk/ldm.c b/grub-core/disk/ldm.c
index 4577a51..1726607 100644
--- a/grub-core/disk/ldm.c
+++ b/grub-core/disk/ldm.c
@@ -220,6 +220,7 @@ make_vg (grub_disk_t disk,
struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE
/ sizeof (struct grub_ldm_vblk)];
unsigned i;
+ grub_size_t sz;
err = grub_disk_read (disk, cursec, 0,
sizeof(vblk), &vblk);
if (err)
@@ -251,7 +252,13 @@ make_vg (grub_disk_t disk,
grub_free (pv);
goto fail2;
}
- pv->internal_id = grub_malloc (ptr[0] + 2);
+ if (grub_add (ptr[0], 2, &sz))
+ {
+ grub_free (pv);
+ goto fail2;
+ }
+
+ pv->internal_id = grub_malloc (sz);
if (!pv->internal_id)
{
grub_free (pv);
@@ -276,7 +283,15 @@ make_vg (grub_disk_t disk,
goto fail2;
}
pv->id.uuidlen = *ptr;
- pv->id.uuid = grub_malloc (pv->id.uuidlen + 1);
+
+ if (grub_add (pv->id.uuidlen, 1, &sz))
+ {
+ grub_free (pv->internal_id);
+ grub_free (pv);
+ goto fail2;
+ }
+
+ pv->id.uuid = grub_malloc (sz);
grub_memcpy (pv->id.uuid, ptr + 1, pv->id.uuidlen);
pv->id.uuid[pv->id.uuidlen] = 0;
@@ -343,7 +358,13 @@ make_vg (grub_disk_t disk,
grub_free (lv);
goto fail2;
}
- lv->internal_id = grub_malloc ((grub_size_t) ptr[0] + 2);
+ if (grub_add (ptr[0], 2, &sz))
+ {
+ grub_free (lv->segments);
+ grub_free (lv);
+ goto fail2;
+ }
+ lv->internal_id = grub_malloc (sz);
if (!lv->internal_id)
{
grub_free (lv);
@@ -455,6 +476,7 @@ make_vg (grub_disk_t disk,
struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE
/ sizeof (struct grub_ldm_vblk)];
unsigned i;
+ grub_size_t sz;
err = grub_disk_read (disk, cursec, 0,
sizeof(vblk), &vblk);
if (err)
@@ -489,7 +511,12 @@ make_vg (grub_disk_t disk,
{
goto fail2;
}
- comp->internal_id = grub_malloc ((grub_size_t) ptr[0] + 2);
+ if (grub_add (ptr[0], 2, &sz))
+ {
+ grub_free (comp);
+ goto fail2;
+ }
+ comp->internal_id = grub_malloc (sz);
if (!comp->internal_id)
{
grub_free (comp);
@@ -639,7 +666,6 @@ make_vg (grub_disk_t disk,
if (lv->segments->node_alloc == lv->segments->node_count)
{
void *t;
- grub_size_t sz;
if (grub_mul (lv->segments->node_alloc, 2, &lv->segments->node_alloc) ||
grub_mul (lv->segments->node_alloc, sizeof (*lv->segments->nodes), &sz))
diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c
index ac3ab09..50f0e69 100644
--- a/grub-core/disk/luks2.c
+++ b/grub-core/disk/luks2.c
@@ -26,6 +26,7 @@
#include <grub/crypto.h>
#include <grub/partition.h>
#include <grub/i18n.h>
+#include <grub/safemath.h>
#include <base64.h>
#include <json.h>
@@ -549,6 +550,7 @@ luks2_recover_key (grub_disk_t source,
gcry_err_code_t gcry_ret;
grub_json_t *json = NULL, keyslots;
grub_err_t ret;
+ grub_size_t sz;
if (cargs->key_data == NULL || cargs->key_len == 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "no key data");
@@ -557,7 +559,10 @@ luks2_recover_key (grub_disk_t source,
if (ret)
return ret;
- json_header = grub_zalloc (grub_be_to_cpu64 (header.hdr_size) - sizeof (header));
+ if (grub_sub (grub_be_to_cpu64 (header.hdr_size), sizeof (header), &sz))
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "underflow detected while calculating json header size");
+
+ json_header = grub_zalloc (sz);
if (!json_header)
return GRUB_ERR_OUT_OF_MEMORY;
diff --git a/grub-core/disk/memdisk.c b/grub-core/disk/memdisk.c
index 613779c..36de3bf 100644
--- a/grub-core/disk/memdisk.c
+++ b/grub-core/disk/memdisk.c
@@ -23,6 +23,7 @@
#include <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 47e6480..21ec407 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 8257159b3..99f5e7cc6 100644
--- a/grub-core/disk/lvm.c
+++ b/grub-core/disk/lvm.c
@@ -671,8 +671,7 @@ grub_lvm_detect (grub_disk_t disk,
goto lvs_segment_fail;
}
- seg->nodes = grub_zalloc (sizeof (seg->nodes[0])
- * seg->node_count);
+ seg->nodes = grub_calloc (seg->node_count, sizeof (seg->nodes[0]));
p = grub_strstr (p, "mirrors = [");
if (p == NULL)
@@ -760,8 +759,7 @@ grub_lvm_detect (grub_disk_t disk,
}
}
- seg->nodes = grub_zalloc (sizeof (seg->nodes[0])
- * seg->node_count);
+ seg->nodes = grub_calloc (seg->node_count, sizeof (seg->nodes[0]));
p = grub_strstr (p, "raids = [");
if (p == NULL)

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 3620a282e..8bc3ab7f3 100644
--- a/grub-core/disk/ata.c
+++ b/grub-core/disk/ata.c
@@ -112,10 +112,10 @@ grub_ata_identify (struct grub_ata *dev)
return grub_atapi_identify (dev);
info64 = grub_malloc (GRUB_DISK_SECTOR_SIZE);
+ if (info64 == NULL)
+ return grub_errno;
info32 = (grub_uint32_t *) info64;
info16 = (grub_uint16_t *) info64;
- if (! info16)
- return grub_errno;
grub_memset (&parms, 0, sizeof (parms));
parms.buffer = info16;
diff --git a/grub-core/disk/ieee1275/obdisk.c b/grub-core/disk/ieee1275/obdisk.c
index 8e4bbf11c..c72086072 100644
--- a/grub-core/disk/ieee1275/obdisk.c
+++ b/grub-core/disk/ieee1275/obdisk.c
@@ -423,6 +423,12 @@ canonicalise_disk (const char *devname)
}
real_canon = grub_malloc (real_unit_str_len);
+ if (real_canon == NULL)
+ {
+ grub_free (parent);
+ grub_print_error ();
+ return NULL;
+ }
grub_snprintf (real_canon, real_unit_str_len, "%s/disk@%s",
op->name, real_unit_address);
diff --git a/grub-core/disk/ldm.c b/grub-core/disk/ldm.c
index 172660710..246eee3d6 100644
--- a/grub-core/disk/ldm.c
+++ b/grub-core/disk/ldm.c
@@ -292,6 +292,12 @@ make_vg (grub_disk_t disk,
}
pv->id.uuid = grub_malloc (sz);
+ if (pv->id.uuid == NULL)
+ {
+ grub_free (pv->internal_id);
+ grub_free (pv);
+ goto fail2;
+ }
grub_memcpy (pv->id.uuid, ptr + 1, pv->id.uuidlen);
pv->id.uuid[pv->id.uuidlen] = 0;
diff --git a/grub-core/disk/lvm.c b/grub-core/disk/lvm.c
index 99f5e7cc6..4ddb81526 100644
--- a/grub-core/disk/lvm.c
+++ b/grub-core/disk/lvm.c
@@ -370,6 +370,8 @@ grub_lvm_detect (grub_disk_t disk,
break;
pv = grub_zalloc (sizeof (*pv));
+ if (pv == NULL)
+ goto fail4;
q = p;
while (*q != ' ' && q < mda_end)
q++;
@@ -379,6 +381,8 @@ grub_lvm_detect (grub_disk_t disk,
s = q - p;
pv->name = grub_malloc (s + 1);
+ if (pv->name == NULL)
+ goto pvs_fail_noname;
grub_memcpy (pv->name, p, s);
pv->name[s] = '\0';
@@ -451,6 +455,8 @@ grub_lvm_detect (grub_disk_t disk,
break;
lv = grub_zalloc (sizeof (*lv));
+ if (lv == NULL)
+ goto fail4;
q = p;
while (*q != ' ' && q < mda_end)
@@ -545,6 +551,8 @@ grub_lvm_detect (grub_disk_t disk,
goto lvs_fail;
}
lv->segments = grub_calloc (lv->segment_count, sizeof (*seg));
+ if (lv->segments == NULL)
+ goto lvs_fail;
seg = lv->segments;
for (i = 0; i < lv->segment_count; i++)
@@ -612,6 +620,8 @@ grub_lvm_detect (grub_disk_t disk,
seg->nodes = grub_calloc (seg->node_count,
sizeof (*stripe));
+ if (seg->nodes == NULL)
+ goto lvs_segment_fail;
stripe = seg->nodes;
p = grub_strstr (p, "stripes = [");
@@ -672,6 +682,8 @@ grub_lvm_detect (grub_disk_t disk,
}
seg->nodes = grub_calloc (seg->node_count, sizeof (seg->nodes[0]));
+ if (seg->nodes == NULL)
+ goto lvs_segment_fail;
p = grub_strstr (p, "mirrors = [");
if (p == NULL)
@@ -760,6 +772,8 @@ grub_lvm_detect (grub_disk_t disk,
}
seg->nodes = grub_calloc (seg->node_count, sizeof (seg->nodes[0]));
+ if (seg->nodes == NULL)
+ goto lvs_segment_fail;
p = grub_strstr (p, "raids = [");
if (p == NULL)
diff --git a/grub-core/disk/memdisk.c b/grub-core/disk/memdisk.c
index 36de3bfab..2d7afaea3 100644
--- a/grub-core/disk/memdisk.c
+++ b/grub-core/disk/memdisk.c
@@ -103,6 +103,8 @@ GRUB_MOD_INIT(memdisk)
return;
}
memdisk_addr = grub_malloc (memdisk_size);
+ if (memdisk_addr == NULL)
+ return;
grub_dprintf ("memdisk", "Copying memdisk image to dynamic memory\n");
grub_memmove (memdisk_addr, memdisk_orig_addr, memdisk_size);

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 209996390..abb5082cd 100644
--- a/grub-core/disk/ieee1275/ofdisk.c
+++ b/grub-core/disk/ieee1275/ofdisk.c
@@ -268,7 +268,10 @@ dev_iterate (const struct grub_ieee1275_devalias *alias)
buf = grub_malloc (sz);
if (!buf)
- return;
+ {
+ grub_ieee1275_close (ihandle);
+ return;
+ }
bufptr = grub_stpcpy (buf, alias->path);
for (i = 0; i < args.nentries; i++)

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 0cf544f6f..6491f74f9 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 3ed37a4db..0d45f09d3 100644
--- a/grub-core/fs/btrfs.c
+++ b/grub-core/fs/btrfs.c
@@ -1999,6 +1999,7 @@ find_path (struct grub_btrfs_data *data,
char *origpath = NULL;
unsigned symlinks_max = 32;
const char *relpath = grub_env_get ("btrfs_relative_path");
+ grub_size_t sz;
follow_default = 0;
origpath = grub_strdup (path);
@@ -2125,9 +2126,15 @@ find_path (struct grub_btrfs_data *data,
struct grub_btrfs_dir_item *cdirel;
if (elemsize > allocated)
{
- allocated = 2 * elemsize;
+ if (grub_mul (2, elemsize, &allocated) ||
+ grub_add (allocated, 1, &sz))
+ {
+ grub_free (path_alloc);
+ grub_free (origpath);
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("directory item size overflow"));
+ }
grub_free (direl);
- direl = grub_malloc (allocated + 1);
+ direl = grub_malloc (sz);
if (!direl)
{
grub_free (path_alloc);
@@ -2191,8 +2198,16 @@ find_path (struct grub_btrfs_data *data,
grub_free (origpath);
return err;
}
- tmp = grub_malloc (grub_le_to_cpu64 (inode.size)
- + grub_strlen (path) + 1);
+
+ if (grub_add (grub_le_to_cpu64 (inode.size), grub_strlen (path), &sz) ||
+ grub_add (sz, 1, &sz))
+ {
+ grub_free (direl);
+ grub_free (path_alloc);
+ grub_free (origpath);
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("buffer size overflow"));
+ }
+ tmp = grub_malloc (sz);
if (!tmp)
{
grub_free (direl);
@@ -2334,6 +2349,7 @@ grub_btrfs_dir (grub_device_t device, const char *path,
grub_uint8_t type;
char *new_path = NULL;
grub_size_t est_size = 0;
+ grub_size_t sz;
if (!data)
return grub_errno;
@@ -2383,9 +2399,15 @@ grub_btrfs_dir (grub_device_t device, const char *path,
}
if (elemsize > allocated)
{
- allocated = 2 * elemsize;
+ if (grub_mul (2, elemsize, &allocated) ||
+ grub_add (allocated, 1, &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("directory element size overflow"));
+ r = -grub_errno;
+ break;
+ }
grub_free (direl);
- direl = grub_malloc (allocated + 1);
+ direl = grub_malloc (sz);
if (!direl)
{
r = -grub_errno;
diff --git a/grub-core/fs/cpio_common.c b/grub-core/fs/cpio_common.c
index 4e885d623..ce49aa0b1 100644
--- a/grub-core/fs/cpio_common.c
+++ b/grub-core/fs/cpio_common.c
@@ -24,6 +24,7 @@
#include <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 e5dcbc470..a3182a3e5 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 3cd97d337..4bf95c85d 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 ccfa3eea5..0ee9bb2e8 100644
--- a/grub-core/fs/squash4.c
+++ b/grub-core/fs/squash4.c
@@ -460,11 +460,11 @@ grub_squash_read_symlink (grub_fshelp_node_t node)
{
char *ret;
grub_err_t err;
- grub_size_t sz;
+ grub_uint32_t sz;
if (grub_add (grub_le_to_cpu32 (node->ino.symlink.namelen), 1, &sz))
{
- grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected"));
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("symlink name length overflow"));
return NULL;
}
@@ -577,6 +577,7 @@ grub_squash_iterate_dir (grub_fshelp_node_t dir,
struct grub_squash_dirent di;
struct grub_squash_inode ino;
grub_size_t sz;
+ grub_uint16_t nlen;
err = read_chunk (dir->data, &di, sizeof (di),
grub_le_to_cpu64 (dir->data->sb.diroffset)
@@ -592,7 +593,12 @@ grub_squash_iterate_dir (grub_fshelp_node_t dir,
if (err)
return 0;
- buf = grub_malloc (grub_le_to_cpu16 (di.namelen) + 2);
+ if (grub_add (grub_le_to_cpu16 (di.namelen), 2, &nlen))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("name length overflow"));
+ return 0;
+ }
+ buf = grub_malloc (nlen);
if (!buf)
return 0;
err = read_chunk (dir->data, buf,
diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c
index 7b0ea577e..ff6fe3d83 100644
--- a/grub-core/fs/xfs.c
+++ b/grub-core/fs/xfs.c
@@ -676,6 +676,7 @@ static char *
grub_xfs_read_symlink (grub_fshelp_node_t node)
{
grub_ssize_t size = grub_be_to_cpu64 (node->inode.size);
+ grub_size_t sz;
if (size < 0)
{
@@ -697,7 +698,12 @@ grub_xfs_read_symlink (grub_fshelp_node_t node)
if (node->data->hascrc)
off = 56;
- symlink = grub_malloc (size + 1);
+ if (grub_add (size, 1, &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("symlink size overflow"));
+ return 0;
+ }
+ symlink = grub_malloc (sz);
if (!symlink)
return 0;
@@ -747,8 +753,15 @@ static int iterate_dir_call_hook (grub_uint64_t ino, const char *filename,
{
struct grub_fshelp_node *fdiro;
grub_err_t err;
+ grub_size_t sz;
- fdiro = grub_malloc (grub_xfs_fshelp_size(ctx->diro->data) + 1);
+ if (grub_add (grub_xfs_fshelp_size(ctx->diro->data), 1, &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("directory data size overflow"));
+ grub_print_error ();
+ return 0;
+ }
+ fdiro = grub_malloc (sz);
if (!fdiro)
{
grub_print_error ();

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 0d45f09d3..4a4a8f243 100644
--- a/grub-core/fs/btrfs.c
+++ b/grub-core/fs/btrfs.c
@@ -1409,8 +1409,8 @@ grub_btrfs_mount (grub_device_t dev)
}
data->n_devices_allocated = 16;
- data->devices_attached = grub_malloc (sizeof (data->devices_attached[0])
- * data->n_devices_allocated);
+ data->devices_attached = grub_calloc (data->n_devices_allocated,
+ sizeof (data->devices_attached[0]));
if (!data->devices_attached)
{
grub_free (data);
diff --git a/grub-core/fs/hfspluscomp.c b/grub-core/fs/hfspluscomp.c
index d76f3f137..4965ef19a 100644
--- a/grub-core/fs/hfspluscomp.c
+++ b/grub-core/fs/hfspluscomp.c
@@ -244,14 +244,19 @@ hfsplus_open_compressed_real (struct grub_hfsplus_file *node)
return 0;
}
node->compress_index_size = grub_le_to_cpu32 (index_size);
- node->compress_index = grub_malloc (node->compress_index_size
- * sizeof (node->compress_index[0]));
+ node->compress_index = grub_calloc (node->compress_index_size,
+ sizeof (node->compress_index[0]));
if (!node->compress_index)
{
node->compressed = 0;
grub_free (attr_node);
return grub_errno;
}
+
+ /*
+ * The node->compress_index_size * sizeof (node->compress_index[0]) is safe here
+ * due to relevant checks done in grub_calloc() above.
+ */
if (grub_hfsplus_read_file (node, 0, 0,
0x104 + sizeof (index_size),
node->compress_index_size
diff --git a/grub-core/fs/squash4.c b/grub-core/fs/squash4.c
index 0ee9bb2e8..5239cdd5c 100644
--- a/grub-core/fs/squash4.c
+++ b/grub-core/fs/squash4.c
@@ -810,10 +810,10 @@ direct_read (struct grub_squash_data *data,
break;
}
total_blocks = ((total_size + data->blksz - 1) >> data->log2_blksz);
- ino->block_sizes = grub_malloc (total_blocks
- * sizeof (ino->block_sizes[0]));
- ino->cumulated_block_sizes = grub_malloc (total_blocks
- * sizeof (ino->cumulated_block_sizes[0]));
+ ino->block_sizes = grub_calloc (total_blocks,
+ sizeof (ino->block_sizes[0]));
+ ino->cumulated_block_sizes = grub_calloc (total_blocks,
+ sizeof (ino->cumulated_block_sizes[0]));
if (!ino->block_sizes || !ino->cumulated_block_sizes)
{
grub_free (ino->block_sizes);

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 ce49aa0b1..e6c51a6af 100644
--- a/grub-core/fs/cpio_common.c
+++ b/grub-core/fs/cpio_common.c
@@ -62,11 +62,21 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name,
#endif
)
return grub_error (GRUB_ERR_BAD_FS, "invalid cpio archive");
- data->size = read_number (hd.filesize, ARRAY_SIZE (hd.filesize));
+
+ if (grub_cast (read_number (hd.filesize, ARRAY_SIZE (hd.filesize)), &data->size))
+ return grub_error (GRUB_ERR_BAD_FS, N_("data size overflow"));
+
if (mtime)
- *mtime = read_number (hd.mtime, ARRAY_SIZE (hd.mtime));
- modeval = read_number (hd.mode, ARRAY_SIZE (hd.mode));
- namesize = read_number (hd.namesize, ARRAY_SIZE (hd.namesize));
+ {
+ if (grub_cast (read_number (hd.mtime, ARRAY_SIZE (hd.mtime)), mtime))
+ return grub_error (GRUB_ERR_BAD_FS, N_("mtime overflow"));
+ }
+
+ if (grub_cast (read_number (hd.mode, ARRAY_SIZE (hd.mode)), &modeval))
+ return grub_error (GRUB_ERR_BAD_FS, N_("mode overflow"));
+
+ if (grub_cast (read_number (hd.namesize, ARRAY_SIZE (hd.namesize)), &namesize))
+ return grub_error (GRUB_ERR_BAD_FS, N_("namesize overflow"));
/* Don't allow negative numbers. */
if (namesize >= 0x80000000)
diff --git a/grub-core/fs/tar.c b/grub-core/fs/tar.c
index fd2ec1f74..1eaa5349f 100644
--- a/grub-core/fs/tar.c
+++ b/grub-core/fs/tar.c
@@ -99,9 +99,10 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name,
if (hd.typeflag == 'L')
{
grub_err_t err;
- grub_size_t namesize = read_number (hd.size, sizeof (hd.size));
+ grub_size_t namesize;
- if (grub_add (namesize, 1, &sz))
+ if (grub_cast (read_number (hd.size, sizeof (hd.size)), &namesize) ||
+ grub_add (namesize, 1, &sz))
return grub_error (GRUB_ERR_BAD_FS, N_("name size overflow"));
*name = grub_malloc (sz);
@@ -123,9 +124,10 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name,
if (hd.typeflag == 'K')
{
grub_err_t err;
- grub_size_t linksize = read_number (hd.size, sizeof (hd.size));
+ grub_size_t linksize;
- if (grub_add (linksize, 1, &sz))
+ if (grub_cast (read_number (hd.size, sizeof (hd.size)), &linksize) ||
+ grub_add (linksize, 1, &sz))
return grub_error (GRUB_ERR_BAD_FS, N_("link size overflow"));
if (data->linkname_alloc < sz)
@@ -174,15 +176,22 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name,
(*name)[extra_size + sizeof (hd.name)] = 0;
}
- data->size = read_number (hd.size, sizeof (hd.size));
+ if (grub_cast (read_number (hd.size, sizeof (hd.size)), &data->size))
+ return grub_error (GRUB_ERR_BAD_FS, N_("data size overflow"));
+
data->dofs = data->hofs + GRUB_DISK_SECTOR_SIZE;
data->next_hofs = data->dofs + ((data->size + GRUB_DISK_SECTOR_SIZE - 1) &
~(GRUB_DISK_SECTOR_SIZE - 1));
if (mtime)
- *mtime = read_number (hd.mtime, sizeof (hd.mtime));
+ {
+ if (grub_cast (read_number (hd.mtime, sizeof (hd.mtime)), mtime))
+ return grub_error (GRUB_ERR_BAD_FS, N_("mtime overflow"));
+ }
if (mode)
{
- *mode = read_number (hd.mode, sizeof (hd.mode));
+ if (grub_cast (read_number (hd.mode, sizeof (hd.mode)), mode))
+ return grub_error (GRUB_ERR_BAD_FS, N_("mode overflow"));
+
switch (hd.typeflag)
{
/* Hardlink. */

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 cbbd86730..b52d293f2 100644
--- a/grub-core/fs/zfs/zfs.c
+++ b/grub-core/fs/zfs/zfs.c
@@ -2383,6 +2383,7 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
zap_dnode->endian) << DNODE_SHIFT);
grub_err_t err;
grub_zfs_endian_t endian;
+ grub_size_t sz;
if (zap_verify (zap, zap_dnode->endian))
return 0;
@@ -2444,8 +2445,14 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
if (le->le_type != ZAP_CHUNK_ENTRY)
continue;
- buf = grub_malloc (grub_zfs_to_cpu16 (le->le_name_length, endian)
- * name_elem_length + 1);
+ if (grub_mul (grub_zfs_to_cpu16 (le->le_name_length, endian), name_elem_length, &sz) ||
+ grub_add (sz, 1, &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("buffer size overflow"));
+ grub_free (l);
+ return grub_errno;
+ }
+ buf = grub_malloc (sz);
if (zap_leaf_array_get (l, endian, blksft,
grub_zfs_to_cpu16 (le->le_name_chunk,
endian),
@@ -2866,6 +2873,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
&& ((grub_zfs_to_cpu64(((znode_phys_t *) DN_BONUS (&dnode_path->dn.dn))->zp_mode, dnode_path->dn.endian) >> 12) & 0xf) == 0xa)
{
char *sym_value;
+ grub_size_t sz;
grub_size_t sym_sz;
int free_symval = 0;
char *oldpath = path, *oldpathbuf = path_buf;
@@ -2917,7 +2925,18 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
break;
free_symval = 1;
}
- path = path_buf = grub_malloc (sym_sz + grub_strlen (oldpath) + 1);
+
+ if (grub_add (sym_sz, grub_strlen (oldpath), &sz) ||
+ grub_add (sz, 1, &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("path buffer size overflow"));
+ grub_free (oldpathbuf);
+ if (free_symval)
+ grub_free (sym_value);
+ err = grub_errno;
+ break;
+ }
+ path = path_buf = grub_malloc (sz);
if (!path_buf)
{
grub_free (oldpathbuf);
@@ -2951,6 +2970,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
{
void *sahdrp;
int hdrsize;
+ grub_size_t sz;
if (dnode_path->dn.dn.dn_bonuslen != 0)
{
@@ -2984,7 +3004,15 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
+ SA_SIZE_OFFSET),
dnode_path->dn.endian);
char *oldpath = path, *oldpathbuf = path_buf;
- path = path_buf = grub_malloc (sym_sz + grub_strlen (oldpath) + 1);
+ if (grub_add (sym_sz, grub_strlen (oldpath), &sz) ||
+ grub_add (sz, 1, &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("path buffer size overflow"));
+ grub_free (oldpathbuf);
+ err = grub_errno;
+ break;
+ }
+ path = path_buf = grub_malloc (sz);
if (!path_buf)
{
grub_free (oldpathbuf);
@@ -3553,6 +3581,7 @@ grub_zfs_nvlist_lookup_nvlist_array (const char *nvlist, const char *name,
unsigned i;
grub_size_t nelm;
int elemsize = 0;
+ int sz;
found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST_ARRAY, &nvpair,
&size, &nelm);
@@ -3587,7 +3616,12 @@ grub_zfs_nvlist_lookup_nvlist_array (const char *nvlist, const char *name,
return 0;
}
- ret = grub_zalloc (elemsize + sizeof (grub_uint32_t));
+ if (grub_add (elemsize, sizeof (grub_uint32_t), &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("elemsize overflow"));
+ return 0;
+ }
+ ret = grub_zalloc (sz);
if (!ret)
return 0;
grub_memcpy (ret, nvlist, sizeof (grub_uint32_t));
@@ -4166,6 +4200,7 @@ iterate_zap_snap (const char *name, grub_uint64_t val,
struct grub_dirhook_info info;
char *name2;
int ret;
+ grub_size_t sz;
dnode_end_t mdn;
@@ -4186,7 +4221,10 @@ iterate_zap_snap (const char *name, grub_uint64_t val,
return 0;
}
- name2 = grub_malloc (grub_strlen (name) + 2);
+ if (grub_add (grub_strlen (name), 2, &sz))
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("name length overflow"));
+
+ name2 = grub_malloc (sz);
name2[0] = '@';
grub_memcpy (name2 + 1, name, grub_strlen (name) + 1);
ret = ctx->hook (name2, &info, ctx->hook_data);

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 b52d293f2..913046ba9 100644
--- a/grub-core/fs/zfs/zfs.c
+++ b/grub-core/fs/zfs/zfs.c
@@ -721,8 +721,8 @@ fill_vdev_info_real (struct grub_zfs_data *data,
{
fill->n_children = nelm;
- fill->children = grub_zalloc (fill->n_children
- * sizeof (fill->children[0]));
+ fill->children = grub_calloc (fill->n_children,
+ sizeof (fill->children[0]));
}
for (i = 0; i < nelm; i++)
@@ -3697,8 +3697,8 @@ zfs_mount (grub_device_t dev)
#endif
data->n_devices_allocated = 16;
- data->devices_attached = grub_malloc (sizeof (data->devices_attached[0])
- * data->n_devices_allocated);
+ data->devices_attached = grub_calloc (data->n_devices_allocated,
+ sizeof (data->devices_attached[0]));
data->n_devices_attached = 0;
err = scan_disk (dev, data, 1, &inserted);
if (err)

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 913046ba9..9123b5682 100644
--- a/grub-core/fs/zfs/zfs.c
+++ b/grub-core/fs/zfs/zfs.c
@@ -612,6 +612,8 @@ zfs_fetch_nvlist (struct grub_zfs_device_desc *diskdesc, char **nvlist)
return grub_error (GRUB_ERR_BUG, "member drive unknown");
*nvlist = grub_malloc (VDEV_PHYS_SIZE);
+ if (!*nvlist)
+ return grub_errno;
/* Read in the vdev name-value pair list (112K). */
err = grub_disk_read (diskdesc->dev->disk, diskdesc->vdev_phys_sector, 0,
@@ -723,6 +725,11 @@ fill_vdev_info_real (struct grub_zfs_data *data,
fill->children = grub_calloc (fill->n_children,
sizeof (fill->children[0]));
+ if (!fill->children)
+ {
+ grub_free (type);
+ return grub_errno;
+ }
}
for (i = 0; i < nelm; i++)
@@ -2453,6 +2460,11 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
return grub_errno;
}
buf = grub_malloc (sz);
+ if (!buf)
+ {
+ grub_free (l);
+ return grub_errno;
+ }
if (zap_leaf_array_get (l, endian, blksft,
grub_zfs_to_cpu16 (le->le_name_chunk,
endian),
@@ -2468,6 +2480,12 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
val_length = ((int) le->le_value_length
* (int) le->le_int_size);
val = grub_malloc (grub_zfs_to_cpu16 (val_length, endian));
+ if (!val)
+ {
+ grub_free (l);
+ grub_free (buf);
+ return grub_errno;
+ }
if (zap_leaf_array_get (l, endian, blksft,
grub_zfs_to_cpu16 (le->le_value_chunk,
endian),
@@ -3699,6 +3717,11 @@ zfs_mount (grub_device_t dev)
data->n_devices_allocated = 16;
data->devices_attached = grub_calloc (data->n_devices_allocated,
sizeof (data->devices_attached[0]));
+ if (!data->devices_attached)
+ {
+ grub_free (data);
+ return NULL;
+ }
data->n_devices_attached = 0;
err = scan_disk (dev, data, 1, &inserted);
if (err)
@@ -4225,6 +4248,9 @@ iterate_zap_snap (const char *name, grub_uint64_t val,
return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("name length overflow"));
name2 = grub_malloc (sz);
+ if (!name2)
+ return grub_errno;
+
name2[0] = '@';
grub_memcpy (name2 + 1, name, grub_strlen (name) + 1);
ret = ctx->hook (name2, &info, ctx->hook_data);

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 9123b5682..da014b123 100644
--- a/grub-core/fs/zfs/zfs.c
+++ b/grub-core/fs/zfs/zfs.c
@@ -3297,6 +3297,8 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
filename = 0;
snapname = 0;
fsname = grub_strdup (fullpath);
+ if (!fsname)
+ return grub_errno;
}
else
{

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 | 44 +++++++++++++++++++++++++++-------
4 files changed, 76 insertions(+), 13 deletions(-)
diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c
index 7baf3540c..f00d4a9ad 100644
--- a/grub-core/net/bootp.c
+++ b/grub-core/net/bootp.c
@@ -27,6 +27,7 @@
#include <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)
@@ -1476,6 +1477,7 @@ grub_cmd_dhcpopt (struct grub_command *cmd __attribute__ ((unused)),
unsigned num;
const grub_uint8_t *ptr;
grub_uint8_t taglength;
+ grub_uint8_t len;
if (argc < 4)
return grub_error (GRUB_ERR_BAD_ARGUMENT,
@@ -1517,7 +1519,12 @@ grub_cmd_dhcpopt (struct grub_command *cmd __attribute__ ((unused)),
if (grub_strcmp (args[3], "string") == 0)
{
grub_err_t err = GRUB_ERR_NONE;
- char *val = grub_malloc (taglength + 1);
+ char *val;
+
+ if (grub_add (taglength, 1, &len))
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("tag length overflow"));
+
+ val = grub_malloc (len);
if (!val)
return grub_errno;
grub_memcpy (val, ptr, taglength);
@@ -1550,7 +1557,12 @@ grub_cmd_dhcpopt (struct grub_command *cmd __attribute__ ((unused)),
if (grub_strcmp (args[3], "hex") == 0)
{
grub_err_t err = GRUB_ERR_NONE;
- char *val = grub_malloc (2 * taglength + 1);
+ char *val;
+
+ if (grub_mul (taglength, 2, &len) || grub_add (len, 1, &len))
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("tag length overflow"));
+
+ val = grub_malloc (len);
int i;
if (!val)
return grub_errno;
diff --git a/grub-core/net/dns.c b/grub-core/net/dns.c
index 17961a9f1..64b48a31c 100644
--- a/grub-core/net/dns.c
+++ b/grub-core/net/dns.c
@@ -224,10 +224,17 @@ get_name (const grub_uint8_t *name_at, const grub_uint8_t *head,
{
int length;
char *ret;
+ int len;
if (!check_name_real (name_at, head, tail, NULL, &length, NULL))
return NULL;
- ret = grub_malloc (length + 1);
+
+ if (grub_add (length, 1, &len))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("name length overflow"));
+ return NULL;
+ }
+ ret = grub_malloc (len);
if (!ret)
return NULL;
if (!check_name_real (name_at, head, tail, NULL, NULL, ret))
diff --git a/grub-core/net/drivers/ieee1275/ofnet.c b/grub-core/net/drivers/ieee1275/ofnet.c
index bcb3f9ea0..650114806 100644
--- a/grub-core/net/drivers/ieee1275/ofnet.c
+++ b/grub-core/net/drivers/ieee1275/ofnet.c
@@ -22,6 +22,7 @@
#include <grub/net.h>
#include <grub/time.h>
#include <grub/i18n.h>
+#include <grub/safemath.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -404,6 +405,7 @@ search_net_devices (struct grub_ieee1275_devalias *alias)
grub_uint8_t *pprop;
char *shortname;
char need_suffix = 1;
+ grub_size_t sz;
if (grub_strcmp (alias->type, "network") != 0)
return 0;
@@ -461,9 +463,23 @@ search_net_devices (struct grub_ieee1275_devalias *alias)
}
if (need_suffix)
- ofdata->path = grub_malloc (grub_strlen (alias->path) + sizeof (SUFFIX));
+ {
+ if (grub_add (grub_strlen (alias->path), sizeof (SUFFIX), &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obatining size of ofdata path"));
+ grub_print_error ();
+ return 0;
+ }
+ }
else
- ofdata->path = grub_malloc (grub_strlen (alias->path) + 1);
+ {
+ if (grub_add (grub_strlen (alias->path), 1, &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obatining size of ofdata path"));
+ grub_print_error ();
+ return 0;
+ }
+ }
if (!ofdata->path)
{
grub_print_error ();
diff --git a/grub-core/net/net.c b/grub-core/net/net.c
index 6c0bd00b4..9826328ca 100644
--- a/grub-core/net/net.c
+++ b/grub-core/net/net.c
@@ -32,6 +32,7 @@
#include <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);
@@ -306,9 +316,14 @@ grub_net_ipv6_get_link_local (struct grub_net_card *card,
return inf;
}
- name = grub_malloc (grub_strlen (card->name)
- + GRUB_NET_MAX_STR_HWADDR_LEN
- + sizeof (":link"));
+ if (grub_add (grub_strlen (card->name),
+ (GRUB_NET_MAX_STR_HWADDR_LEN + sizeof (":link")), &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE,
+ "overflow detected while obtaining size of link name");
+ return NULL;
+ }
+ name = grub_malloc (sz);
if (!name)
return NULL;
@@ -1461,8 +1476,15 @@ grub_net_open_real (const char *name)
if (grub_strchr (port_start + 1, ':'))
{
int iplen = grub_strlen (server);
+ grub_size_t sz;
+
/* bracket bare ipv6 addrs */
- host = grub_malloc (iplen + 3);
+ if (grub_add (iplen, 3, &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining length of host"));
+ return NULL;
+ }
+ host = grub_malloc (sz);
if(!host)
{
return NULL;
@@ -1722,6 +1744,7 @@ grub_env_set_net_property (const char *intername, const char *suffix,
{
char *varname, *varvalue;
char *ptr;
+ grub_size_t sz;
varname = grub_xasprintf ("net_%s_%s", intername, suffix);
if (!varname)
@@ -1729,7 +1752,12 @@ grub_env_set_net_property (const char *intername, const char *suffix,
for (ptr = varname; *ptr; ptr++)
if (*ptr == ':')
*ptr = '_';
- varvalue = grub_malloc (len + 1);
+ if (grub_add (len, 1, &sz))
+ {
+ grub_free (varname);
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while obtaining the size of an env variable");
+ }
+ varvalue = grub_malloc (sz);
if (!varvalue)
{
grub_free (varname);

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 64b48a31c..aafd92902 100644
--- a/grub-core/net/dns.c
+++ b/grub-core/net/dns.c
@@ -494,8 +494,8 @@ grub_net_dns_lookup (const char *name,
&& grub_get_time_ms () < dns_cache[h].limit_time)
{
grub_dprintf ("dns", "retrieved from cache\n");
- *addresses = grub_malloc (dns_cache[h].naddresses
- * sizeof ((*addresses)[0]));
+ *addresses = grub_calloc (dns_cache[h].naddresses,
+ sizeof ((*addresses)[0]));
if (!*addresses)
return grub_errno;
*naddresses = dns_cache[h].naddresses;
diff --git a/grub-core/net/net.c b/grub-core/net/net.c
index 9826328ca..a17392abb 100644
--- a/grub-core/net/net.c
+++ b/grub-core/net/net.c
@@ -91,8 +91,8 @@ grub_net_link_layer_add_address (struct grub_net_card *card,
/* Add sender to cache table. */
if (card->link_layer_table == NULL)
{
- card->link_layer_table = grub_zalloc (LINK_LAYER_CACHE_SIZE
- * sizeof (card->link_layer_table[0]));
+ card->link_layer_table = grub_calloc (LINK_LAYER_CACHE_SIZE,
+ sizeof (card->link_layer_table[0]));
if (card->link_layer_table == NULL)
return;
}

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 a17392abb..4bfe03d53 100644
--- a/grub-core/net/net.c
+++ b/grub-core/net/net.c
@@ -232,6 +232,11 @@ grub_net_ipv6_get_slaac (struct grub_net_card *card,
}
slaac->name = grub_malloc (sz);
+ if (slaac->name == NULL)
+ {
+ grub_free (slaac);
+ return NULL;
+ }
ptr = grub_stpcpy (slaac->name, card->name);
if (grub_net_hwaddr_cmp (&card->default_address, hwaddr) != 0)
{

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 c383eb87c..89fdaa101 100644
--- a/grub-core/script/execute.c
+++ b/grub-core/script/execute.c
@@ -794,6 +794,9 @@ cleanup:
}
}
+ if (result.args == NULL || result.argc == 0)
+ goto fail;
+
if (! result.args[result.argc - 1])
result.argc--;

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 f0c503f43..893527a95 100644
--- a/grub-core/osdep/linux/getroot.c
+++ b/grub-core/osdep/linux/getroot.c
@@ -599,6 +599,9 @@ again:
}
}
+ if (!entry_len)
+ goto out;
+
/* Now scan visible mounts for the ones we're interested in. */
for (i = entry_len - 1; i >= 0; i--)
{

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 96f038c54..7ebcaf063 100644
--- a/grub-core/fs/ntfs.c
+++ b/grub-core/fs/ntfs.c
@@ -574,7 +574,7 @@ retry:
goto retry;
}
}
- return grub_error (GRUB_ERR_BAD_FS, "run list overflown");
+ return grub_error (GRUB_ERR_BAD_FS, "run list overflow");
}
ctx->curr_vcn = ctx->next_vcn;
ctx->next_vcn += read_run_data (run, c1, 0); /* length of current VCN */
diff --git a/grub-core/fs/ntfscomp.c b/grub-core/fs/ntfscomp.c
index 4bf95c85d..88594702e 100644
--- a/grub-core/fs/ntfscomp.c
+++ b/grub-core/fs/ntfscomp.c
@@ -30,7 +30,7 @@ static grub_err_t
decomp_nextvcn (struct grub_ntfs_comp *cc)
{
if (cc->comp_head >= cc->comp_tail)
- return grub_error (GRUB_ERR_BAD_FS, "compression block overflown");
+ return grub_error (GRUB_ERR_BAD_FS, "compression block overflow");
if (grub_disk_read
(cc->disk,
(cc->comp_table[cc->comp_head].next_lcn -
diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c
index 7f2ba7849..3ff215dd6 100644
--- a/grub-core/video/readers/png.c
+++ b/grub-core/video/readers/png.c
@@ -622,7 +622,7 @@ static grub_err_t
grub_png_output_byte (struct grub_png_data *data, grub_uint8_t n)
{
if (--data->raw_bytes < 0)
- return grub_error (GRUB_ERR_BAD_FILE_TYPE, "image size overflown");
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "image size overflow");
if (data->cur_column == 0)
{

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 d966fc210..d1e8a01ca 100644
--- a/grub-core/bus/usb/ehci.c
+++ b/grub-core/bus/usb/ehci.c
@@ -218,7 +218,7 @@ enum
#define GRUB_EHCI_TERMINATE (1<<0)
-#define GRUB_EHCI_TOGGLE (1<<31)
+#define GRUB_EHCI_TOGGLE ((grub_uint32_t) 1<<31)
enum
{

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 c8516a5a0..9a6033109 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 f3f125e75..144a7b6a6 100644
--- a/grub-core/kern/partition.c
+++ b/grub-core/kern/partition.c
@@ -125,14 +125,22 @@ grub_partition_probe (struct grub_disk *disk, const char *str)
for (ptr = str; *ptr;)
{
grub_partition_map_t partmap;
- int num;
+ unsigned long num;
const char *partname, *partname_end;
partname = ptr;
while (*ptr && grub_isalpha (*ptr))
ptr++;
partname_end = ptr;
- num = grub_strtoul (ptr, &ptr, 0) - 1;
+
+ num = grub_strtoul (ptr, &ptr, 0);
+ if (*ptr != '\0' || num == 0 || num > GRUB_INT_MAX)
+ {
+ grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid partition number"));
+ return 0;
+ }
+
+ num -= 1;
curpart = 0;
/* Use the first partition map type found. */

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 50af9ee1b..da2f6e551 100644
--- a/grub-core/kern/misc.c
+++ b/grub-core/kern/misc.c
@@ -858,7 +858,7 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args,
while ((c = *fmt++) != 0)
{
int longfmt = 0;
- grub_size_t curn;
+ unsigned long curn;
const char *p;
if (c != '%')
@@ -876,7 +876,10 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args,
if (*fmt == '$')
{
- curn = grub_strtoull (p, 0, 10) - 1;
+ curn = grub_strtoul (p, 0, 10);
+ if (curn == 0)
+ continue;
+ curn--;
fmt++;
}
@@ -1035,6 +1038,8 @@ grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt0,
if (*fmt == '$')
{
+ if (format1 == 0)
+ continue;
curn = format1 - 1;
fmt++;
format1 = 0;

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 3c1ff6476..9d4c57619 100644
--- a/grub-core/loader/i386/linux.c
+++ b/grub-core/loader/i386/linux.c
@@ -811,7 +811,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W, GRUB_MEM_ATTR_X);
linux_params.code32_start = prot_mode_target + lh.code32_start - GRUB_LINUX_BZIMAGE_ADDR;
- linux_params.kernel_alignment = (1 << align);
+ linux_params.kernel_alignment = ((grub_uint32_t)1 << align);
linux_params.ps_mouse = linux_params.padding11 = 0;
linux_params.type_of_loader = GRUB_LINUX_BOOT_LOADER_TYPE;

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 54befc266..939628f9e 100644
--- a/grub-core/loader/i386/bsd.c
+++ b/grub-core/loader/i386/bsd.c
@@ -1341,6 +1341,7 @@ static grub_err_t
grub_bsd_load_elf (grub_elf_t elf, const char *filename)
{
grub_err_t err;
+ grub_size_t sz;
kern_end = 0;
kern_start = ~0;
@@ -1371,8 +1372,11 @@ grub_bsd_load_elf (grub_elf_t elf, const char *filename)
if (grub_errno)
return grub_errno;
- err = grub_relocator_alloc_chunk_addr (relocator, &ch,
- kern_start, kern_end - kern_start);
+
+ if (grub_sub (kern_end, kern_start, &sz))
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "underflow detected while determining size of kernel for relocator");
+
+ err = grub_relocator_alloc_chunk_addr (relocator, &ch, kern_start, sz);
if (err)
return err;
@@ -1432,8 +1436,10 @@ grub_bsd_load_elf (grub_elf_t elf, const char *filename)
{
grub_relocator_chunk_t ch;
- err = grub_relocator_alloc_chunk_addr (relocator, &ch, kern_start,
- kern_end - kern_start);
+ if (grub_sub (kern_end, kern_start, &sz))
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "underflow detected while determining size of kernel for relocator");
+
+ err = grub_relocator_alloc_chunk_addr (relocator, &ch, kern_start, sz);
if (err)
return err;
kern_chunk_src = get_virtual_current_address (ch);

View File

@ -0,0 +1,78 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Fri, 4 Nov 2022 12:13:34 -0400
Subject: [PATCH] types: Make bool generally available
Add an include on stdbool.h, making the bool type generally available
within the GRUB without needing to add a file-specific include every
time it would be used.
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/commands/parttool.c | 2 +-
grub-core/parttool/msdospart.c | 4 ++--
include/grub/parttool.h | 2 +-
include/grub/types.h | 1 +
4 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/grub-core/commands/parttool.c b/grub-core/commands/parttool.c
index 051e31320..ff45c65e6 100644
--- a/grub-core/commands/parttool.c
+++ b/grub-core/commands/parttool.c
@@ -315,7 +315,7 @@ grub_cmd_parttool (grub_command_t cmd __attribute__ ((unused)),
switch (curarg->type)
{
case GRUB_PARTTOOL_ARG_BOOL:
- pargs[curarg - ptool->args].bool
+ pargs[curarg - ptool->args].b
= (args[j][grub_strlen (curarg->name)] != '-');
break;
diff --git a/grub-core/parttool/msdospart.c b/grub-core/parttool/msdospart.c
index 3918caa06..3a7699e45 100644
--- a/grub-core/parttool/msdospart.c
+++ b/grub-core/parttool/msdospart.c
@@ -61,7 +61,7 @@ static grub_err_t grub_pcpart_boot (const grub_device_t dev,
return grub_errno;
}
- if (args[0].set && args[0].bool)
+ if (args[0].set && args[0].b)
{
for (i = 0; i < 4; i++)
mbr.entries[i].flag = 0x0;
@@ -116,7 +116,7 @@ static grub_err_t grub_pcpart_type (const grub_device_t dev,
if (args[1].set)
{
- if (args[1].bool)
+ if (args[1].b)
type |= GRUB_PC_PARTITION_TYPE_HIDDEN_FLAG;
else
type &= ~GRUB_PC_PARTITION_TYPE_HIDDEN_FLAG;
diff --git a/include/grub/parttool.h b/include/grub/parttool.h
index 4e8f8d5e5..4799a22c5 100644
--- a/include/grub/parttool.h
+++ b/include/grub/parttool.h
@@ -32,7 +32,7 @@ struct grub_parttool_args
int set;
union
{
- int bool;
+ int b;
char *str;
};
};
diff --git a/include/grub/types.h b/include/grub/types.h
index ba446d990..c00842ab0 100644
--- a/include/grub/types.h
+++ b/include/grub/types.h
@@ -20,6 +20,7 @@
#define GRUB_TYPES_HEADER 1
#include <config.h>
+#include <stdbool.h>
#ifndef GRUB_UTIL
#include <grub/cpu/types.h>
#endif

View File

@ -0,0 +1,35 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Glenn Washburn <development@efficientek.com>
Date: Wed, 28 Jun 2023 02:38:23 -0500
Subject: [PATCH] include/grub/types.h: Add PRI*GRUB_OFFSET and
PRI*GRUB_DISK_ADDR
These are currently always the same as PRI*GRUB_UINT64_T, but they may
not be in the future.
Signed-off-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
include/grub/types.h | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/include/grub/types.h b/include/grub/types.h
index c00842a..1587ff4 100644
--- a/include/grub/types.h
+++ b/include/grub/types.h
@@ -181,10 +181,13 @@ typedef grub_uint64_t grub_properly_aligned_t;
#define GRUB_PROPERLY_ALIGNED_ARRAY(name, size) grub_properly_aligned_t name[((size) + sizeof (grub_properly_aligned_t) - 1) / sizeof (grub_properly_aligned_t)]
/* The type for representing a file offset. */
-typedef grub_uint64_t grub_off_t;
+typedef grub_uint64_t grub_off_t;
+#define PRIxGRUB_OFFSET PRIxGRUB_UINT64_T
+#define PRIuGRUB_OFFSET PRIuGRUB_UINT64_T
/* The type for representing a disk block address. */
-typedef grub_uint64_t grub_disk_addr_t;
+typedef grub_uint64_t grub_disk_addr_t;
+#define PRIxGRUB_DISK_ADDR PRIxGRUB_UINT64_T
/* Byte-orders. */
static inline grub_uint16_t grub_swap_bytes16(grub_uint16_t _x)

View File

@ -0,0 +1,106 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Darren Kenny <darren.kenny@oracle.com>
Date: Fri, 2 Jun 2023 18:08:44 +0000
Subject: [PATCH] fs/xfs: Fix issues found while fuzzing the XFS filesystem
While performing fuzz testing with XFS filesystem images with ASAN
enabled, several issues were found where the memory accesses are made
beyond the data that is allocated into the struct grub_xfs_data
structure's data field.
The existing structure didn't store the size of the memory allocated into
the buffer in the data field and had no way to check it. To resolve these
issues, the data size is stored to enable checks into the data buffer.
With these checks in place, the fuzzing corpus no longer cause any crashes.
Signed-off-by: Darren Kenny <darren.kenny@oracle.com>
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
Signed-off-by: Marta Lewandowska <mlewando@redhat.com>
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/xfs.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c
index ff6fe3d..cc50feb 100644
--- a/grub-core/fs/xfs.c
+++ b/grub-core/fs/xfs.c
@@ -239,6 +239,7 @@ struct grub_fshelp_node
struct grub_xfs_data
{
+ grub_size_t data_size;
struct grub_xfs_sblock sblock;
grub_disk_t disk;
int pos;
@@ -621,8 +622,20 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
}
else if (node->inode.format == XFS_INODE_FORMAT_EXT)
{
+ grub_addr_t exts_end = 0;
+ grub_addr_t data_end = 0;
+
nrec = grub_be_to_cpu32 (node->inode.nextents);
exts = (struct grub_xfs_extent *) grub_xfs_inode_data(&node->inode);
+
+ if (grub_mul (sizeof (struct grub_xfs_extent), nrec, &exts_end) ||
+ grub_add ((grub_addr_t) node->data, exts_end, &exts_end) ||
+ grub_add ((grub_addr_t) node->data, node->data->data_size, &data_end) ||
+ exts_end > data_end)
+ {
+ grub_error (GRUB_ERR_BAD_FS, "invalid number of XFS extents");
+ return 0;
+ }
}
else
{
@@ -825,6 +838,9 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
grub_uint8_t *inopos = grub_xfs_inline_de_inopos(dir->data, de);
grub_uint8_t c;
+ if ((inopos + (smallino ? 4 : 8)) > (grub_uint8_t *) dir + grub_xfs_fshelp_size (dir->data))
+ return grub_error (GRUB_ERR_BAD_FS, "not a correct XFS inode");
+
/* inopos might be unaligned. */
if (smallino)
ino = (((grub_uint32_t) inopos[0]) << 24)
@@ -851,6 +867,10 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
de->name[de->len] = c;
de = grub_xfs_inline_next_de(dir->data, head, de);
+
+ if ((grub_uint8_t *) de >= (grub_uint8_t *) dir + grub_xfs_fshelp_size (dir->data))
+ return grub_error (GRUB_ERR_BAD_FS, "invalid XFS directory entry");
+
}
break;
}
@@ -916,6 +936,9 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
}
filename = (char *)(direntry + 1);
+ if (filename + direntry->len - 1 > (char *) tail)
+ return grub_error (GRUB_ERR_BAD_FS, "invalid XFS directory entry");
+
/* The byte after the filename is for the filetype, padding, or
tag, which is not used by GRUB. So it can be overwritten. */
filename[direntry->len] = '\0';
@@ -960,6 +983,8 @@ grub_xfs_mount (grub_disk_t disk)
if (!data)
return 0;
+ data->data_size = sizeof (struct grub_xfs_data);
+
grub_dprintf("xfs", "Reading sb\n");
/* Read the superblock. */
if (grub_disk_read (disk, 0, 0,
@@ -981,6 +1006,7 @@ grub_xfs_mount (grub_disk_t disk)
if (! data)
goto fail;
+ data->data_size = sz;
data->diropen.data = data;
data->diropen.ino = grub_be_to_cpu64(data->sblock.rootino);
data->diropen.inode_read = 1;

View File

@ -352,3 +352,102 @@ Patch0351: 0351-arm64-Use-proper-memory-type-for-kernel-allocation.patch
Patch0352: 0352-cmd-search-Fix-a-possible-NULL-ptr-dereference.patch
Patch0353: 0353-10_linux.in-escape-semicolon-and-ampersand-on-BLS-up.patch
Patch0354: 0354-kern-ieee1275-init-Add-IEEE-1275-Radix-support-for-K.patch
Patch0355: 0355-misc-Implement-grub_strlcpy.patch
Patch0356: 0356-fs-ufs-Fix-a-heap-OOB-write.patch
Patch0357: 0357-fs-hfs-Fix-stack-OOB-write-with-grub_strcpy.patch
Patch0358: 0358-fs-tar-Initialize-name-in-grub_cpio_find_file.patch
Patch0359: 0359-fs-tar-Integer-overflow-leads-to-heap-OOB-write.patch
Patch0360: 0360-fs-f2fs-Set-a-grub_errno-if-mount-fails.patch
Patch0361: 0361-fs-hfsplus-Set-a-grub_errno-if-mount-fails.patch
Patch0362: 0362-fs-iso9660-Set-a-grub_errno-if-mount-fails.patch
Patch0363: 0363-fs-iso9660-Fix-invalid-free.patch
Patch0364: 0364-fs-jfs-Fix-OOB-read-in-jfs_getent.patch
Patch0365: 0365-fs-jfs-Fix-OOB-read-caused-by-invalid-dir-slot-index.patch
Patch0366: 0366-fs-jfs-Use-full-40-bits-offset-and-address-for-a-dat.patch
Patch0367: 0367-fs-jfs-Inconsistent-signed-unsigned-types-usage-in-r.patch
Patch0368: 0368-fs-ext2-Fix-out-of-bounds-read-for-inline-extents.patch
Patch0369: 0369-fs-ntfs-Fix-out-of-bounds-read.patch
Patch0370: 0370-fs-ntfs-Track-the-end-of-the-MFT-attribute-buffer.patch
Patch0371: 0371-fs-ntfs-Use-a-helper-function-to-access-attributes.patch
Patch0372: 0372-fs-ntfs-Implement-attribute-verification.patch
Patch0373: 0373-fs-xfs-Fix-out-of-bounds-read.patch
Patch0374: 0374-fs-xfs-Ensuring-failing-to-mount-sets-a-grub_errno.patch
Patch0375: 0375-kern-file-Ensure-file-data-is-set.patch
Patch0376: 0376-kern-file-Implement-filesystem-reference-counting.patch
Patch0377: 0377-cli_lock-Add-build-option-to-block-command-line-inte.patch
Patch0378: 0378-cryptodisk-Refactor-to-discard-have_it-global.patch
Patch0379: 0379-cryptodisk-Return-failure-in-cryptomount-when-no-cry.patch
Patch0380: 0380-cryptodisk-Improve-error-messaging-in-cryptomount-in.patch
Patch0381: 0381-cryptodisk-Improve-cryptomount-u-error-message.patch
Patch0382: 0382-cryptodisk-Add-infrastructure-to-pass-data-from-cryp.patch
Patch0383: 0383-cryptodisk-Refactor-password-input-out-of-crypto-dev.patch
Patch0384: 0384-luks2-Add-debug-message-to-align-with-luks-and-geli-.patch
Patch0385: 0385-cryptodisk-Move-global-variables-into-grub_cryptomou.patch
Patch0386: 0386-cryptodisk-Improve-handling-of-partition-name-in-cry.patch
Patch0387: 0387-cryptodisk-Fix-Coverity-use-after-free-bug.patch
Patch0388: 0388-disk-cryptodisk-Add-options-to-cryptomount-to-suppor.patch
Patch0389: 0389-disk-cryptodisk-Use-enum-constants-as-indexes-into-c.patch
Patch0390: 0390-cryptodisk-Add-support-for-using-detached-header-fil.patch
Patch0391: 0391-disk-cryptodisk-Support-encrypted-volumes-using-deta.patch
Patch0392: 0392-disk-cryptodisk-Allows-UUIDs-to-be-compared-in-a-das.patch
Patch0393: 0393-disk-cryptodisk-Fix-unintentional-integer-overflow.patch
Patch0394: 0394-disk-cryptodisk-When-cheatmounting-use-the-sector-in.patch
Patch0395: 0395-disk-cryptodisk-Fix-missing-change-when-updating-to-.patch
Patch0396: 0396-disk-cryptodisk-Optimize-luks_script_get.patch
Patch0397: 0397-disk-cryptodisk-Add-support-for-LUKS2-in-proc-luks_s.patch
Patch0398: 0398-disk-cryptodisk-Require-authentication-after-TPM-unl.patch
Patch0399: 0399-disk-loopback-Reference-tracking-for-the-loopback.patch
Patch0400: 0400-kern-disk-Limit-recursion-depth.patch
Patch0401: 0401-kern-partition-Limit-recursion-in-part_iterate.patch
Patch0402: 0402-script-execute-Limit-the-recursion-depth.patch
Patch0403: 0403-net-Unregister-net_default_ip-and-net_default_mac-va.patch
Patch0404: 0404-net-Remove-variables-hooks-when-interface-is-unregis.patch
Patch0405: 0405-net-Fix-OOB-write-in-grub_net_search_config_file.patch
Patch0406: 0406-net-tftp-Fix-stack-buffer-overflow-in-tftp_open.patch
Patch0407: 0407-video-readers-jpeg-Do-not-permit-duplicate-SOF0-mark.patch
Patch0408: 0408-kern-dl-Fix-for-an-integer-overflow-in-grub_dl_ref.patch
Patch0409: 0409-kern-dl-Check-for-the-SHF_INFO_LINK-flag-in-grub_dl_.patch
Patch0410: 0410-commands-extcmd-Missing-check-for-failed-allocation.patch
Patch0411: 0411-commands-ls-Fix-NULL-dereference.patch
Patch0412: 0412-commands-pgp-Unregister-the-check_signatures-hooks-o.patch
Patch0413: 0413-normal-Remove-variables-hooks-on-module-unload.patch
Patch0414: 0414-gettext-Remove-variables-hooks-on-module-unload.patch
Patch0415: 0415-gettext-Integer-overflow-leads-to-heap-OOB-write-or-.patch
Patch0416: 0416-gettext-Integer-overflow-leads-to-heap-OOB-write.patch
Patch0417: 0417-commands-read-Add-silent-mode-to-read-command-to-sup.patch
Patch0418: 0418-commands-read-Fix-overflow-in-grub_getline.patch
Patch0419: 0419-commands-read-Fix-an-integer-overflow-when-supplying.patch
Patch0420: 0420-commands-test-Stack-overflow-due-to-unlimited-recurs.patch
Patch0421: 0421-commands-minicmd-Block-the-dump-command-in-lockdown-.patch
Patch0422: 0422-commands-memrw-Disable-memory-reading-in-lockdown-mo.patch
Patch0423: 0423-commands-hexdump-Disable-memory-reading-in-lockdown-.patch
Patch0424: 0424-fs-bfs-Disable-under-lockdown.patch
Patch0425: 0425-fs-Disable-many-filesystems-under-lockdown.patch
Patch0426: 0426-disk-plainmount-Support-plain-encryption-mode.patch
Patch0427: 0427-disk-Use-safe-math-macros-to-prevent-overflows.patch
Patch0428: 0428-disk-Prevent-overflows-when-allocating-memory-for-ar.patch
Patch0429: 0429-disk-Check-if-returned-pointer-for-allocated-memory-.patch
Patch0430: 0430-disk-ieee1275-ofdisk-Call-grub_ieee1275_close-when-g.patch
Patch0431: 0431-fs-Use-safe-math-macros-to-prevent-overflows.patch
Patch0432: 0432-fs-Prevent-overflows-when-allocating-memory-for-arra.patch
Patch0433: 0433-fs-Prevent-overflows-when-assigning-returned-values-.patch
Patch0434: 0434-fs-zfs-Use-safe-math-macros-to-prevent-overflows.patch
Patch0435: 0435-fs-zfs-Prevent-overflows-when-allocating-memory-for-.patch
Patch0436: 0436-fs-zfs-Check-if-returned-pointer-for-allocated-memor.patch
Patch0437: 0437-fs-zfs-Add-missing-NULL-check-after-grub_strdup-call.patch
Patch0438: 0438-net-Use-safe-math-macros-to-prevent-overflows.patch
Patch0439: 0439-net-Prevent-overflows-when-allocating-memory-for-arr.patch
Patch0440: 0440-net-Check-if-returned-pointer-for-allocated-memory-i.patch
Patch0441: 0441-fs-sfs-Check-if-allocated-memory-is-NULL.patch
Patch0442: 0442-script-execute-Fix-potential-underflow-and-NULL-dere.patch
Patch0443: 0443-osdep-unix-getroot-Fix-potential-underflow.patch
Patch0444: 0444-misc-Ensure-consistent-overflow-error-messages.patch
Patch0445: 0445-bus-usb-ehci-Define-GRUB_EHCI_TOGGLE-as-grub_uint32_.patch
Patch0446: 0446-normal-menu-Use-safe-math-to-avoid-an-integer-overfl.patch
Patch0447: 0447-kern-partition-Add-sanity-check-after-grub_strtoul-c.patch
Patch0448: 0448-kern-misc-Add-sanity-check-after-grub_strtoul-call.patch
Patch0449: 0449-loader-i386-linux-Cast-left-shift-to-grub_uint32_t.patch
Patch0450: 0450-loader-i386-bsd-Use-safe-math-to-avoid-underflow.patch
Patch0451: 0451-types-Make-bool-generally-available.patch
Patch0452: 0452-include-grub-types.h-Add-PRI-GRUB_OFFSET-and-PRI-GRU.patch
Patch0453: 0453-fs-xfs-Fix-issues-found-while-fuzzing-the-XFS-filesy.patch

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