mirror of
https://git.proxmox.com/git/grub2
synced 2025-07-27 06:30:35 +00:00
revert broken NTFS patches
NTFS is disabled with secure boot enabled anyway now, and these patches caused a regression both for grub during boot and grub_mount in userspace. Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
This commit is contained in:
parent
df8135c033
commit
a7a440dc54
@ -1,47 +0,0 @@
|
||||
From: Michael Chang <mchang@suse.com>
|
||||
Date: Mon, 3 Jun 2024 12:12:06 +0800
|
||||
Subject: 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>
|
||||
(cherry picked from commit aff26318783a135562b904ff09e2359893885732)
|
||||
---
|
||||
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 deb058a..976ad1d 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)
|
@ -1,141 +0,0 @@
|
||||
From: B Horn <b@horn.uk>
|
||||
Date: Tue, 7 Jan 2025 11:38:34 +0000
|
||||
Subject: 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>
|
||||
(cherry picked from commit 237a71184a32d1ef7732f5f49ed6a89c5fe1c99a)
|
||||
---
|
||||
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 976ad1d..562b4f7 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 d1a6af6..ec1c4db 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;
|
||||
};
|
||||
|
@ -1,197 +0,0 @@
|
||||
From: B Horn <b@horn.uk>
|
||||
Date: Tue, 14 May 2024 12:39:56 +0100
|
||||
Subject: fs/ntfs: Use a helper function to access attributes
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
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>
|
||||
(cherry picked from commit 048777bc29043403d077d41a81d0183767b8bc71)
|
||||
FG: add missing stdbool.h include statement
|
||||
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
|
||||
---
|
||||
grub-core/fs/ntfs.c | 71 +++++++++++++++++++++++++++++++++++++++++++----------
|
||||
include/grub/ntfs.h | 2 ++
|
||||
2 files changed, 60 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c
|
||||
index 562b4f7..56de4e6 100644
|
||||
--- a/grub-core/fs/ntfs.c
|
||||
+++ b/grub-core/fs/ntfs.c
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
#define grub_fshelp_node grub_ntfs_file
|
||||
|
||||
+#include <stdbool.h>
|
||||
+
|
||||
#include <grub/file.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/misc.h>
|
||||
@@ -70,6 +72,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 +172,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 +202,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 +245,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 +292,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 +320,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 +337,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 +574,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 ec1c4db..2c80784 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,
|
@ -1,245 +0,0 @@
|
||||
From: B Horn <b@horn.uk>
|
||||
Date: Tue, 14 May 2024 12:39:56 +0100
|
||||
Subject: 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>
|
||||
(cherry picked from commit 067b6d225d482280abad03944f04e30abcbdafa1)
|
||||
---
|
||||
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 56de4e6..35e6c30 100644
|
||||
--- a/grub-core/fs/ntfs.c
|
||||
+++ b/grub-core/fs/ntfs.c
|
||||
@@ -72,6 +72,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)
|
||||
@@ -86,6 +229,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;
|
||||
}
|
||||
@@ -292,6 +437,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))
|
||||
@@ -321,6 +469,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)
|
||||
@@ -574,6 +725,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 2c80784..77b182a 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,
|
@ -246,10 +246,10 @@ index 3c248a9..c44583e 100644
|
||||
my_mod = mod;
|
||||
}
|
||||
diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c
|
||||
index 35e6c30..4126c63 100644
|
||||
index deb058a..0ffcc9c 100644
|
||||
--- a/grub-core/fs/ntfs.c
|
||||
+++ b/grub-core/fs/ntfs.c
|
||||
@@ -1539,6 +1539,7 @@ static struct grub_fs grub_ntfs_fs =
|
||||
@@ -1316,6 +1316,7 @@ static struct grub_fs grub_ntfs_fs =
|
||||
|
||||
GRUB_MOD_INIT (ntfs)
|
||||
{
|
||||
|
@ -196,10 +196,10 @@ index c44583e..dd10c08 100644
|
||||
+ grub_fs_unregister (&grub_nilfs2_fs);
|
||||
}
|
||||
diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c
|
||||
index 4126c63..b1884ac 100644
|
||||
index 0ffcc9c..66ea467 100644
|
||||
--- a/grub-core/fs/ntfs.c
|
||||
+++ b/grub-core/fs/ntfs.c
|
||||
@@ -29,6 +29,7 @@
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <grub/fshelp.h>
|
||||
#include <grub/ntfs.h>
|
||||
#include <grub/charset.h>
|
||||
@ -207,7 +207,7 @@ index 4126c63..b1884ac 100644
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
@@ -1539,12 +1540,16 @@ static struct grub_fs grub_ntfs_fs =
|
||||
@@ -1316,12 +1317,16 @@ static struct grub_fs grub_ntfs_fs =
|
||||
|
||||
GRUB_MOD_INIT (ntfs)
|
||||
{
|
||||
|
@ -15,10 +15,10 @@ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
|
||||
3 files changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c
|
||||
index b1884ac..ec99331 100644
|
||||
index 66ea467..542b01e 100644
|
||||
--- a/grub-core/fs/ntfs.c
|
||||
+++ b/grub-core/fs/ntfs.c
|
||||
@@ -576,7 +576,7 @@ retry:
|
||||
@@ -364,7 +364,7 @@ retry:
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
4
debian/patches/series
vendored
4
debian/patches/series
vendored
@ -142,10 +142,6 @@ cve_2025_02_multiple/0141-fs-jfs-Fix-OOB-read-caused-by-invalid-dir-slot-index.p
|
||||
cve_2025_02_multiple/0142-fs-jfs-Use-full-40-bits-offset-and-address-for-a-dat.patch
|
||||
cve_2025_02_multiple/0143-fs-jfs-Inconsistent-signed-unsigned-types-usage-in-r.patch
|
||||
cve_2025_02_multiple/0144-fs-ext2-Fix-out-of-bounds-read-for-inline-extents.patch
|
||||
cve_2025_02_multiple/0145-fs-ntfs-Fix-out-of-bounds-read.patch
|
||||
cve_2025_02_multiple/0146-fs-ntfs-Track-the-end-of-the-MFT-attribute-buffer.patch
|
||||
cve_2025_02_multiple/0147-fs-ntfs-Use-a-helper-function-to-access-attributes.patch
|
||||
cve_2025_02_multiple/0148-fs-ntfs-Implement-attribute-verification.patch
|
||||
cve_2025_02_multiple/0149-fs-xfs-Fix-issues-found-while-fuzzing-the-XFS-filesy.patch
|
||||
cve_2025_02_multiple/0150-fs-xfs-Incorrect-short-form-directory-data-boundary-.patch
|
||||
cve_2025_02_multiple/0151-fs-xfs-Fix-XFS-directory-extent-parsing.patch
|
||||
|
Loading…
Reference in New Issue
Block a user