Skip to content

omfs: fix inverted check and use-after-brelse in omfs_dir_is_empty() - #2612

Open
vfsci-bot[bot] wants to merge 1 commit into
vfs.base.cifrom
pw/1169387/vfs.base.ci
Open

vfsci-bot[bot] wants to merge 1 commit into
vfs.base.cifrom
pw/1169387/vfs.base.ci

Conversation

@vfsci-bot

@vfsci-bot vfsci-bot Bot commented Sep 20, 2026

Copy link
Copy Markdown

Series: https://patchwork.kernel.org/project/linux-fsdevel/list/?series=1169387
Submitter: Hui Peng
Version: 1
Patches: 1/1
Message-ID: <20260919202053.2435593-1-benquike@gmail.com>
Base: vfs.base.ci
Lore: https://lore.kernel.org/linux-fsdevel/20260919202053.2435593-1-benquike@gmail.com


Automated by ml2pr

omfs_dir_is_empty() scans the directory's hash bucket table for an
occupied slot (~0 marks an empty bucket) and then returns:

        for (i = 0; i < nbuckets; i++, ptr++)
                if (*ptr != ~0)
                        break;

        brelse(bh);
        return *ptr != ~0;

That return statement has three bugs at once:

  1. The sense is backwards. Its only caller is omfs_remove():

         if (S_ISDIR(inode->i_mode) &&
             !omfs_dir_is_empty(inode))
                 return -ENOTEMPTY;

     When the directory is NOT empty the loop breaks on the first
     occupied bucket, so *ptr != ~0 is true, omfs_dir_is_empty() returns
     1 ("empty"), -ENOTEMPTY is skipped, and rmdir unlinks the directory
     while leaving its children allocated and unreachable.

  2. When the directory IS empty the loop runs to i == nbuckets, leaving
     ptr one u64 past the end of the bucket array - which for a standard
     block size is one u64 past the end of bh->b_data itself. Both the
     out-of-bounds read and the emptiness verdict then depend on whatever
     sits in memory after the buffer.

  3. Either way, ptr points into bh->b_data and is dereferenced after
     brelse(bh) has dropped the buffer reference.

With KASAN enabled, rmdir of an empty directory reports:

 ==================================================================
 BUG: KASAN: use-after-free in omfs_remove+0x265/0x270
 Read of size 8 at addr ffff88811a145000 by task init/1

 CPU: 1 UID: 0 PID: 1 Comm: init Tainted: G    B D  7.3.0-rc3 #1
 Call Trace:
  <TASK>
  dump_stack_lvl+0x70/0xa0
  print_report+0x153/0x4c6
  kasan_report+0xf1/0x120
  omfs_remove+0x265/0x270
  vfs_rmdir+0x2e6/0x810
  filename_rmdir+0x3bf/0x530
  __x64_sys_rmdir+0x4b/0x70
  do_syscall_64+0xda/0x4b0
  entry_SYSCALL_64_after_hwframe+0x77/0x7f
  </TASK>
 ==================================================================

All the information needed is already in the loop counter: the directory
is empty iff the scan reached nbuckets without breaking. Return
`i == nbuckets`, which neither touches the buffer after brelse() nor
reads past the end of the array, and gives omfs_remove() the polarity it
expects.

Fixes: a3ab715 ("omfs: add directory routines")
Assisted-by: LLM
Signed-off-by: Hui Peng <benquike@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant