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