From: Andrej Shadura <andrewsh@debian.org>
Date: Mon, 1 Jun 2026 16:09:58 +0200
X-Dgit-Generated: 1.3+hg20170412-3 8116fb97ee16eb7b52591edf8b9e72fcd67bb218
Subject: SECURITY FIX: When passing nodev and nosuid, set appropriate mount() options too

9mount passes flags=0 to the mount(2) syscall. For non-root users,
9mount appends the strings "nosuid" and "nodev" to the mount options
string (the "data" argument to mount(2)). However, this has NO security
effect whatsoever:

The Linux VFS enforces nosuid/nodev restrictions exclusively through
the integer "flags" parameter of mount(2) — specifically MS_NOSUID
(bit 2) and MS_NODEV (bit 4). These flags control the MNT_NOSUID
and MNT_NODEV bits in the kernel's struct vfsmount, which are the
only mechanism the kernel checks when deciding whether to honor SUID
bits on executables (mnt_may_suid() in fs/namespace.c) or allow
device node access.

The options string ("data" parameter) is passed verbatim to the
filesystem driver for FS-specific parsing. The 9p filesystem driver
(fs/9p/) does not recognize "nosuid" or "nodev" at all — it simply
ignores them. These strings have zero effect on mount security.

Since 9mount passes flags=0, the resulting mount has SUID and device
nodes fully enabled. Any unprivileged user can mount a malicious 9P
server that serves a SUID root binary, then execute it to gain root.

Thanks: Georgii Shutiaev

---

diff --git a/9mount.c b/9mount.c
index 80a751db73f2..32feb4c77817 100644
--- a/9mount.c
+++ b/9mount.c
@@ -114,6 +114,7 @@ main(int argc, char **argv)
 	int axess = 0, dotu = 0, uidgid = 0, dev = 0, debug = 0, dryrun = 0;
 	char *debugstr = NULL, *msize = NULL, *cache = NULL, *aname = NULL;
 	char *cp, *proto, *addr;
+	unsigned long mountflags = 0;
 
 	if (!(opts=calloc(optlen, 1))) {
 		err(1, "calloc");
@@ -257,9 +258,11 @@ main(int argc, char **argv)
 	}
 	if (!dev) {
 		append(&opts, "nodev", &optlen);
+		mountflags |= MS_NODEV;
 	}
 	if (pw->pw_uid != 0) {
 		append(&opts, "nosuid", &optlen);
+		mountflags |= MS_NOSUID;
 	}
 	if (uidgid) {
 		snprintf(buf, sizeof(buf), "uid=%d,gid=%d", getuid(), getgid());
@@ -292,7 +295,7 @@ main(int argc, char **argv)
 
 	if(dryrun) {
 		fprintf(stderr, "mount -t 9p -o %s %s %s\n", opts, buf, mountpt);
-	} else if (mount(buf, mountpt, "9p", 0, (void*)opts)) {
+	} else if (mount(buf, mountpt, "9p", mountflags, (void*)opts)) {
 		err(1, "mount");
 	}
 
