Linux kernel -stable discussions
 help / color / mirror / Atom feed
* [PATCH 0/7] proc: block mounts below /proc/<pid>/net and on the links into /proc/self
@ 2026-10-24 10:38 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
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Christian Brauner @ 2026-10-24 10:38 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: linux-afs, linux-nfs, Alexander Viro, Jan Kara, Aleksa Sarai,
	Chris Mason, Christian Brauner (Amutable), stable

In Linux 6.12 I stopped allowing mounts on the entries below
/proc/<pid>/fd/, /proc/<pid>/fdinfo/ and /proc/<pid>/map_files/ (cf.
[1]). This extends that to two more groups of entries:

(1) Everything below /proc/<pid>/net/.

    proc_net_d_revalidate() fails on every lookup since 1fde6f21d90f
    ("proc: fix /proc/net/* after setns(2)"). lookup_fast() answers that
    with d_invalidate() which detaches every mount on the dentry. That
    affects every mount namespace and includes locked mounts.

    So a mask on /proc/<pid>/net/dev goes away the first time anybody
    looks the name up. The directory is 0555 so anybody really means
    anybody. This is reproducible with a container that masks
    /proc/<pid>/net/dev with a locked bind mount and a stat() by nobody
    in the initial namespaces makes the real file show up again. So it's
    pointless.

    A mount that can't stick is better refused than taken away. I also
    have a version that makes proc_net_d_revalidate() check the network
    namespace instead so mounts there stick. But I think that's
    bullsh*t. It would make mounts on the net entries of other processes
    stick as well and the few users that try to mount there fail today
    anyway (see below).

(2) The links into /proc/self: /proc/self, /proc/thread-self,
    /proc/mounts, /proc/net and the afs and nfs links below /proc/fs/.

    These resolve to a different directory for every process. A mount
    on the link itself is crossed by every lookup through it in that
    mount namespace, so it redirects all processes at once. Mounting
    through the links keeps working and lands on the caller's own entry
    as before.

What I really wanted was to block mounting on anything below
/proc/<pid>/. That was the big hammer I mentioned in [1] years ago. We
can't... I did a pretty exhaustive survey of who mounts on the entries
below /proc/<pid>/ or on the links into it:

- GitHub code search and regex searches on Sourcegraph
- Debian Code Search over unstable
- the systemd units of every binary package in Debian 11, 12, 13 and
  sid, Ubuntu 22.04, 24.04 and 26.04, Fedora 43 and 44, CentOS Stream
  10, openSUSE Leap 16 and Tumbleweed and Arch
- clones of 46 container runtimes and orchestrators, the sandboxes
  (systemd, bubblewrap, flatpak, firejail, snapd, nsjail, minijail,
  Chromium and Firefox), Android and the rooting tools on top of it,
  and the AppArmor and SELinux policies
- detection rules, issue trackers, lore, LWN and the Q&A sites

The legitimate users all mount on entries of the process that does the
mount:

(1) systemd units that list /proc/self/... in ReadOnlyPaths=,
    ReadWritePaths= or ReadWriteDirectories=. systemd resolves
    /proc/self in the child of the service and binds the entry onto
    itself before it execs the service. If the mount fails the unit
    fails with 226/NAMESPACE and the "-" prefix doesn't help. That's
    netdata in Debian 11 and 12 and Ubuntu 22.04 and 24.04, opendht in
    Debian 12 and sid, Ubuntu 24.04 and Arch, accountsservice 22.x in
    Debian 12 and Ubuntu 22.04, OpenSearch 3, wazuh-indexer, TrueNAS
    SCALE, OONI's backend and the JupyterHub systemdspawner example. Of
    the 731 unit files on GitHub that name a /proc path in one of these
    directives 53 name an entry of the service itself.

(2) systemd's make_filesystem() binds /dev/null over /proc/self/mounts
    before it execs mkfs.btrfs so that it doesn't refuse a device whose
    other partitions are mounted. systemd-repart, systemd-homed and
    systemd-makefs use that.

