[PATCH] ocfs2: Fix use-after-free in ocfs2_dx_dir_lookup_rec

ssrane_b23@ee.vjti.ac.in posted 1 patch 2 months, 1 week ago
fs/ocfs2/dir.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
[PATCH] ocfs2: Fix use-after-free in ocfs2_dx_dir_lookup_rec
Posted by ssrane_b23@ee.vjti.ac.in 2 months, 1 week ago
From: Shaurya Rane <ssrane_b23@ee.vjti.ac.in>

A syzbot report triggered a KASAN use-after-free read when creating a
file on a corrupted OCFS2 filesystem image.

The crash occurs in an error-handling path within the
ocfs2_dx_dir_lookup_rec function. When the function fails to find a
matching extent record (`found` is false), it attempts to log details
about the corruption by reading from the `rec` variable.

According to the KASAN report, the memory pointed to by `rec` can be
invalid at this point, leading to a kernel crash.

Fix this by modifying the error message to use only variables that are
known to be safe, such as the inode number and the extent block's
buffer head block number. This preserves the valuable error log for
debugging corrupted filesystems while preventing the memory safety
violation.

Reported-by: syzbot+30b53487d00b4f7f0922@syzkaller.appspotmail.com
Tested-by: syzbot+30b53487d00b4f7f0922@syzkaller.appspotmail.com
Signed-off-by: Shaurya Rane <ssrane_b23@ee.vjti.ac.in>
---
 fs/ocfs2/dir.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
index 8c9c4825f984..8c4dd61efa8d 100644
--- a/fs/ocfs2/dir.c
+++ b/fs/ocfs2/dir.c
@@ -820,8 +820,7 @@ static int ocfs2_dx_dir_lookup_rec(struct inode *inode,
 		ret = ocfs2_error(inode->i_sb,
 				  "Inode %lu has bad extent record (%u, %u, 0) in btree\n",
 				  inode->i_ino,
-				  le32_to_cpu(rec->e_cpos),
-				  ocfs2_rec_clusters(el, rec));
+				  eb_bh ? (unsigned long long)eb_bh->b_blocknr : 0);
 		goto out;
 	}
 
-- 
2.34.1
Re: [PATCH] ocfs2: Fix use-after-free in ocfs2_dx_dir_lookup_rec
Posted by kernel test robot 2 months, 1 week ago
Hi,

kernel test robot noticed the following build warnings:

