From 66175696f3a385b14bdf1ebcda7755834bd2d5fb 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 10/73] 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 62e20ef6f..e2fe2850c 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;
-- 
2.33.0