(3) mkosi binds a fake /proc/self/mountinfo for grub-bios-setup.

(4) runc applies maskedPaths such as /proc/1/environ from the
    container's init when a config asks for it, bwrap does the same
    from its pid 1, firejail hides the name of its pid 1 and clampdown
    masks /proc/1/mem.

(5) Shell scripts that mount on /proc/$$/... and then exec, e.g.,
    luci-app-shadowrt on OpenWrt.

(6) Tests in systemd, elogind, LXC, libpathrs and bun.

Fedora's SELinux policy even grants fsadm_t and init_t the permission to
mount over their own entries because of (1) and (2). Sad, very sad...

Everything else I found is malware or offensive tooling:

Hiding a process by mounting over /proc/<pid> is catalogued as MITRE
ATT&CK T1564.013 and used in the wild by TeamTNT, Commando Cat, the KONO
DIO DA miner, KV-botnet, UNC2891 and kbotne. hackshell and emp3r0r ship
it and Elastic's endpoint rule kills any process that does it.

So blocking all of /proc/<pid>/ would break units in released
distributions and systemd itself. A rule that only lets a process
mount on its own entries, and on a directory only a bind of itself,
keeps (1) to (4) working, except for a few bwrap sandboxes that put a
tmpfs over directories like /proc/1/task, and stops all of the attacks.
I have that as well but it's not really a fix so we can delay it.

The remaining entries of a process only fail pid_revalidate() once the
task is gone and proc_flush_pid() invalidates them when it is reaped.
Their mounts go away together with the task and nothing gets revealed.

Nothing I found mounts on the links themselves and crun even has a
test that expects it to fail. The handful of units that mask entries
below /proc/<pid>/net/, e.g., Algo VPN's ReadOnlyPaths=/proc/net/pfkey
for strongswan, already fail today.

systemd's own lookup invalidates the dentry before it can bind onto it.
With this series they fail the same way. Apart from tests in libpathrs
and securejoin that had to be adapted the only fallout from the 6.12
change we found is one small project that handed libmount's new mount
api a /proc/self/fd/N target that move_mount() doesn't follow without
MOVE_MOUNT_T_SYMLINKS. Ubuntu even backported the 6.12 change to their
22.04 and 24.04 kernels this year.

Nuke this crap.

[1]: https://lore.kernel.org/r/20240806-work-procfs-v1-0-fb04e1d09f0c@kernel.org

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
Christian Brauner (7):
      proc: don't let an entry below /proc/<pid>/net be a mountpoint
      proc: don't let /proc/self and /proc/thread-self be mountpoints
      proc: don't let /proc/mounts and /proc/net be mountpoints
      afs: create /proc/fs/afs with proc_self_symlink()
      nfs: create the /proc/fs/nfsfs links with proc_self_symlink()
      proc: explain which entries can't be mountpoints
      selftests/proc: test which entries can't be mountpoints

 fs/afs/main.c                                   |   2 +-
 fs/nfs/client.c                                 |   4 +-
 fs/proc/generic.c                               |  31 ++++-
 fs/proc/internal.h                              |  18 ++-
 fs/proc/proc_net.c                              |   2 +-
 fs/proc/root.c                                  |   2 +-
 fs/proc/self.c                                  |   2 +
 fs/proc/thread_self.c                           |   2 +
 include/linux/proc_fs.h                         |   5 +
 tools/testing/selftests/proc/.gitignore         |   1 +
 tools/testing/selftests/proc/Makefile           |   1 +
 tools/testing/selftests/proc/proc-unmountable.c | 150 ++++++++++++++++++++++++
 12 files changed, 208 insertions(+), 12 deletions(-)