[auto build test WARNING on brauner-vfs/vfs.all]
[also build test WARNING on linus/master v6.17 next-20251009]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/ssrane_b23-ee-vjti-ac-in/ocfs2-Fix-use-after-free-in-ocfs2_dx_dir_lookup_rec/20251009-163456
base:   https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git vfs.all
patch link:    https://lore.kernel.org/r/20251005151403.9012-1-ssranevjti%40gmail.com
patch subject: [PATCH] ocfs2: Fix use-after-free in ocfs2_dx_dir_lookup_rec
config: m68k-allyesconfig (https://download.01.org/0day-ci/archive/20251010/202510100838.uqgonWvJ-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251010/202510100838.uqgonWvJ-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202510100838.uqgonWvJ-lkp@intel.com/

All warnings (new ones prefixed by >>):

   In file included from fs/ocfs2/dir.c:45:
   fs/ocfs2/dir.c: In function 'ocfs2_dx_dir_lookup_rec':
>> fs/ocfs2/dir.c:821:35: warning: format '%u' expects argument of type 'unsigned int', but argument 5 has type 'long long unsigned int' [-Wformat=]
     821 |                                   "Inode %lu has bad extent record (%u, %u, 0) in btree\n",
         |                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     822 |                                   inode->i_ino,
     823 |                                   eb_bh ? (unsigned long long)eb_bh->b_blocknr : 0);
         |                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         |                                                                                |
         |                                                                                long long unsigned int
   fs/ocfs2/super.h:18:48: note: in definition of macro 'ocfs2_error'
      18 |         __ocfs2_error(sb, __PRETTY_FUNCTION__, fmt, ##__VA_ARGS__)
         |                                                ^~~
   fs/ocfs2/dir.c:821:70: note: format string is defined here
     821 |                                   "Inode %lu has bad extent record (%u, %u, 0) in btree\n",
         |                                                                     ~^
         |                                                                      |
         |                                                                      unsigned int
         |                                                                     %llu
>> fs/ocfs2/dir.c:821:35: warning: format '%u' expects a matching 'unsigned int' argument [-Wformat=]
     821 |                                   "Inode %lu has bad extent record (%u, %u, 0) in btree\n",
         |                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   fs/ocfs2/super.h:18:48: note: in definition of macro 'ocfs2_error'
      18 |         __ocfs2_error(sb, __PRETTY_FUNCTION__, fmt, ##__VA_ARGS__)
         |                                                ^~~
   fs/ocfs2/dir.c:821:74: note: format string is defined here
     821 |                                   "Inode %lu has bad extent record (%u, %u, 0) in btree\n",
         |                                                                         ~^
         |                                                                          |
         |                                                                          unsigned int


vim +821 fs/ocfs2/dir.c

316f4b9f98a353a Mark Fasheh       2007-09-07  768  
9b7895efac906d6 Mark Fasheh       2008-11-12  769  static int ocfs2_dx_dir_lookup_rec(struct inode *inode,
9b7895efac906d6 Mark Fasheh       2008-11-12  770  				   struct ocfs2_extent_list *el,
9b7895efac906d6 Mark Fasheh       2008-11-12  771  				   u32 major_hash,
9b7895efac906d6 Mark Fasheh       2008-11-12  772  				   u32 *ret_cpos,
9b7895efac906d6 Mark Fasheh       2008-11-12  773  				   u64 *ret_phys_blkno,
9b7895efac906d6 Mark Fasheh       2008-11-12  774  				   unsigned int *ret_clen)
23193e513d1cd69 Mark Fasheh       2007-09-12  775  {
9b7895efac906d6 Mark Fasheh       2008-11-12  776  	int ret = 0, i, found;
9b7895efac906d6 Mark Fasheh       2008-11-12  777  	struct buffer_head *eb_bh = NULL;
9b7895efac906d6 Mark Fasheh       2008-11-12  778  	struct ocfs2_extent_block *eb;
9b7895efac906d6 Mark Fasheh       2008-11-12  779  	struct ocfs2_extent_rec *rec = NULL;
23193e513d1cd69 Mark Fasheh       2007-09-12  780  
9b7895efac906d6 Mark Fasheh       2008-11-12  781  	if (el->l_tree_depth) {
facdb77f54f09a3 Joel Becker       2009-02-12  782  		ret = ocfs2_find_leaf(INODE_CACHE(inode), el, major_hash,
facdb77f54f09a3 Joel Becker       2009-02-12  783  				      &eb_bh);
9b7895efac906d6 Mark Fasheh       2008-11-12  784  		if (ret) {
9b7895efac906d6 Mark Fasheh       2008-11-12  785  			mlog_errno(ret);
9b7895efac906d6 Mark Fasheh       2008-11-12  786  			goto out;
9b7895efac906d6 Mark Fasheh       2008-11-12  787  		}
23193e513d1cd69 Mark Fasheh       2007-09-12  788  
9b7895efac906d6 Mark Fasheh       2008-11-12  789  		eb = (struct ocfs2_extent_block *) eb_bh->b_data;
9b7895efac906d6 Mark Fasheh       2008-11-12  790  		el = &eb->h_list;
4a12ca3a00a244e Mark Fasheh       2008-11-12  791  
9b7895efac906d6 Mark Fasheh       2008-11-12  792  		if (el->l_tree_depth) {
17a5b9ab32fe046 Goldwyn Rodrigues 2015-09-04  793  			ret = ocfs2_error(inode->i_sb,
7ecef14ab1db961 Joe Perches       2015-09-04  794  					  "Inode %lu has non zero tree depth in btree tree block %llu\n",
7ecef14ab1db961 Joe Perches       2015-09-04  795  					  inode->i_ino,
9b7895efac906d6 Mark Fasheh       2008-11-12  796  					  (unsigned long long)eb_bh->b_blocknr);
9b7895efac906d6 Mark Fasheh       2008-11-12  797  			goto out;
9b7895efac906d6 Mark Fasheh       2008-11-12  798  		}
23193e513d1cd69 Mark Fasheh       2007-09-12  799  	}
23193e513d1cd69 Mark Fasheh       2007-09-12  800  
44acc46d182ff36 Ivan Pravdin      2025-07-07  801  	if (le16_to_cpu(el->l_next_free_rec) == 0) {
44acc46d182ff36 Ivan Pravdin      2025-07-07  802  		ret = ocfs2_error(inode->i_sb,
44acc46d182ff36 Ivan Pravdin      2025-07-07  803  				  "Inode %lu has empty extent list at depth %u\n",
44acc46d182ff36 Ivan Pravdin      2025-07-07  804  				  inode->i_ino,
44acc46d182ff36 Ivan Pravdin      2025-07-07  805  				  le16_to_cpu(el->l_tree_depth));
44acc46d182ff36 Ivan Pravdin      2025-07-07  806  		goto out;
44acc46d182ff36 Ivan Pravdin      2025-07-07  807  	}
44acc46d182ff36 Ivan Pravdin      2025-07-07  808  
9b7895efac906d6 Mark Fasheh       2008-11-12  809  	found = 0;
9b7895efac906d6 Mark Fasheh       2008-11-12  810  	for (i = le16_to_cpu(el->l_next_free_rec) - 1; i >= 0; i--) {
9b7895efac906d6 Mark Fasheh       2008-11-12  811  		rec = &el->l_recs[i];
9b7895efac906d6 Mark Fasheh       2008-11-12  812  
9b7895efac906d6 Mark Fasheh       2008-11-12  813  		if (le32_to_cpu(rec->e_cpos) <= major_hash) {
9b7895efac906d6 Mark Fasheh       2008-11-12  814  			found = 1;
9b7895efac906d6 Mark Fasheh       2008-11-12  815  			break;
9b7895efac906d6 Mark Fasheh       2008-11-12  816  		}
9b7895efac906d6 Mark Fasheh       2008-11-12  817  	}
9b7895efac906d6 Mark Fasheh       2008-11-12  818  
9b7895efac906d6 Mark Fasheh       2008-11-12  819  	if (!found) {
7ecef14ab1db961 Joe Perches       2015-09-04  820  		ret = ocfs2_error(inode->i_sb,
7ecef14ab1db961 Joe Perches       2015-09-04 @821  				  "Inode %lu has bad extent record (%u, %u, 0) in btree\n",
7ecef14ab1db961 Joe Perches       2015-09-04  822  				  inode->i_ino,
82a88475c352f95 Shaurya Rane      2025-10-05  823  				  eb_bh ? (unsigned long long)eb_bh->b_blocknr : 0);
9b7895efac906d6 Mark Fasheh       2008-11-12  824  		goto out;
9b7895efac906d6 Mark Fasheh       2008-11-12  825  	}
9b7895efac906d6 Mark Fasheh       2008-11-12  826  
9b7895efac906d6 Mark Fasheh       2008-11-12  827  	if (ret_phys_blkno)
9b7895efac906d6 Mark Fasheh       2008-11-12  828  		*ret_phys_blkno = le64_to_cpu(rec->e_blkno);
9b7895efac906d6 Mark Fasheh       2008-11-12  829  	if (ret_cpos)
9b7895efac906d6 Mark Fasheh       2008-11-12  830  		*ret_cpos = le32_to_cpu(rec->e_cpos);
9b7895efac906d6 Mark Fasheh       2008-11-12  831  	if (ret_clen)
9b7895efac906d6 Mark Fasheh       2008-11-12  832  		*ret_clen = le16_to_cpu(rec->e_leaf_clusters);
9b7895efac906d6 Mark Fasheh       2008-11-12  833  
9b7895efac906d6 Mark Fasheh       2008-11-12  834  out:
9b7895efac906d6 Mark Fasheh       2008-11-12  835  	brelse(eb_bh);
9b7895efac906d6 Mark Fasheh       2008-11-12  836  	return ret;
9b7895efac906d6 Mark Fasheh       2008-11-12  837  }
38760e243249f03 Mark Fasheh       2007-09-11  838  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Re: [PATCH] ocfs2: Fix use-after-free in ocfs2_dx_dir_lookup_rec
Posted by Joseph Qi 2 months, 1 week ago
Hi,
This seems to be fixed by the following commit:
44acc46d182f ocfs2: avoid NULL pointer dereference in dx_dir_lookup_rec()

Thanks,
Joseph

On 2025/10/5 23:14, ssrane_b23@ee.vjti.ac.in wrote:
> From: Shaurya Rane <ssrane_b23@ee.vjti.ac.in>
> 
> A syzbot report triggered a KASAN use-after-free read when creating a
> file on a corrupted OCFS2 filesystem image.
> 
> The crash occurs in an error-handling path within the
> ocfs2_dx_dir_lookup_rec function. When the function fails to find a
> matching extent record (`found` is false), it attempts to log details
> about the corruption by reading from the `rec` variable.
> 
> According to the KASAN report, the memory pointed to by `rec` can be
> invalid at this point, leading to a kernel crash.
> 
> Fix this by modifying the error message to use only variables that are
> known to be safe, such as the inode number and the extent block's
> buffer head block number. This preserves the valuable error log for
> debugging corrupted filesystems while preventing the memory safety
> violation.
> 
> Reported-by: syzbot+30b53487d00b4f7f0922@syzkaller.appspotmail.com
> Tested-by: syzbot+30b53487d00b4f7f0922@syzkaller.appspotmail.com
> Signed-off-by: Shaurya Rane <ssrane_b23@ee.vjti.ac.in>
> ---
>  fs/ocfs2/dir.c | 3 +--
>  1 file changed, 1 insertion(+), 2 deletions(-)
> 
> diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
> index 8c9c4825f984..8c4dd61efa8d 100644
> --- a/fs/ocfs2/dir.c
> +++ b/fs/ocfs2/dir.c
> @@ -820,8 +820,7 @@ static int ocfs2_dx_dir_lookup_rec(struct inode *inode,
>  		ret = ocfs2_error(inode->i_sb,
>  				  "Inode %lu has bad extent record (%u, %u, 0) in btree\n",
>  				  inode->i_ino,
> -				  le32_to_cpu(rec->e_cpos),
> -				  ocfs2_rec_clusters(el, rec));
> +				  eb_bh ? (unsigned long long)eb_bh->b_blocknr : 0);
>  		goto out;
>  	}
>