lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20220218183114.2867528-2-riel@surriel.com>
Date:   Fri, 18 Feb 2022 13:31:13 -0500
From:   Rik van Riel <riel@...riel.com>
To:     linux-kernel@...r.kernel.org
Cc:     kernel-team@...com, linux-fsdevel@...r.kernel.org,
        paulmck@...nel.org, gscrivan@...hat.com, viro@...iv.linux.org.uk,
        Rik van Riel <riel@...riel.com>,
        Eric Biederman <ebiederm@...ssion.com>,
        Chris Mason <clm@...com>
Subject: [PATCH 1/2] vfs: free vfsmount through rcu work from kern_unmount

After kern_unmount returns, callers can no longer access the
vfsmount structure. However, the vfsmount structure does need
to be kept around until the end of the RCU grace period, to
make sure other accesses have all gone away too.

This can be accomplished by either gating each kern_unmount
on synchronize_rcu (the comment in the code says it all), or
by deferring the freeing until the next grace period, where
it needs to be handled in a workqueue due to the locking in
mntput_no_expire().

Suggested-by: Eric Biederman <ebiederm@...ssion.com>
Reported-by: Chris Mason <clm@...com>
---
 fs/namespace.c        | 11 +++++++++--
 include/linux/mount.h |  2 ++
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/fs/namespace.c b/fs/namespace.c
index 40b994a29e90..9f62cf6c69de 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -4384,13 +4384,20 @@ struct vfsmount *kern_mount(struct file_system_type *type)
 }
 EXPORT_SYMBOL_GPL(kern_mount);
 
+static void mntput_rcu_work(struct work_struct *work)
+{
+	struct vfsmount *mnt = container_of(to_rcu_work(work),
+			       struct vfsmount, free_rwork);
+	mntput(mnt);
+}
+
 void kern_unmount(struct vfsmount *mnt)
 {
 	/* release long term mount so mount point can be released */
 	if (!IS_ERR_OR_NULL(mnt)) {
 		real_mount(mnt)->mnt_ns = NULL;
-		synchronize_rcu();	/* yecchhh... */
-		mntput(mnt);
+		INIT_RCU_WORK(&mnt->free_rwork, mntput_rcu_work);
+		queue_rcu_work(system_wq, &mnt->free_rwork);
 	}
 }
 EXPORT_SYMBOL(kern_unmount);
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 7f18a7555dff..cd007cb70d57 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -16,6 +16,7 @@
 #include <linux/spinlock.h>
 #include <linux/seqlock.h>
 #include <linux/atomic.h>
+#include <linux/workqueue.h>
 
 struct super_block;
 struct vfsmount;
@@ -73,6 +74,7 @@ struct vfsmount {
 	struct super_block *mnt_sb;	/* pointer to superblock */
 	int mnt_flags;
 	struct user_namespace *mnt_userns;
+	struct rcu_work free_rwork;
 } __randomize_layout;
 
 static inline struct user_namespace *mnt_user_ns(const struct vfsmount *mnt)
-- 
2.34.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