---
base-commit: 7be4bc52fd9e0e55dc9a2e0232b89427d2c4b614
change-id: 20261024-work-procfs-fixes-8b21a6d17448


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/7] proc: don't let an entry below /proc/<pid>/net be a mountpoint
  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 ` 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
  2 siblings, 0 replies; 4+ messages in thread
From: Christian Brauner @ 2026-10-24 10:38 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: linux-afs, linux-nfs, Alexander Viro, Jan Kara, Aleksa Sarai,
	Chris Mason, Christian Brauner (Amutable), stable

proc_net_d_revalidate() always returns 0 so that a dentry below
/proc/<pid>/net is never reused after setns(). So lookup_fast() will end
up calling d_invalidate(), which unhashes the dentry and detaches every
mount on it, in every mount namespace; including locked mounts.

Then lookup_slow() creates a new dentry for the same entry. So a mount
on /proc/<pid>/net/dev succeeds and goes away with the first lookup of
the name by anybody with search permission on the directory. Given it's
0555 that's everyone's grandma. A mask on such a name hides nothing as
the repro below shows.

Treat those entries like I did fd/, fdinfo/ and map_files/ and refuse to
mount on them in the first place. It's nonsensical theater otherwise:

  procnet net/dev stat

  // SPDX-License-Identifier: GPL-2.0
  /*
   * procnet: cover an entry of /proc/<pid>/ with a bind mount, lock the mount,
   * then look the name up.
   *
   * The first task stays alive, <pid> is its pid. The "container" task has its
   * own mount namespace. There it binds a mask on /proc/<pid>/<name>. It drops to
   * uid 1000 and enters a new user namespace with a new mount namespace, so that
   * the mask is locked. Then one task looks the name up:
   *
   *   stat    the container calls stat() on the name
   *   umount  the container calls umount2(MNT_DETACH) on the name
   *   nobody  a task with uid 65534 in the first namespaces calls stat()
   *
   * The container lists its mounts before and after (that does not look the
   * name up) and then reads the name. MASK is fine. Anything else means that
   * the lookup uncovered the entry.
   *
   * usage: procnet <name> stat|umount|nobody
   *   name "status" is the control, "net/dev" is a file below net, "net/stat" is
   *   a directory below net
   */
  #define _GNU_SOURCE
  #include <dirent.h>
  #include <errno.h>
  #include <fcntl.h>
  #include <sched.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <time.h>
  #include <unistd.h>
  #include <sys/mount.h>
  #include <sys/prctl.h>
  #include <sys/stat.h>
  #include <sys/wait.h>

  #define WORK "/run/pn"

  static char target[128];

  static void die(const char *what)
  {
  	fprintf(stderr, "FATAL %s: %s\n", what, strerror(errno));
  	exit(2);
  }

  static void write_str(const char *path, const char *s, int flags)
  {
  	int fd = open(path, O_WRONLY | flags, 0644);

  	if (fd < 0 || write(fd, s, strlen(s)) < 0)
  		die(path);
  	close(fd);
  }

  /* list the mounts below /proc without a lookup of the target */
  static void mounts(const char *when)
  {
  	char line[512];
  	FILE *f = fopen("/proc/self/mountinfo", "r");
  	int n = 0;

  	if (!f)
  		die("mountinfo");
  	while (fgets(line, sizeof(line), f)) {
  		if (!strstr(line, " /proc/"))
  			continue;
  		printf("container: %s: mount: %s", when, line);
  		n++;
  	}
  	fclose(f);
  	if (!n)
  		printf("container: %s: nothing is mounted below /proc\n", when);
  }

  static void show(const char *when, int isdir)
  {
  	char buf[48] = "";
  	int fd;

  	if (isdir) {
  		struct dirent *de;
  		DIR *d = opendir(target);
  		int hit = 0;

  		if (!d) {
  			printf("container: %s: opendir(%s) = %s\n", when, target, strerror(errno));
  			return;
  		}
  		printf("container: %s: readdir(%s) =", when, target);
  		while ((de = readdir(d))) {
  			if (de->d_name[0] == '.')
  				continue;
  			printf(" %s", de->d_name);
  			hit |= strcmp(de->d_name, "MASK");
  		}
  		closedir(d);
  		printf("%s\n", hit ? "   <-- HIT" : "");
  		return;
  	}
  	fd = open(target, O_RDONLY);
  	if (fd < 0) {
  		printf("container: %s: open(%s) = %s\n", when, target, strerror(errno));
  		return;
  	}
  	if (read(fd, buf, sizeof(buf) - 1) < 0)
  		die("read");
  	close(fd);
  	if (strchr(buf, '\n'))
  		*strchr(buf, '\n') = 0;
  	printf("container: %s: read(%s) = \"%s\"%s\n", when, target, buf,
  	       strncmp(buf, "MASK", 4) ? "   <-- HIT" : "");
  }

  int main(int argc, char **argv)
  {
  	const char *name = argc > 1 ? argv[1] : "net/dev";
  	const char *op = argc > 2 ? argv[2] : "stat";
  	int isdir = !strcmp(name, "net/stat");
  	int to_host[2], to_cont[2];
  	struct stat st;
  	pid_t pid;
  	char c;

  	setvbuf(stdout, NULL, _IOLBF, 0);
  	snprintf(target, sizeof(target), "/proc/%d/%s", getpid(), name);
  	if (unshare(CLONE_NEWNS) || mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL))
  		die("unshare");
  	mkdir(WORK, 0755);
  	if (mount("W", WORK, "tmpfs", 0, NULL))
  		die("mount W");
  	write_str(WORK "/mask", "MASK", O_CREAT);
  	mkdir(WORK "/maskdir", 0755);
  	write_str(WORK "/maskdir/MASK", "MASK", O_CREAT);
  	if (pipe(to_host) || pipe(to_cont))
  		die("pipe");

  	pid = fork();
  	if (pid < 0)
  		die("fork");
  	if (!pid) {
  		if (unshare(CLONE_NEWNS))
  			die("container unshare");
  		if (mount(isdir ? WORK "/maskdir" : WORK "/mask", target, NULL, MS_BIND, NULL)) {
  			printf("container: bind the mask on %s: %s\n", target, strerror(errno));
  			exit(0);
  		}
  		printf("container: bind the mask on %s: ok\n", target);
  		if (setgid(1000) || setuid(1000) || prctl(PR_SET_DUMPABLE, 1))
  			die("setuid");
  		/* lock the mount: a new user namespace with a copy of the tree */
  		if (unshare(CLONE_NEWUSER | CLONE_NEWNS))
  			die("container userns");
  		write_str("/proc/self/setgroups", "deny", 0);
  		write_str("/proc/self/uid_map", "0 1000 1", 0);
  		write_str("/proc/self/gid_map", "0 1000 1", 0);
  		mounts("before");
  		errno = 0;
  		if (!strcmp(op, "stat")) {
  			stat(target, &st);
  			printf("container: stat(%s): %s\n", target, strerror(errno));
  		} else if (!strcmp(op, "umount")) {
  			umount2(target, MNT_DETACH);
  			printf("container: umount2(%s, MNT_DETACH): %s\n", target, strerror(errno));
  		} else if (write(to_host[1], "g", 1) != 1 || read(to_cont[0], &c, 1) != 1) {
  			die("sync");
  		}
  		mounts("after");
  		show("after", isdir);
  		exit(0);
  	}
  	close(to_host[1]);
  	if (read(to_host[0], &c, 1) == 1) {
  		pid_t p2 = fork();

  		if (!p2) {
  			if (setgid(65534) || setuid(65534))
  				die("setuid");
  			errno = 0;
  			stat(target, &st);
  			printf("nobody: uid %u: stat(%s): %s\n", getuid(), target, strerror(errno));
  			exit(0);
  		}
  		waitpid(p2, NULL, 0);
  		if (write(to_cont[1], "g", 1) != 1)
  			die("sync");
  	}
  	waitpid(pid, NULL, 0);
  	return 0;
  }

Fixes: 1fde6f21d90f ("proc: fix /proc/net/* after setns(2)")
Cc: <stable@vger.kernel.org>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 fs/proc/generic.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 2b1971da4a85..4c3fcaf68ef4 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -256,9 +256,10 @@ struct dentry *proc_lookup_de(struct inode *dir, struct dentry *dentry,
 		inode = proc_get_inode(dir->i_sb, de);
 		if (!inode)
 			return ERR_PTR(-ENOMEM);
+		/* never reused and so never a mountpoint for long */
 		if (de->flags & PROC_ENTRY_FORCE_LOOKUP)
-			return d_splice_alias_ops(inode, dentry,
-						  &proc_net_dentry_ops);
+			return proc_splice_unmountable(inode, dentry,
+						       &proc_net_dentry_ops);
 		return d_splice_alias_ops(inode, dentry,
 					  &proc_misc_dentry_ops);
 	}

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH 0/7] proc: block mounts below /proc/<pid>/net and on the links into /proc/self
  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-26 13:00 ` Jan Kara
  2026-10-27  5:34 ` Aleksa Sarai
  2 siblings, 0 replies; 4+ messages in thread
From: Jan Kara @ 2026-10-26 13:00 UTC (permalink / raw)
  To: Christian Brauner
  Cc: linux-fsdevel, linux-afs, linux-nfs, Alexander Viro, Jan Kara,
	Aleksa Sarai, Chris Mason, stable

On Sat 24-10-26 12:38:26, Christian Brauner wrote:
> In Linux 6.12 I stopped allowing mounts on the entries below
> /proc/<pid>/fd/, /proc/<pid>/fdinfo/ and /proc/<pid>/map_files/ (cf.
> [1]). This extends that to two more groups of entries:
> 
> (1) Everything below /proc/<pid>/net/.
> 
>     proc_net_d_revalidate() fails on every lookup since 1fde6f21d90f
>     ("proc: fix /proc/net/* after setns(2)"). lookup_fast() answers that
>     with d_invalidate() which detaches every mount on the dentry. That
>     affects every mount namespace and includes locked mounts.
> 
>     So a mask on /proc/<pid>/net/dev goes away the first time anybody
>     looks the name up. The directory is 0555 so anybody really means
>     anybody. This is reproducible with a container that masks
>     /proc/<pid>/net/dev with a locked bind mount and a stat() by nobody
>     in the initial namespaces makes the real file show up again. So it's
>     pointless.
> 
>     A mount that can't stick is better refused than taken away. I also
>     have a version that makes proc_net_d_revalidate() check the network
>     namespace instead so mounts there stick. But I think that's
>     bullsh*t. It would make mounts on the net entries of other processes
>     stick as well and the few users that try to mount there fail today
>     anyway (see below).
> 
> (2) The links into /proc/self: /proc/self, /proc/thread-self,
>     /proc/mounts, /proc/net and the afs and nfs links below /proc/fs/.
> 
>     These resolve to a different directory for every process. A mount
>     on the link itself is crossed by every lookup through it in that
>     mount namespace, so it redirects all processes at once. Mounting
>     through the links keeps working and lands on the caller's own entry
>     as before.
> 
> What I really wanted was to block mounting on anything below
> /proc/<pid>/. That was the big hammer I mentioned in [1] years ago. We
> can't... I did a pretty exhaustive survey of who mounts on the entries
> below /proc/<pid>/ or on the links into it:
> 
> - GitHub code search and regex searches on Sourcegraph
> - Debian Code Search over unstable
> - the systemd units of every binary package in Debian 11, 12, 13 and
>   sid, Ubuntu 22.04, 24.04 and 26.04, Fedora 43 and 44, CentOS Stream
>   10, openSUSE Leap 16 and Tumbleweed and Arch
> - clones of 46 container runtimes and orchestrators, the sandboxes
>   (systemd, bubblewrap, flatpak, firejail, snapd, nsjail, minijail,
>   Chromium and Firefox), Android and the rooting tools on top of it,
>   and the AppArmor and SELinux policies
> - detection rules, issue trackers, lore, LWN and the Q&A sites
> 
> The legitimate users all mount on entries of the process that does the
> mount:
> 
> (1) systemd units that list /proc/self/... in ReadOnlyPaths=,
>     ReadWritePaths= or ReadWriteDirectories=. systemd resolves
>     /proc/self in the child of the service and binds the entry onto
>     itself before it execs the service. If the mount fails the unit
>     fails with 226/NAMESPACE and the "-" prefix doesn't help. That's
>     netdata in Debian 11 and 12 and Ubuntu 22.04 and 24.04, opendht in
>     Debian 12 and sid, Ubuntu 24.04 and Arch, accountsservice 22.x in
>     Debian 12 and Ubuntu 22.04, OpenSearch 3, wazuh-indexer, TrueNAS
>     SCALE, OONI's backend and the JupyterHub systemdspawner example. Of
>     the 731 unit files on GitHub that name a /proc path in one of these
>     directives 53 name an entry of the service itself.
> 
> (2) systemd's make_filesystem() binds /dev/null over /proc/self/mounts
>     before it execs mkfs.btrfs so that it doesn't refuse a device whose
>     other partitions are mounted. systemd-repart, systemd-homed and
>     systemd-makefs use that.
> 
> (3) mkosi binds a fake /proc/self/mountinfo for grub-bios-setup.
> 
> (4) runc applies maskedPaths such as /proc/1/environ from the
>     container's init when a config asks for it, bwrap does the same
>     from its pid 1, firejail hides the name of its pid 1 and clampdown
>     masks /proc/1/mem.
> 
> (5) Shell scripts that mount on /proc/$$/... and then exec, e.g.,
>     luci-app-shadowrt on OpenWrt.
> 
> (6) Tests in systemd, elogind, LXC, libpathrs and bun.
> 
> Fedora's SELinux policy even grants fsadm_t and init_t the permission to
> mount over their own entries because of (1) and (2). Sad, very sad...
> 
> Everything else I found is malware or offensive tooling:
> 
> Hiding a process by mounting over /proc/<pid> is catalogued as MITRE
> ATT&CK T1564.013 and used in the wild by TeamTNT, Commando Cat, the KONO
> DIO DA miner, KV-botnet, UNC2891 and kbotne. hackshell and emp3r0r ship
> it and Elastic's endpoint rule kills any process that does it.
> 
> So blocking all of /proc/<pid>/ would break units in released
> distributions and systemd itself. A rule that only lets a process
> mount on its own entries, and on a directory only a bind of itself,
> keeps (1) to (4) working, except for a few bwrap sandboxes that put a
> tmpfs over directories like /proc/1/task, and stops all of the attacks.
> I have that as well but it's not really a fix so we can delay it.
> 
> The remaining entries of a process only fail pid_revalidate() once the
> task is gone and proc_flush_pid() invalidates them when it is reaped.
> Their mounts go away together with the task and nothing gets revealed.
> 
> Nothing I found mounts on the links themselves and crun even has a
> test that expects it to fail. The handful of units that mask entries
> below /proc/<pid>/net/, e.g., Algo VPN's ReadOnlyPaths=/proc/net/pfkey
> for strongswan, already fail today.
> 
> systemd's own lookup invalidates the dentry before it can bind onto it.
> With this series they fail the same way. Apart from tests in libpathrs
> and securejoin that had to be adapted the only fallout from the 6.12
> change we found is one small project that handed libmount's new mount
> api a /proc/self/fd/N target that move_mount() doesn't follow without
> MOVE_MOUNT_T_SYMLINKS. Ubuntu even backported the 6.12 change to their
> 22.04 and 24.04 kernels this year.
> 
> Nuke this crap.
> 
> [1]: https://lore.kernel.org/r/20240806-work-procfs-v1-0-fb04e1d09f0c@kernel.org
> 
> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>

Makes sense to me although I don't dare to judge all possible consequences
(I don't have much practical experience with container runtimes that play
these games). Anyway, feel free to add:

Acked-by: Jan Kara <jack@suse.cz>

								Honza

> ---
> Christian Brauner (7):
>       proc: don't let an entry below /proc/<pid>/net be a mountpoint
>       proc: don't let /proc/self and /proc/thread-self be mountpoints
>       proc: don't let /proc/mounts and /proc/net be mountpoints
>       afs: create /proc/fs/afs with proc_self_symlink()
>       nfs: create the /proc/fs/nfsfs links with proc_self_symlink()
>       proc: explain which entries can't be mountpoints
>       selftests/proc: test which entries can't be mountpoints
> 
>  fs/afs/main.c                                   |   2 +-
>  fs/nfs/client.c                                 |   4 +-
>  fs/proc/generic.c                               |  31 ++++-
>  fs/proc/internal.h                              |  18 ++-
>  fs/proc/proc_net.c                              |   2 +-
>  fs/proc/root.c                                  |   2 +-
>  fs/proc/self.c                                  |   2 +
>  fs/proc/thread_self.c                           |   2 +
>  include/linux/proc_fs.h                         |   5 +
>  tools/testing/selftests/proc/.gitignore         |   1 +
>  tools/testing/selftests/proc/Makefile           |   1 +
>  tools/testing/selftests/proc/proc-unmountable.c | 150 ++++++++++++++++++++++++
>  12 files changed, 208 insertions(+), 12 deletions(-)
> ---
> base-commit: 7be4bc52fd9e0e55dc9a2e0232b89427d2c4b614
> change-id: 20261024-work-procfs-fixes-8b21a6d17448
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 0/7] proc: block mounts below /proc/<pid>/net and on the links into /proc/self
  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-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
  2 siblings, 0 replies; 4+ messages in thread
From: Aleksa Sarai @ 2026-10-27  5:34 UTC (permalink / raw)
  To: Christian Brauner
  Cc: linux-fsdevel, linux-afs, linux-nfs, Alexander Viro, Jan Kara,
	Chris Mason, stable

[-- Attachment #1: Type: text/plain, Size: 2174 bytes --]

On 2026-10-24, Christian Brauner <brauner@kernel.org> wrote:
> Nuke this crap.
> 
> [1]: https://lore.kernel.org/r/20240806-work-procfs-v1-0-fb04e1d09f0c@kernel.org
> 
> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
> ---
> Christian Brauner (7):
>       proc: don't let an entry below /proc/<pid>/net be a mountpoint
>       proc: don't let /proc/self and /proc/thread-self be mountpoints
>       proc: don't let /proc/mounts and /proc/net be mountpoints
>       afs: create /proc/fs/afs with proc_self_symlink()
>       nfs: create the /proc/fs/nfsfs links with proc_self_symlink()
>       proc: explain which entries can't be mountpoints
>       selftests/proc: test which entries can't be mountpoints

I love it, nuke it from orbit.

Reviewed-by: Aleksa Sarai <aleksa@amutable.com>

The proc_net_d_revalidate() thing is particularly wild, I'm surprised it
hadn't come up to us in bug reports in the past ~10 years. I guess
nobody cared enough to try to mask it?

And yeah, it's a shame we couldn't kill this entirely but I'm looking
forward to the patch you mentioned that restricts who and what can be
over-mounted.

>  fs/afs/main.c                                   |   2 +-
>  fs/nfs/client.c                                 |   4 +-
>  fs/proc/generic.c                               |  31 ++++-
>  fs/proc/internal.h                              |  18 ++-
>  fs/proc/proc_net.c                              |   2 +-
>  fs/proc/root.c                                  |   2 +-
>  fs/proc/self.c                                  |   2 +
>  fs/proc/thread_self.c                           |   2 +
>  include/linux/proc_fs.h                         |   5 +
>  tools/testing/selftests/proc/.gitignore         |   1 +
>  tools/testing/selftests/proc/Makefile           |   1 +
>  tools/testing/selftests/proc/proc-unmountable.c | 150 ++++++++++++++++++++++++
>  12 files changed, 208 insertions(+), 12 deletions(-)
> ---
> base-commit: 7be4bc52fd9e0e55dc9a2e0232b89427d2c4b614
> change-id: 20261024-work-procfs-fixes-8b21a6d17448

-- 
Aleksa Sarai
Founding Engineer at Amutable
https://www.cyphar.com/

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 265 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-10-27  5:35 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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-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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox