From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Maxim Suhanov Date: Mon, 28 Aug 2023 16:31:57 +0300 Subject: [PATCH] fs/ntfs: Fix an OOB write when parsing the $ATTRIBUTE_LIST attribute for the $MFT file When parsing an extremely fragmented $MFT file, i.e., the file described using the $ATTRIBUTE_LIST attribute, current NTFS code will reuse a buffer containing bytes read from the underlying drive to store sector numbers, which are consumed later to read data from these sectors into another buffer. These sectors numbers, two 32-bit integers, are always stored at predefined offsets, 0x10 and 0x14, relative to first byte of the selected entry within the $ATTRIBUTE_LIST attribute. Usually, this won't cause any problem. However, when parsing a specially-crafted file system image, this may cause the NTFS code to write these integers beyond the buffer boundary, likely causing the GRUB memory allocator to misbehave or fail. These integers contain values which are controlled by on-disk structures of the NTFS file system. Such modification and resulting misbehavior may touch a memory range not assigned to the GRUB and owned by firmware or another EFI application/driver. This fix introduces checks to ensure that these sector numbers are never written beyond the boundary. Fixes: CVE-2023-4692 Reported-by: Maxim Suhanov Signed-off-by: Maxim Suhanov Reviewed-by: Daniel Kiper --- grub-core/fs/ntfs.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c index 3511e4e2cb6f..4681c7ac32a8 100644 --- a/grub-core/fs/ntfs.c +++ b/grub-core/fs/ntfs.c @@ -184,7 +184,7 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) } if (at->attr_end) { - grub_uint8_t *pa; + grub_uint8_t *pa, *pa_end; at->emft_buf = grub_malloc (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR); if (at->emft_buf == NULL) @@ -209,11 +209,13 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) } at->attr_nxt = at->edat_buf; at->attr_end = at->edat_buf + u32at (pa, 0x30); + pa_end = at->edat_buf + n; } else { at->attr_nxt = at->attr_end + u16at (pa, 0x14); at->attr_end = at->attr_end + u32at (pa, 4); + pa_end = at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR); } at->flags |= GRUB_NTFS_AF_ALST; while (at->attr_nxt < at->attr_end) @@ -230,6 +232,13 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) at->flags |= GRUB_NTFS_AF_GPOS; at->attr_cur = at->attr_nxt; pa = at->attr_cur; + + if ((pa >= pa_end) || (pa_end - pa < 0x18)) + { + grub_error (GRUB_ERR_BAD_FS, "can\'t parse attribute list"); + return NULL; + } + grub_set_unaligned32 ((char *) pa + 0x10, grub_cpu_to_le32 (at->mft->data->mft_start)); grub_set_unaligned32 ((char *) pa + 0x14, @@ -240,6 +249,13 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) { if (*pa != attr) break; + + if ((pa >= pa_end) || (pa_end - pa < 0x18)) + { + grub_error (GRUB_ERR_BAD_FS, "can\'t parse attribute list"); + return NULL; + } + if (read_attr (at, pa + 0x10, u32at (pa, 0x10) * (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR),