anon_inode: rework assertions

Making anonymous inodes regular files comes with a lot of risk and
regression potential as evidenced by a recent hickup in io_uring. We're
better of continuing to not have them be regular files. Since we have
S_ANON_INODE we can port all of our assertions easily.

Link: https://lore.kernel.org/20250702-work-fixes-v1-1-ff76ea589e33@kernel.org
Fixes: cfd86ef7e8 ("anon_inode: use a proper mode internally")
Acked-by: Jens Axboe <axboe@kernel.dk>
Cc: stable@kernel.org
Reported-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
Christian Brauner 2025-07-02 11:23:55 +02:00
parent d5cb81ba92
commit 1e7ab6f678
3 changed files with 11 additions and 8 deletions

View file

@ -114,6 +114,9 @@ static inline void put_binfmt(struct linux_binfmt * fmt)
bool path_noexec(const struct path *path) bool path_noexec(const struct path *path)
{ {
/* If it's an anonymous inode make sure that we catch any shenanigans. */
VFS_WARN_ON_ONCE(IS_ANON_FILE(d_inode(path->dentry)) &&
!(path->mnt->mnt_sb->s_iflags & SB_I_NOEXEC));
return (path->mnt->mnt_flags & MNT_NOEXEC) || return (path->mnt->mnt_flags & MNT_NOEXEC) ||
(path->mnt->mnt_sb->s_iflags & SB_I_NOEXEC); (path->mnt->mnt_sb->s_iflags & SB_I_NOEXEC);
} }
@ -781,13 +784,15 @@ static struct file *do_open_execat(int fd, struct filename *name, int flags)
if (IS_ERR(file)) if (IS_ERR(file))
return file; return file;
if (path_noexec(&file->f_path))
return ERR_PTR(-EACCES);
/* /*
* In the past the regular type check was here. It moved to may_open() in * In the past the regular type check was here. It moved to may_open() in
* 633fb6ac3980 ("exec: move S_ISREG() check earlier"). Since then it is * 633fb6ac3980 ("exec: move S_ISREG() check earlier"). Since then it is
* an invariant that all non-regular files error out before we get here. * an invariant that all non-regular files error out before we get here.
*/ */
if (WARN_ON_ONCE(!S_ISREG(file_inode(file)->i_mode)) || if (WARN_ON_ONCE(!S_ISREG(file_inode(file)->i_mode)))
path_noexec(&file->f_path))
return ERR_PTR(-EACCES); return ERR_PTR(-EACCES);
err = exe_file_deny_write_access(file); err = exe_file_deny_write_access(file);

View file

@ -1649,12 +1649,10 @@ struct inode *alloc_anon_inode(struct super_block *s)
*/ */
inode->i_state = I_DIRTY; inode->i_state = I_DIRTY;
/* /*
* Historically anonymous inodes didn't have a type at all and * Historically anonymous inodes don't have a type at all and
* userspace has come to rely on this. Internally they're just * userspace has come to rely on this.
* regular files but S_IFREG is masked off when reporting
* information to userspace.
*/ */
inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR; inode->i_mode = S_IRUSR | S_IWUSR;
inode->i_uid = current_fsuid(); inode->i_uid = current_fsuid();
inode->i_gid = current_fsgid(); inode->i_gid = current_fsgid();
inode->i_flags |= S_PRIVATE | S_ANON_INODE; inode->i_flags |= S_PRIVATE | S_ANON_INODE;

View file

@ -3471,7 +3471,7 @@ static int may_open(struct mnt_idmap *idmap, const struct path *path,
return -EACCES; return -EACCES;
break; break;
default: default:
VFS_BUG_ON_INODE(1, inode); VFS_BUG_ON_INODE(!IS_ANON_FILE(inode), inode);
} }
error = inode_permission(idmap, inode, MAY_OPEN | acc_mode); error = inode_permission(idmap, inode, MAY_OPEN | acc_mode);