kernel/1233-fs-add-s-anon-inode.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

171 lines
5.7 KiB
Diff

From 0e6f0c4069e34ae66ce960879b5a88ae0ce9aab8 Mon Sep 17 00:00:00 2001
From: Rafael Aquini <raquini@redhat.com>
Date: Mon, 11 May 2026 10:39:37 -0400
Subject: [PATCH] fs: add S_ANON_INODE
JIRA: https://issues.redhat.com/browse/RHEL-171616
Conflicts:
* mm/readahead.c: in order to reduce differences and make the porting cleaner
we are folding the hunk from 6348be02eead ("fdget(), trivial conversions")
commit 19bbfe7b5fcc04d8711e8e1352acc77c1a5c3955
Author: Christian Brauner <brauner@kernel.org>
Date: Mon Apr 21 10:27:40 2025 +0200
fs: add S_ANON_INODE
This makes it easy to detect proper anonymous inodes and to ensure that
we can detect them in codepaths such as readahead().
Readahead on anonymous inodes didn't work because they didn't have a
proper mode. Now that they have we need to retain EINVAL being returned
otherwise LTP will fail.
We also need to ensure that ioctls aren't simply fired like they are for
regular files so things like inotify inodes continue to correctly call
their own ioctl handlers as in [1].
Reported-by: Xilin Wu <sophon@radxa.com>
Link: https://lore.kernel.org/3A9139D5CD543962+89831381-31b9-4392-87ec-a84a5b3507d8@radxa.com [1]
Link: https://lore.kernel.org/7a1a7076-ff6b-4cb0-94e7-7218a0a44028@sirena.org.uk
Signed-off-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Rafael Aquini <raquini@redhat.com>
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 6e0c954388d4..4dbd5627af8f 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -822,7 +822,8 @@ static int do_vfs_ioctl(struct file *filp, unsigned int fd,
return ioctl_fioasync(fd, filp, argp);
case FIOQSIZE:
- if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode) ||
+ if (S_ISDIR(inode->i_mode) ||
+ (S_ISREG(inode->i_mode) && !IS_ANON_FILE(inode)) ||
S_ISLNK(inode->i_mode)) {
loff_t res = inode_get_bytes(inode);
return copy_to_user(argp, &res, sizeof(res)) ?
@@ -857,7 +858,7 @@ static int do_vfs_ioctl(struct file *filp, unsigned int fd,
return ioctl_file_dedupe_range(filp, argp);
case FIONREAD:
- if (!S_ISREG(inode->i_mode))
+ if (!S_ISREG(inode->i_mode) || IS_ANON_FILE(inode))
return vfs_ioctl(filp, cmd, arg);
return put_user(i_size_read(inode) - filp->f_pos,
@@ -882,7 +883,7 @@ static int do_vfs_ioctl(struct file *filp, unsigned int fd,
return ioctl_get_fs_sysfs_path(filp, argp);
default:
- if (S_ISREG(inode->i_mode))
+ if (S_ISREG(inode->i_mode) && !IS_ANON_FILE(inode))
return file_ioctl(filp, cmd, argp);
break;
}
diff --git a/fs/libfs.c b/fs/libfs.c
index 4e9de5aa4d7f..c4a305967619 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -1660,7 +1660,7 @@ struct inode *alloc_anon_inode(struct super_block *s)
inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR;
inode->i_uid = current_fsuid();
inode->i_gid = current_fsgid();
- inode->i_flags |= S_PRIVATE;
+ inode->i_flags |= S_PRIVATE | S_ANON_INODE;
simple_inode_init_ts(inode);
return inode;
}
diff --git a/fs/pidfs.c b/fs/pidfs.c
index d6c0ed79ea24..7e10fac8e623 100644
--- a/fs/pidfs.c
+++ b/fs/pidfs.c
@@ -804,7 +804,7 @@ static int pidfs_init_inode(struct inode *inode, void *data)
const struct pid *pid = data;
inode->i_private = data;
- inode->i_flags |= S_PRIVATE;
+ inode->i_flags |= S_PRIVATE | S_ANON_INODE;
inode->i_mode |= S_IRWXU;
inode->i_op = &pidfs_inode_operations;
inode->i_fop = &pidfs_file_operations;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 3e14c4eb64f4..fa47510429f0 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2319,6 +2319,7 @@ struct super_operations {
#define S_CASEFOLD (1 << 15) /* Casefolded file */
#define S_VERITY (1 << 16) /* Verity file (using fs/verity/) */
#define S_KERNEL_FILE (1 << 17) /* File is in use by the kernel (eg. fs/cachefiles) */
+#define S_ANON_INODE (1 << 19) /* Inode is an anonymous inode */
/*
* Note that nosuid etc flags are inode-specific: setting some file-system
@@ -2375,6 +2376,7 @@ static inline bool sb_rdonly(const struct super_block *sb) { return sb->s_flags
#define IS_WHITEOUT(inode) (S_ISCHR(inode->i_mode) && \
(inode)->i_rdev == WHITEOUT_DEV)
+#define IS_ANON_FILE(inode) ((inode)->i_flags & S_ANON_INODE)
static inline bool HAS_UNMAPPED_ID(struct mnt_idmap *idmap,
struct inode *inode)
diff --git a/mm/readahead.c b/mm/readahead.c
index 2dbe5993b6aa..a3547f923249 100644
--- a/mm/readahead.c
+++ b/mm/readahead.c
@@ -678,29 +678,34 @@ EXPORT_SYMBOL_GPL(page_cache_async_ra);
ssize_t ksys_readahead(int fd, loff_t offset, size_t count)
{
- ssize_t ret;
- struct fd f;
+ struct file *file;
+ const struct inode *inode;
- ret = -EBADF;
- f = fdget(fd);
- if (!fd_file(f) || !(fd_file(f)->f_mode & FMODE_READ))
- goto out;
+ CLASS(fd, f)(fd);
+ if (fd_empty(f))
+ return -EBADF;
+
+ file = fd_file(f);
+ if (!(file->f_mode & FMODE_READ))
+ return -EBADF;
/*
* The readahead() syscall is intended to run only on files
* that can execute readahead. If readahead is not possible
* on this file, then we must return -EINVAL.
*/
- ret = -EINVAL;
- if (!fd_file(f)->f_mapping || !fd_file(f)->f_mapping->a_ops ||
- (!S_ISREG(file_inode(fd_file(f))->i_mode) &&
- !S_ISBLK(file_inode(fd_file(f))->i_mode)))
- goto out;
-
- ret = vfs_fadvise(fd_file(f), offset, count, POSIX_FADV_WILLNEED);
-out:
- fdput(f);
- return ret;
+ if (!file->f_mapping)
+ return -EINVAL;
+ if (!file->f_mapping->a_ops)
+ return -EINVAL;
+
+ inode = file_inode(file);
+ if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))
+ return -EINVAL;
+ if (IS_ANON_FILE(inode))
+ return -EINVAL;
+
+ return vfs_fadvise(fd_file(f), offset, count, POSIX_FADV_WILLNEED);
}
SYSCALL_DEFINE3(readahead, int, fd, loff_t, offset, size_t, count)
--
2.50.1 (Apple Git-155)