From: Christian Brauner <brauner@kernel.org>
To: linux-fsdevel@vger.kernel.org
Cc: linux-afs@lists.infradead.org, linux-nfs@vger.kernel.org,
Alexander Viro <viro@zeniv.linux.org.uk>,
Jan Kara <jack@suse.cz>, Aleksa Sarai <cyphar@cyphar.com>,
Chris Mason <mason@kernel.org>,
"Christian Brauner (Amutable)" <brauner@kernel.org>
Subject: [PATCH 3/7] proc: don't let /proc/mounts and /proc/net be mountpoints
Date: Sat, 24 Oct 2026 12:38:29 +0200 [thread overview]
Message-ID: <20261024-work-procfs-fixes-v1-3-46b03c3a8fac@kernel.org> (raw)
In-Reply-To: <20261024-work-procfs-fixes-v1-0-46b03c3a8fac@kernel.org>
/proc/mounts and /proc/net are links into /proc/self. Like /proc/self
itself they resolve differently for every process. A mount on one of the
links redirects the lookup for all processes in that mount namespace.
Add proc_self_symlink() for links that point into /proc/self. It creates
the link with PROC_ENTRY_CANT_MOUNT and proc_lookup_de() splices such an
entry with proc_splice_unmountable(). Use it for /proc/mounts and
/proc/net.
Mounting through the links keeps working. Such a mount lands on the
caller's own /proc/<pid>/mounts or /proc/<pid>/net, not on the link.
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
fs/proc/generic.c | 26 ++++++++++++++++++++++++--
fs/proc/proc_net.c | 2 +-
fs/proc/root.c | 2 +-
include/linux/proc_fs.h | 5 +++++
4 files changed, 31 insertions(+), 4 deletions(-)
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 4c3fcaf68ef4..484d7dc123eb 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -260,6 +260,10 @@ struct dentry *proc_lookup_de(struct inode *dir, struct dentry *dentry,
if (de->flags & PROC_ENTRY_FORCE_LOOKUP)
return proc_splice_unmountable(inode, dentry,
&proc_net_dentry_ops);
+ /* a mount on a link into /proc/self redirects every process */
+ if (de->flags & PROC_ENTRY_CANT_MOUNT)
+ return proc_splice_unmountable(inode, dentry,
+ &proc_misc_dentry_ops);
return d_splice_alias_ops(inode, dentry,
&proc_misc_dentry_ops);
}
@@ -487,8 +491,8 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent,
return ent;
}
-struct proc_dir_entry *proc_symlink(const char *name,
- struct proc_dir_entry *parent, const char *dest)
+static struct proc_dir_entry *__proc_symlink(const char *name,
+ struct proc_dir_entry *parent, const char *dest, u8 flags)
{
struct proc_dir_entry *ent;
@@ -496,6 +500,7 @@ struct proc_dir_entry *proc_symlink(const char *name,
(S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO),1);
if (ent) {
+ ent->flags |= flags;
ent->size = strlen(dest);
ent->data = kmemdup(dest, ent->size + 1, GFP_KERNEL);
if (ent->data) {
@@ -508,8 +513,25 @@ struct proc_dir_entry *proc_symlink(const char *name,
}
return ent;
}
+
+struct proc_dir_entry *proc_symlink(const char *name,
+ struct proc_dir_entry *parent, const char *dest)
+{
+ return __proc_symlink(name, parent, dest, 0);
+}
EXPORT_SYMBOL(proc_symlink);
+/*
+ * A link into /proc/self resolves differently for every process, so a
+ * mount on the link itself would redirect all of them.
+ */
+struct proc_dir_entry *proc_self_symlink(const char *name,
+ struct proc_dir_entry *parent, const char *dest)
+{
+ return __proc_symlink(name, parent, dest, PROC_ENTRY_CANT_MOUNT);
+}
+EXPORT_SYMBOL_GPL(proc_self_symlink);
+
struct proc_dir_entry *_proc_mkdir(const char *name, umode_t mode,
struct proc_dir_entry *parent, void *data, bool force_lookup)
{
diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c
index b1f5eafb069a..578b1eb081bf 100644
--- a/fs/proc/proc_net.c
+++ b/fs/proc/proc_net.c
@@ -420,7 +420,7 @@ static struct pernet_operations __net_initdata proc_net_ns_ops = {
int __init proc_net_init(void)
{
- proc_symlink("net", NULL, "self/net");
+ proc_self_symlink("net", NULL, "self/net");
return register_pernet_subsys(&proc_net_ns_ops);
}
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 7fbbe92bf73a..42fdc6ec50a3 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -380,7 +380,7 @@ void __init proc_root_init(void)
set_proc_pid_nlink();
proc_self_init();
proc_thread_self_init();
- proc_symlink("mounts", NULL, "self/mounts");
+ proc_self_symlink("mounts", NULL, "self/mounts");
proc_net_init();
proc_mkdir("fs", NULL);
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 47d7deaeed8f..903fc811efd4 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -29,6 +29,7 @@ enum {
PROC_ENTRY_proc_compat_ioctl = 1U << 2,
PROC_ENTRY_proc_lseek = 1U << 3,
+ PROC_ENTRY_CANT_MOUNT = 1U << 6,
PROC_ENTRY_FORCE_LOOKUP = 1U << 7,
};
@@ -87,6 +88,8 @@ extern void proc_flush_pid(struct pid *);
extern struct proc_dir_entry *proc_symlink(const char *,
struct proc_dir_entry *, const char *);
+struct proc_dir_entry *proc_self_symlink(const char *, struct proc_dir_entry *,
+ const char *);
struct proc_dir_entry *_proc_mkdir(const char *, umode_t, struct proc_dir_entry *, void *, bool);
extern struct proc_dir_entry *proc_mkdir(const char *, struct proc_dir_entry *);
extern struct proc_dir_entry *proc_mkdir_data(const char *, umode_t,
@@ -179,6 +182,8 @@ static inline void proc_flush_pid(struct pid *pid)
static inline struct proc_dir_entry *proc_symlink(const char *name,
struct proc_dir_entry *parent,const char *dest) { return NULL;}
+static inline struct proc_dir_entry *proc_self_symlink(const char *name,
+ struct proc_dir_entry *parent, const char *dest) { return NULL; }
static inline struct proc_dir_entry *proc_mkdir(const char *name,
struct proc_dir_entry *parent) {return NULL;}
static inline struct proc_dir_entry *proc_create_mount_point(const char *name) { return NULL; }
--
2.53.0
next prev parent reply other threads:[~2026-10-24 10:38 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-24 10:38 [PATCH 0/7] proc: block mounts below /proc/<pid>/net and on the links into /proc/self Christian Brauner
2026-10-24 10:38 ` [PATCH 1/7] proc: don't let an entry below /proc/<pid>/net be a mountpoint Christian Brauner
2026-10-24 10:38 ` [PATCH 2/7] proc: don't let /proc/self and /proc/thread-self be mountpoints Christian Brauner
2026-10-24 10:38 ` Christian Brauner [this message]
2026-10-24 10:38 ` [PATCH 4/7] afs: create /proc/fs/afs with proc_self_symlink() Christian Brauner
2026-10-24 10:38 ` [PATCH 5/7] nfs: create the /proc/fs/nfsfs links " Christian Brauner
2026-10-26 17:58 ` Anna Schumaker
2026-10-24 10:38 ` [PATCH 6/7] proc: explain which entries can't be mountpoints Christian Brauner
2026-10-24 10:38 ` [PATCH 7/7] selftests/proc: test " Christian Brauner
2026-10-26 13:00 ` [PATCH 0/7] proc: block mounts below /proc/<pid>/net and on the links into /proc/self Jan Kara
2026-10-27 5:34 ` Aleksa Sarai
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=20261024-work-procfs-fixes-v1-3-46b03c3a8fac@kernel.org \
--to=brauner@kernel.org \
--cc=cyphar@cyphar.com \
--cc=jack@suse.cz \
--cc=linux-afs@lists.infradead.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-nfs@vger.kernel.org \
--cc=mason@kernel.org \
--cc=viro@zeniv.linux.org.uk \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.