137 lines
4.6 KiB
Diff
137 lines
4.6 KiB
Diff
From edaacbee0f33b7371ec460723d1042a6c5a4bb9d Mon Sep 17 00:00:00 2001
|
|
From: Christian Brauner <brauner@kernel.org>
|
|
Date: Mon, 21 Apr 2025 10:27:40 +0200
|
|
Subject: 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>
|
|
---
|
|
fs/ioctl.c | 7 ++++---
|
|
fs/libfs.c | 2 +-
|
|
fs/pidfs.c | 2 +-
|
|
include/linux/fs.h | 2 ++
|
|
mm/readahead.c | 20 ++++++++++++++++----
|
|
5 files changed, 24 insertions(+), 9 deletions(-)
|
|
|
|
--- a/fs/ioctl.c
|
|
+++ b/fs/ioctl.c
|
|
@@ -821,7 +821,8 @@ static int do_vfs_ioctl(struct file *fil
|
|
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)) ?
|
|
@@ -856,7 +857,7 @@ static int do_vfs_ioctl(struct file *fil
|
|
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,
|
|
@@ -881,7 +882,7 @@ static int do_vfs_ioctl(struct file *fil
|
|
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;
|
|
}
|
|
--- a/fs/libfs.c
|
|
+++ b/fs/libfs.c
|
|
@@ -1656,7 +1656,7 @@ struct inode *alloc_anon_inode(struct su
|
|
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;
|
|
}
|
|
--- a/fs/pidfs.c
|
|
+++ b/fs/pidfs.c
|
|
@@ -826,7 +826,7 @@ static int pidfs_init_inode(struct inode
|
|
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;
|
|
--- a/include/linux/fs.h
|
|
+++ b/include/linux/fs.h
|
|
@@ -2344,6 +2344,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
|
|
@@ -2400,6 +2401,7 @@ static inline bool sb_rdonly(const struc
|
|
|
|
#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)
|
|
--- a/mm/readahead.c
|
|
+++ b/mm/readahead.c
|
|
@@ -690,9 +690,15 @@ EXPORT_SYMBOL_GPL(page_cache_async_ra);
|
|
|
|
ssize_t ksys_readahead(int fd, loff_t offset, size_t count)
|
|
{
|
|
+ struct file *file;
|
|
+ const struct inode *inode;
|
|
+
|
|
CLASS(fd, f)(fd);
|
|
+ if (fd_empty(f))
|
|
+ return -EBADF;
|
|
|
|
- if (fd_empty(f) || !(fd_file(f)->f_mode & FMODE_READ))
|
|
+ file = fd_file(f);
|
|
+ if (!(file->f_mode & FMODE_READ))
|
|
return -EBADF;
|
|
|
|
/*
|
|
@@ -700,9 +706,15 @@ ssize_t ksys_readahead(int fd, loff_t of
|
|
* that can execute readahead. If readahead is not possible
|
|
* on this file, then we must return -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)))
|
|
+ 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);
|