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>
This commit is contained in:
Lidong Chen authored and Daniel Kiper committed 2025-01-23 16:22:46 +01:00
1 parent 1443833a95
commit 66175696f3
1 file changed
+15 -2
+15 -2
View File
@@ -41,6 +41,12 @@ GRUB_MOD_LICENSE ("GPLv3+");
#define GRUB_JFS_TREE_LEAF 2 #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 struct grub_jfs_sblock
{ {
/* The magic for JFS. It should contain the string "JFS1". */ /* 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 freecnt;
grub_uint8_t freelist; grub_uint8_t freelist;
grub_uint32_t idotdot; grub_uint32_t idotdot;
grub_uint8_t sorted[8]; grub_uint8_t sorted[GRUB_JFS_INODE_INLINE_ENTRIES];
} header; } header;
struct grub_jfs_leaf_dirent dirents[8]; struct grub_jfs_leaf_dirent dirents[GRUB_JFS_INODE_INLINE_ENTRIES];
} GRUB_PACKED dir; } GRUB_PACKED dir;
/* Fast symlink. */ /* Fast symlink. */
struct 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. */ /* Check if the entire tree is contained within the inode. */
if (inode->file.tree.flags & GRUB_JFS_TREE_LEAF) 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->leaf = inode->dir.dirents;
diro->next_leaf = (struct grub_jfs_leaf_next_dirent *) de; diro->next_leaf = (struct grub_jfs_leaf_next_dirent *) de;
diro->sorted = inode->dir.header.sorted; diro->sorted = inode->dir.header.sorted;