]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
anon_inode: rework assertions
authorChristian Brauner <brauner@kernel.org>
Wed, 2 Jul 2025 09:23:55 +0000 (11:23 +0200)
committerChristian Brauner <brauner@kernel.org>
Wed, 2 Jul 2025 12:41:39 +0000 (14:41 +0200)
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: cfd86ef7e8e7 ("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>
fs/exec.c
fs/libfs.c
fs/namei.c

index 1f5fdd2e096e392b342f122d35aba4cf035441c7..ba400aafd6406163a616deaca24ab41d29998353 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -114,6 +114,9 @@ static inline void put_binfmt(struct linux_binfmt * fmt)
 
 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) ||
               (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))
                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
         * 633fb6ac3980 ("exec: move S_ISREG() check earlier"). Since then it is
         * an invariant that all non-regular files error out before we get here.
         */
-       if (WARN_ON_ONCE(!S_ISREG(file_inode(file)->i_mode)) ||
-           path_noexec(&file->f_path))
+       if (WARN_ON_ONCE(!S_ISREG(file_inode(file)->i_mode)))
                return ERR_PTR(-EACCES);
 
        err = exe_file_deny_write_access(file);
index 9ea0ecc325a81c93a55e584824417789e8d1aea0..6f487fc6be343014f8d7d17e5cd2699cc65a868a 100644 (file)
@@ -1649,12 +1649,10 @@ struct inode *alloc_anon_inode(struct super_block *s)
         */
        inode->i_state = I_DIRTY;
        /*
-        * Historically anonymous inodes didn't have a type at all and
-        * userspace has come to rely on this. Internally they're just
-        * regular files but S_IFREG is masked off when reporting
-        * information to userspace.
+        * Historically anonymous inodes don't have a type at all and
+        * userspace has come to rely on this.
         */
-       inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR;
+       inode->i_mode = S_IRUSR | S_IWUSR;
        inode->i_uid = current_fsuid();
        inode->i_gid = current_fsgid();
        inode->i_flags |= S_PRIVATE | S_ANON_INODE;
index 4bb889fc980b7d44914e11ec38ae3e8fdfbafadd..ceb0d47aa6b164bc0c8eb4414576b348db306c7f 100644 (file)
@@ -3471,7 +3471,7 @@ static int may_open(struct mnt_idmap *idmap, const struct path *path,
                        return -EACCES;
                break;
        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);