From: Al Viro <viro@zeniv.linux.org.uk>
To: linux-fsdevel@vger.kernel.org
Cc: Linus Torvalds <torvalds@linux-foundation.org>,
Christian Brauner <brauner@kernel.org>, Jan Kara <jack@suse.cz>,
Amir Goldstein <amir73il@gmail.com>,
Chuck Lever <chuck.lever@oracle.com>,
Namjae Jeon <linkinjeon@kernel.org>,
John Johansen <john@apparmor.net>
Subject: [PATCH 1/2] kernel/acct.c: saner struct file treatment
Date: Sat, 6 Sep 2025 10:13:39 +0100 [thread overview]
Message-ID: <20250906091339.GB31600@ZenIV> (raw)
In-Reply-To: <20250906090738.GA31600@ZenIV>
[first commit in work.f_path]
Instead of switching ->f_path.mnt of an opened file to internal
clone, resolve the pathname, get a struct path with ->mnt set to internal
clone, then dentry_open() that to get the file with right ->f_path.mnt
from the very beginning.
The only subtle part here is that on failure exits we need to
close the file with __fput_sync() and make sure we do that *before*
dropping the original mount.
With that done, only fs/{file_table,open,namei}.c ever store
anything to file->f_path and only prior to file->f_mode & FMODE_OPENED
becoming true. Analysis of mount write count handling also becomes
less brittle and convoluted...
Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
diff --git a/kernel/acct.c b/kernel/acct.c
index 6520baa13669..30ae403ee322 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -44,19 +44,14 @@
* a struct file opened for write. Fixed. 2/6/2000, AV.
*/
-#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/acct.h>
#include <linux/capability.h>
-#include <linux/file.h>
#include <linux/tty.h>
-#include <linux/security.h>
-#include <linux/vfs.h>
+#include <linux/statfs.h>
#include <linux/jiffies.h>
-#include <linux/times.h>
#include <linux/syscalls.h>
-#include <linux/mount.h>
-#include <linux/uaccess.h>
+#include <linux/namei.h>
#include <linux/sched/cputime.h>
#include <asm/div64.h>
@@ -217,84 +212,68 @@ static void close_work(struct work_struct *work)
complete(&acct->done);
}
-static int acct_on(struct filename *pathname)
+DEFINE_FREE(fput_sync, struct file *, if (!IS_ERR_OR_NULL(_T)) __fput_sync(_T))
+static int acct_on(const char __user *name)
{
- struct file *file;
- struct vfsmount *mnt, *internal;
+ /* Difference from BSD - they don't do O_APPEND */
+ const int open_flags = O_WRONLY|O_APPEND|O_LARGEFILE;
struct pid_namespace *ns = task_active_pid_ns(current);
+ struct path path __free(path_put) = {}; // in that order
+ struct path internal __free(path_put) = {}; // in that order
+ struct file *file __free(fput_sync) = NULL; // in that order
struct bsd_acct_struct *acct;
+ struct vfsmount *mnt;
struct fs_pin *old;
int err;
- acct = kzalloc(sizeof(struct bsd_acct_struct), GFP_KERNEL);
- if (!acct)
- return -ENOMEM;
+ err = user_path_at(AT_FDCWD, name, LOOKUP_FOLLOW, &path);
+ if (err)
+ return err;
- /* Difference from BSD - they don't do O_APPEND */
- file = file_open_name(pathname, O_WRONLY|O_APPEND|O_LARGEFILE, 0);
- if (IS_ERR(file)) {
- kfree(acct);
+ mnt = mnt_clone_internal(&path);
+ if (IS_ERR(mnt))
+ return PTR_ERR(mnt);
+
+ internal.mnt = mnt;
+ internal.dentry = dget(mnt->mnt_root);
+
+ file = dentry_open(&internal, open_flags, current_cred());
+ if (IS_ERR(file))
return PTR_ERR(file);
- }
- if (!S_ISREG(file_inode(file)->i_mode)) {
- kfree(acct);
- filp_close(file, NULL);
+ if (!S_ISREG(file_inode(file)->i_mode))
return -EACCES;
- }
/* Exclude kernel kernel internal filesystems. */
- if (file_inode(file)->i_sb->s_flags & (SB_NOUSER | SB_KERNMOUNT)) {
- kfree(acct);
- filp_close(file, NULL);
+ if (file_inode(file)->i_sb->s_flags & (SB_NOUSER | SB_KERNMOUNT))
return -EINVAL;
- }
/* Exclude procfs and sysfs. */
- if (file_inode(file)->i_sb->s_iflags & SB_I_USERNS_VISIBLE) {
- kfree(acct);
- filp_close(file, NULL);
+ if (file_inode(file)->i_sb->s_iflags & SB_I_USERNS_VISIBLE)
return -EINVAL;
- }
- if (!(file->f_mode & FMODE_CAN_WRITE)) {
- kfree(acct);
- filp_close(file, NULL);
+ if (!(file->f_mode & FMODE_CAN_WRITE))
return -EIO;
- }
- internal = mnt_clone_internal(&file->f_path);
- if (IS_ERR(internal)) {
- kfree(acct);
- filp_close(file, NULL);
- return PTR_ERR(internal);
- }
- err = mnt_get_write_access(internal);
- if (err) {
- mntput(internal);
- kfree(acct);
- filp_close(file, NULL);
- return err;
- }
- mnt = file->f_path.mnt;
- file->f_path.mnt = internal;
+
+ acct = kzalloc(sizeof(struct bsd_acct_struct), GFP_KERNEL);
+ if (!acct)
+ return -ENOMEM;
atomic_long_set(&acct->count, 1);
init_fs_pin(&acct->pin, acct_pin_kill);
- acct->file = file;
+ acct->file = no_free_ptr(file);
acct->needcheck = jiffies;
acct->ns = ns;
mutex_init(&acct->lock);
INIT_WORK(&acct->work, close_work);
init_completion(&acct->done);
mutex_lock_nested(&acct->lock, 1); /* nobody has seen it yet */
- pin_insert(&acct->pin, mnt);
+ pin_insert(&acct->pin, path.mnt);
rcu_read_lock();
old = xchg(&ns->bacct, &acct->pin);
mutex_unlock(&acct->lock);
pin_kill(old);
- mnt_put_write_access(mnt);
- mntput(mnt);
return 0;
}
@@ -319,14 +298,9 @@ SYSCALL_DEFINE1(acct, const char __user *, name)
return -EPERM;
if (name) {
- struct filename *tmp = getname(name);
-
- if (IS_ERR(tmp))
- return PTR_ERR(tmp);
mutex_lock(&acct_on_mutex);
- error = acct_on(tmp);
+ error = acct_on(name);
mutex_unlock(&acct_on_mutex);
- putname(tmp);
} else {
rcu_read_lock();
pin_kill(task_active_pid_ns(current)->bacct);
next prev parent reply other threads:[~2025-09-06 9:13 UTC|newest]
Thread overview: 70+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-09-06 9:07 [PATCHES] file->f_path safety and struct path constifications Al Viro
2025-09-06 9:11 ` [PATCH 01/21] backing_file_user_path(): constify struct path * Al Viro
2025-09-06 9:11 ` [PATCH 02/21] constify path argument of vfs_statx_path() Al Viro
2025-09-08 9:38 ` Jan Kara
2025-09-15 12:01 ` Christian Brauner
2025-09-06 9:11 ` [PATCH 03/21] filename_lookup(): constify root argument Al Viro
2025-09-08 9:39 ` Jan Kara
2025-09-15 12:00 ` Christian Brauner
2025-09-06 9:11 ` [PATCH 04/21] done_path_create(): constify path argument Al Viro
2025-09-08 9:40 ` Jan Kara
2025-09-15 12:01 ` Christian Brauner
2025-09-06 9:11 ` [PATCH 05/21] bpf...d_path(): " Al Viro
2025-09-08 9:41 ` Jan Kara
2025-09-15 12:01 ` Christian Brauner
2025-09-06 9:11 ` [PATCH 06/21] nfs: constify path argument of __vfs_getattr() Al Viro
2025-09-08 9:41 ` Jan Kara
2025-09-15 12:02 ` Christian Brauner
2025-09-06 9:11 ` [PATCH 07/21] rqst_exp_get_by_name(): constify path argument Al Viro
2025-09-06 15:16 ` Chuck Lever
2025-09-15 12:02 ` Christian Brauner
2025-09-06 9:11 ` [PATCH 08/21] export_operations->open(): " Al Viro
2025-09-08 9:42 ` Jan Kara
2025-09-15 12:03 ` Christian Brauner
2025-09-06 9:11 ` [PATCH 09/21] check_export(): " Al Viro
2025-09-08 9:43 ` Jan Kara
2025-09-15 12:03 ` Christian Brauner
2025-09-06 9:11 ` [PATCH 10/21] ksmbd_vfs_path_lookup_locked(): root_share_path can be const struct path * Al Viro
2025-09-07 1:45 ` Namjae Jeon
2025-09-15 12:03 ` Christian Brauner
2025-09-06 9:11 ` [PATCH 11/21] ksmbd_vfs_kern_path_unlock(): constify path argument Al Viro
2025-09-07 1:44 ` Namjae Jeon
2025-09-15 12:04 ` Christian Brauner
2025-09-06 9:11 ` [PATCH 12/21] ksmbd_vfs_inherit_posix_acl(): " Al Viro
2025-09-07 1:44 ` Namjae Jeon
2025-09-15 12:04 ` Christian Brauner
2025-09-06 9:11 ` [PATCH 13/21] ksmbd_vfs_set_init_posix_acl(): " Al Viro
2025-09-07 1:44 ` Namjae Jeon
2025-09-15 12:04 ` Christian Brauner
2025-09-06 9:11 ` [PATCH 14/21] ovl_ensure_verity_loaded(): constify datapath argument Al Viro
2025-09-15 12:04 ` Christian Brauner
2025-09-06 9:11 ` [PATCH 15/21] ovl_validate_verity(): constify {meta,data}path arguments Al Viro
2025-09-15 12:05 ` Christian Brauner
2025-09-06 9:11 ` [PATCH 16/21] ovl_get_verity_digest(): constify path argument Al Viro
2025-09-15 12:05 ` Christian Brauner
2025-09-06 9:11 ` [PATCH 17/21] ovl_lower_dir(): " Al Viro
2025-09-15 12:05 ` Christian Brauner
2025-09-06 9:11 ` [PATCH 18/21] ovl_sync_file(): " Al Viro
2025-09-15 12:05 ` Christian Brauner
2025-09-06 9:11 ` [PATCH 19/21] ovl_is_real_file: constify realpath argument Al Viro
2025-09-15 12:06 ` Christian Brauner
2025-09-06 9:11 ` [PATCH 20/21] apparmor/af_unix: constify struct path * arguments Al Viro
2025-09-08 9:46 ` Jan Kara
2025-09-15 12:06 ` Christian Brauner
2025-09-06 9:11 ` [PATCH 21/21] configfs:get_target() - release path as soon as we grab configfs_item reference Al Viro
2025-09-08 9:46 ` Jan Kara
2025-09-15 12:07 ` Christian Brauner
2025-09-08 9:38 ` [PATCH 01/21] backing_file_user_path(): constify struct path * Jan Kara
2025-09-15 11:59 ` Christian Brauner
2025-09-06 9:13 ` Al Viro [this message]
2025-09-25 11:40 ` [PATCH 1/2] kernel/acct.c: saner struct file treatment Mark Brown
2025-09-25 12:28 ` Jan Kara
2025-09-25 18:56 ` Al Viro
2025-09-25 19:09 ` Al Viro
2025-09-25 19:36 ` Al Viro
2025-09-25 20:56 ` Al Viro
2025-09-26 9:13 ` Jan Kara
2025-09-06 9:14 ` [PATCH 2/2] Have cc(1) catch attempts to modify ->f_path Al Viro
2025-09-08 9:52 ` Jan Kara
2025-09-15 12:00 ` Christian Brauner
2025-09-06 9:16 ` [PATCHES] file->f_path safety and struct path constifications Al Viro
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250906091339.GB31600@ZenIV \
--to=viro@zeniv.linux.org.uk \
--cc=amir73il@gmail.com \
--cc=brauner@kernel.org \
--cc=chuck.lever@oracle.com \
--cc=jack@suse.cz \
--cc=john@apparmor.net \
--cc=linkinjeon@kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=torvalds@linux-foundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).