From 9cbfb823500f510b34767edabd3ffd5b436987b4 Mon Sep 17 00:00:00 2001
From: Karel Zak <kzak@redhat.com>
Date: Tue, 16 Jun 2026 10:58:32 +0200
Subject: [PATCH 04/12] libmount: fix SUID bypass via LIBMOUNT_FORCE_MOUNT2 and
 legacy mount path

Use safe_getenv() for LIBMOUNT_FORCE_MOUNT2 to ignore the variable
in SUID context, consistent with LIBMOUNT_FSTAB and other sensitive
environment variables.

Additionally, refuse multi-step mount(2) sequences (bind+remount and
propagation) for restricted (non-root) users in the legacy mount path.
The two-step approach has a window between syscalls where security
flags (nosuid, noexec, ...) are not yet applied.  The new mount API
handles this atomically.

CVE-2026-53614

Reported-by: Xinyao Hu <ctf_0x01@foxmail.com>
Signed-off-by: Karel Zak <kzak@redhat.com>
---
 libmount/src/hook_mount.c        | 3 ++-
 libmount/src/hook_mount_legacy.c | 8 ++++++++
 2 files changed, 10 insertions(+), 1 deletion(-)

Index: util-linux-2.40.4/libmount/src/hook_mount.c
===================================================================
--- util-linux-2.40.4.orig/libmount/src/hook_mount.c
+++ util-linux-2.40.4/libmount/src/hook_mount.c
@@ -44,6 +44,7 @@
  */
 
 #include "mountP.h"
+#include "env.h"
 #include "fileutils.h"	/* statx() fallback */
 #include "strutils.h"
 #include "mount-api-utils.h"
@@ -642,7 +643,7 @@ fail:
 
 static int force_classic_mount(struct libmnt_context *cxt)
 {
-	const char *env = getenv("LIBMOUNT_FORCE_MOUNT2");
+	const char *env = safe_getenv("LIBMOUNT_FORCE_MOUNT2");
 
 	if (env) {
 		if (strcmp(env, "always") == 0)
Index: util-linux-2.40.4/libmount/src/hook_mount_legacy.c
===================================================================
--- util-linux-2.40.4.orig/libmount/src/hook_mount_legacy.c
+++ util-linux-2.40.4/libmount/src/hook_mount_legacy.c
@@ -282,6 +282,8 @@ static int hook_prepare(struct libmnt_co
 
 	/* add extra mount(2) calls for each propagation flag  */
 	if (flags & MS_PROPAGATION) {
+		if (mnt_context_is_restricted(cxt))
+			goto eperm;
 		rc = prepare_propagation(cxt, hs);
 		if (rc)
 			return rc;
@@ -291,12 +293,18 @@ static int hook_prepare(struct libmnt_co
 	if ((flags & MS_BIND)
 	    && (flags & MNT_BIND_SETTABLE)
 	    && !(flags & MS_REMOUNT)) {
+		if (mnt_context_is_restricted(cxt))
+			goto eperm;
 		rc = prepare_bindremount(cxt, hs);
 		if (rc)
 			return rc;
 	}
 
 	return rc;
+eperm:
+	DBG(HOOK, ul_debugobj(hs,
+		"multi-step mount(2) refused for non-root user"));
+	return -EPERM;
 }
 
 const struct libmnt_hookset hookset_mount_legacy =
