kernel/1228-anon-inode-use-a-proper-mode-internally.patch
Andrew Lukoshko b9d46fff46 Recreate RHEL 6.12.0-211.18.1 from CS10/upstream backports
Add the RHEL 211.17.1..211.18.1 backports (1162-1244) from centos-stream-10 and
upstream, on top of 211.16.1. Includes the lpfc 14.4.0.x revert batch and the
RHEL-only lpfc_nlp_get UAF guard. Bump to 211.18.1.
2026-06-07 00:04:03 +00:00

133 lines
4.6 KiB
Diff

From ad4c21b7a2a9f224f45989127541560ccf7cdf53 Mon Sep 17 00:00:00 2001
From: Rafael Aquini <raquini@redhat.com>
Date: Mon, 11 May 2026 10:39:34 -0400
Subject: [PATCH] anon_inode: use a proper mode internally
JIRA: https://issues.redhat.com/browse/RHEL-171616
Conflicts:
* fs/anon_inodes.c: minor context difference due to RHEL-10 missing unrelated
commit c1feab95e0b2 ("add a string-to-qstr constructor")
* fs/internal.h: minor context difference due to RHEL-10 missing unrelated
commits da06e3c51794 ("fs: don't needlessly acquire f_lock") and
37c4a9590e1e ("statmount: allow to retrieve idmappings")
commit cfd86ef7e8e7b9e015707e46479a6b1de141eed0
Author: Christian Brauner <brauner@kernel.org>
Date: Mon Apr 7 11:54:15 2025 +0200
anon_inode: use a proper mode internally
This allows the VFS to not trip over anonymous inodes and we can add
asserts based on the mode into the vfs. When we report it to userspace
we can simply hide the mode to avoid regressions. I've audited all
direct callers of alloc_anon_inode() and only secretmen overrides i_mode
and i_op inode operations but it already uses a regular file.
Link: https://lore.kernel.org/20250407-work-anon_inode-v1-1-53a44c20d44e@kernel.org
Fixes: af153bb63a336 ("vfs: catch invalid modes in may_open()")
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Cc: stable@vger.kernel.org # all LTS kernels
Reported-by: syzbot+5d8e79d323a13aa0b248@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/all/67ed3fb3.050a0220.14623d.0009.GAE@google.com
Signed-off-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Rafael Aquini <raquini@redhat.com>
diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
index 5a070be69922..7c07b22c1d47 100644
--- a/fs/anon_inodes.c
+++ b/fs/anon_inodes.c
@@ -24,9 +24,43 @@
#include <linux/uaccess.h>
+#include "internal.h"
+
static struct vfsmount *anon_inode_mnt __ro_after_init;
static struct inode *anon_inode_inode __ro_after_init;
+/*
+ * User space expects anonymous inodes to have no file type in st_mode.
+ *
+ * In particular, 'lsof' has this legacy logic:
+ *
+ * type = s->st_mode & S_IFMT;
+ * switch (type) {
+ * ...
+ * case 0:
+ * if (!strcmp(p, "anon_inode"))
+ * Lf->ntype = Ntype = N_ANON_INODE;
+ *
+ * to detect our old anon_inode logic.
+ *
+ * Rather than mess with our internal sane inode data, just fix it
+ * up here in getattr() by masking off the format bits.
+ */
+int anon_inode_getattr(struct mnt_idmap *idmap, const struct path *path,
+ struct kstat *stat, u32 request_mask,
+ unsigned int query_flags)
+{
+ struct inode *inode = d_inode(path->dentry);
+
+ generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
+ stat->mode &= ~S_IFMT;
+ return 0;
+}
+
+static const struct inode_operations anon_inode_operations = {
+ .getattr = anon_inode_getattr,
+};
+
/*
* anon_inodefs_dname() is called from d_path().
*/
@@ -78,6 +112,7 @@ struct inode *anon_inode_make_secure_inode(struct super_block *sb, const char *n
if (IS_ERR(inode))
return inode;
inode->i_flags &= ~S_PRIVATE;
+ inode->i_op = &anon_inode_operations;
error = security_inode_init_security_anon(inode, &qname, context_inode);
if (error) {
iput(inode);
@@ -326,6 +361,7 @@ static int __init anon_inode_init(void)
anon_inode_inode = alloc_anon_inode(anon_inode_mnt->mnt_sb);
if (IS_ERR(anon_inode_inode))
panic("anon_inode_init() inode allocation failed (%ld)\n", PTR_ERR(anon_inode_inode));
+ anon_inode_inode->i_op = &anon_inode_operations;
return 0;
}
diff --git a/fs/internal.h b/fs/internal.h
index b555366c7974..afa926ccee7e 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -338,3 +338,6 @@ static inline bool path_mounted(const struct path *path)
return path->mnt->mnt_root == path->dentry;
}
void file_f_owner_release(struct file *file);
+int anon_inode_getattr(struct mnt_idmap *idmap, const struct path *path,
+ struct kstat *stat, u32 request_mask,
+ unsigned int query_flags);
diff --git a/fs/libfs.c b/fs/libfs.c
index 7fd661bb935f..4e9de5aa4d7f 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -1651,7 +1651,13 @@ struct inode *alloc_anon_inode(struct super_block *s)
* that it already _is_ on the dirty list.
*/
inode->i_state = I_DIRTY;
- inode->i_mode = S_IRUSR | S_IWUSR;
+ /*
+ * 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.
+ */
+ inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR;
inode->i_uid = current_fsuid();
inode->i_gid = current_fsgid();
inode->i_flags |= S_PRIVATE;
--
2.50.1 (Apple Git-155)