[PATCH 4/4] efi: Fix use-after-free in finish boot services

2023-05-22 Thread Alec Brown
In grub-core/kern/efi/mm.c, grub_efi_finish_boot_services() has an instance
where the memory for the variable finish_mmap_buf is freed, but on the next
iteration of a while loop, grub_efi_get_memory_map() uses finish_mmap_buf. To
prevent this, we can set finish_mmap_buf to NULL after the free.

Signed-off-by: Alec Brown 
---
 grub-core/kern/efi/mm.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
index 3705b8b1b..c74ccbb05 100644
--- a/grub-core/kern/efi/mm.c
+++ b/grub-core/kern/efi/mm.c
@@ -263,6 +263,7 @@ grub_efi_finish_boot_services (grub_efi_uintn_t 
*outbuf_size, void *outbuf,
   &finish_desc_size, &finish_desc_version) <= 
0)
{
  grub_free (finish_mmap_buf);
+ finish_mmap_buf = NULL;
  return grub_error (GRUB_ERR_IO, "couldn't retrieve memory map");
}
 
@@ -275,10 +276,12 @@ grub_efi_finish_boot_services (grub_efi_uintn_t 
*outbuf_size, void *outbuf,
   if (status != GRUB_EFI_INVALID_PARAMETER)
{
  grub_free (finish_mmap_buf);
+ finish_mmap_buf = NULL;
  return grub_error (GRUB_ERR_IO, "couldn't terminate EFI services");
}
 
   grub_free (finish_mmap_buf);
+  finish_mmap_buf = NULL;
   grub_printf ("Trying to terminate EFI services again\n");
 }
   grub_efi_is_finished = 1;
-- 
2.27.0


___
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel


[PATCH 3/4] elf: check program header offset doesn't exceed constraints

2023-05-22 Thread Alec Brown
In grub-core/loader/multiboot_elfxx.c, we need to make sure that the program
header offset is less than the file size along with the MULTIBOOT_SEARCH
constant. We can do so by setting the variable phlimit to the minimum value of
the two limits and check it each time we change program header index to insure
that the program header offset isn't outside of the limits.

Fixes: CID 314029
Fixes: CID 314038

Signed-off-by: Alec Brown 
---
 grub-core/loader/multiboot_elfxx.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/grub-core/loader/multiboot_elfxx.c 
b/grub-core/loader/multiboot_elfxx.c
index 52eaf9184..72b376cd5 100644
--- a/grub-core/loader/multiboot_elfxx.c
+++ b/grub-core/loader/multiboot_elfxx.c
@@ -70,6 +70,7 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld)
   grub_uint32_t load_offset = 0, load_size = 0;
   Elf_Shnum shnum;
   Elf_Word shstrndx, phnum;
+  grub_off_t phlimit;
   unsigned int i;
   void *source = NULL;
 
@@ -100,7 +101,8 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld)
 return err;
 
   /* FIXME: Should we support program headers at strange locations?  */
-  if (ehdr->e_phoff + phnum * ehdr->e_phentsize > MULTIBOOT_SEARCH)
+  phlimit = grub_min (MULTIBOOT_SEARCH, grub_file_size (mld->file));
+  if ((grub_off_t) ehdr->e_phoff + phnum * ehdr->e_phentsize > phlimit)
 return grub_error (GRUB_ERR_BAD_OS, "program header at a too high offset");
 
   phdr_base = (char *) mld->buffer + ehdr->e_phoff;
-- 
2.27.0


___
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel


[PATCH 1/4] elf: Check program memory isn't larger than allocated memory size

2023-05-22 Thread Alec Brown
In grub-core/loader/multiboot_elfxx.c, the code is filling an area of memory
with grub_memset() but doesn't check if there is space in the allocated memory
before doing so. To make sure we aren't zeroing memory past the allocated memory
region, we need to check that the offset into the allocated memory region plus
the memory size of the program is smaller than the allocated memory size.

Fixes: CID 314029
Fixes: CID 314038

Signed-off-by: Alec Brown 
---
 grub-core/loader/multiboot_elfxx.c | 15 +++
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/grub-core/loader/multiboot_elfxx.c 
b/grub-core/loader/multiboot_elfxx.c
index e067d2d84..69f567588 100644
--- a/grub-core/loader/multiboot_elfxx.c
+++ b/grub-core/loader/multiboot_elfxx.c
@@ -67,7 +67,7 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld)
   char *phdr_base;
   grub_err_t err;
   grub_relocator_chunk_t ch;
-  grub_uint32_t load_offset = 0, load_size;
+  grub_uint32_t load_offset = 0, load_size = 0;
   Elf_Shnum shnum;
   Elf_Word shstrndx, phnum;
   unsigned int i;
@@ -170,8 +170,9 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld)
}
  else
{
+ load_size = phdr(i)->p_memsz;
  err = grub_relocator_alloc_chunk_addr (GRUB_MULTIBOOT 
(relocator), &ch,
-phdr(i)->p_paddr, 
phdr(i)->p_memsz);
+phdr(i)->p_paddr, 
load_size);
 
  if (err != GRUB_ERR_NONE)
{
@@ -199,8 +200,14 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld)
}
 
   if (phdr(i)->p_filesz < phdr(i)->p_memsz)
