Re: [PATCH 2/2] vfs: Fix anon_inode triggering VFS_BUG_ON_INODE in may_open()
From: Mateusz Guzik
Date: Wed Apr 02 2025 - 22:27:01 EST
On Wed, Apr 02, 2025 at 06:59:46PM -0700, Penglei Jiang wrote:
> may_open()
> {
> ...
> switch (inode->i_mode & S_IFMT) {
> case S_IFLNK:
> case S_IFDIR:
> case S_IFBLK:
> case S_IFCHR:
> case S_IFIFO:
> case S_IFSOCK:
> case S_IFREG:
> default:
> VFS_BUG_ON_INODE(1, inode);
> }
> ...
> }
>
> Since some anonymous inodes do not have S_IFLNK, S_IFDIR, S_IFBLK,
> S_IFCHR, S_IFIFO, S_IFSOCK, or S_IFREG flags set when created, they
> end up in the default case branch.
>
> When creating some anon_inode instances, the i_mode in the switch
> statement is not properly set, which causes the open operation to
> follow the default branch when opening anon_inode.
>
> We could check whether the inode is an anon_inode before VFS_BUG_ON_INODE
> and trigger the assertion only if it's not. However, a more reasonable
> approach might be to set a flag during creation in alloc_anon_inode(),
> such as inode->i_flags |= S_ANON, to explicitly mark anonymous inodes.
>
I think this is the right step, but there is a missing bit.
The assert was added because of a prior bug report involving ntfs, where
a misconstructed inode did not have an i_mode and was passed to execve.
That eventually landed in may_open() which did not check for MAY_EXEC as
the inode did not fit any of the modes. It was only caught by a
hardening check later.
Note all other cases handle MAY_EXEC.
So I think the safest way forward has 2 steps in the default case:
- detect inodes which purposefully don't have a valid mode and elide the
assert if so, for example like in your patch
- add the permission check:
if (acc_mode & MAY_EXEC)
return -EACCES;
The hardening check comes with a WARN_ON if the inode is not S_ISREG.
No need to hope none of the anon inodes reach it, this should just be
short-circuited.