-grub_memset ((grub_uint8_t *) source + load_offset + 
phdr(i)->p_filesz, 0,
-phdr(i)->p_memsz - phdr(i)->p_filesz);
+   {
+ /* Need to insure that the memory being set isn't larger than the 
allocated memory*/
+ if (load_offset + phdr(i)->p_memsz - phdr(i)->p_filesz > 
load_size)
+   return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("memory being set 
is larger than allocated memory"));
+
+  grub_memset ((grub_uint8_t *) source + load_offset + 
phdr(i)->p_filesz, 0,
+  phdr(i)->p_memsz - phdr(i)->p_filesz);
+   }
 }
 }
 
-- 
2.27.0


___
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel


[PATCH 2/4] elf: Check section header region before allocating memory

2023-05-22 Thread Alec Brown
In grub-core/loader/multiboot_elfxx.c, space is being allocated for the section
header region, but isn't verifying if the region is within the file's size.
Before calling grub_calloc(), we can add a conditional to check if the section
header region is smaller than the file size.

Fixes: CID 314029
Fixes: CID 314038

Signed-off-by: Alec Brown 
---
 grub-core/loader/multiboot_elfxx.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/grub-core/loader/multiboot_elfxx.c 
b/grub-core/loader/multiboot_elfxx.c
index 69f567588..52eaf9184 100644
--- a/grub-core/loader/multiboot_elfxx.c
+++ b/grub-core/loader/multiboot_elfxx.c
@@ -248,6 +248,9 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld)
 {
   grub_uint8_t *shdr, *shdrptr;
 
+  if ((grub_off_t) ehdr->e_shoff + shnum * ehdr->e_shentsize > 
grub_file_size (mld->file))
+   return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("ELF section header region 
is larger than the file size"));
+
   shdr = grub_calloc (shnum, ehdr->e_shentsize);
   if (!shdr)
return grub_errno;
-- 
2.27.0


___
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel


[PATCH 0/4] Address coverity untrusted loop bound bugs in multiboot_elfxx.c

2023-05-22 Thread Alec Brown
Coverity has listed two untrusted loop bound bugs in
grub-core/loader/multiboot_elfxx.c. They are CID 314029 and CID 314038. After
testing the first patch, the CID changed to an untrusted loop bound for line
244: shdr = grub_calloc (shnum, ehdr->e_shentsize);. I added a second patch to
address this, but after making these changes, it reverted to the original bug of
using tainted data in grub_memset(). The third patch addresses Coverity's issue
with phdr() in grub_memset() and reduces the bug to only having an issue with
using phnum as an untrusted loop bound. However, we can ignore this since phnum
is already getting checked earlier in the function.

I've also bundled a use-after-free patch with this patch set at the end.

Alec Brown (4):
  elf: Check program memory isn't larger than allocated memory size
  elf: Check section header region before allocating memory
  elf: check program header offset doesn't exceed constraints
  efi: Fix use-after-free in finish boot services

 grub-core/kern/efi/mm.c|  3 +++
 grub-core/loader/multiboot_elfxx.c | 22 +-
 2 files changed, 20 insertions(+), 5 deletions(-)



___
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel


[PATCH 1/1] xfs: Fix issues found while fuzzing the XFS filesystem

2023-05-22 Thread Lidong Chen
From: Darren Kenny 

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 stucture didn't store the size of the memory allocted 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 accesses into the data
buffer.

With these checks in place, the fuzzing corpus no longer cause any
crashes.

Signed-off-by: Darren Kenny 
Signed-off-by: Robbie Harwood 
Signed-off-by: Marta Lewandowska 
Signed-off-by: Lidong Chen 
---
 grub-core/fs/xfs.c | 32 
 1 file changed, 32 insertions(+)

diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c
index d6de7f1a2..a0aaa3aa8 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 datasize;
   struct grub_xfs_sblock sblock;
   grub_disk_t disk;
   int pos;
@@ -608,8 +609,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->datasize, &data_end) ||
+ exts_end > data_end)
+{
+ grub_error (GRUB_ERR_BAD_FS, "Invalid number of XFS exts");
+ return 0;
+}
 }
   else
 {
@@ -799,6 +812,12 @@ 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)
@@ -825,6 +844,12 @@ 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;
   }
@@ -890,6 +915,10 @@ 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';
@@ -934,6 +963,8 @@ grub_xfs_mount (grub_disk_t disk)
   if (!data)
 return 0;
 
+  data->datasize = sizeof (struct grub_xfs_data);
+
   grub_dprintf("xfs", "Reading sb\n");
   /* Read the superblock.  */
   if (grub_disk_read (disk, 0, 0,
@@ -955,6 +986,7 @@ grub_xfs_mount (grub_disk_t disk)
   if (! data)
 goto fail;
 
+  data->datasize = sz;
   data->diropen.data = data;
   data->diropen.ino = grub_be_to_cpu64(data->sblock.rootino);
   data->diropen.inode_read = 1;
-- 
2.39.1


___
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel