From 31e37c1c7dcf25b76ccf41391fe934a75644c661 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Tue, 16 Jun 2026 10:58:32 +0200 Subject: [PATCH] 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. Reported-by: Xinyao Hu Signed-off-by: Karel Zak (cherry picked from commit 9cbfb823500f510b34767edabd3ffd5b436987b4) Upstream: https://github.com/util-linux/util-linux/commit/cc81bbcec598cb91f0eb8456282f33eed820ed5f CVE: CVE-2026-53614 Signed-off-by: Thomas Perale --- libmount/src/hook_mount.c | 3 ++- libmount/src/hook_mount_legacy.c | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/libmount/src/hook_mount.c b/libmount/src/hook_mount.c index 374078c97f8..570ee8e01f9 100644 --- a/libmount/src/hook_mount.c +++ b/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" @@ -658,7 +659,7 @@ static int init_sysapi(struct libmnt_context *cxt, 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) diff --git a/libmount/src/hook_mount_legacy.c b/libmount/src/hook_mount_legacy.c index cfdd7af2b2c..942e26e7770 100644 --- a/libmount/src/hook_mount_legacy.c +++ b/libmount/src/hook_mount_legacy.c @@ -285,6 +285,8 @@ static int hook_prepare(struct libmnt_context *cxt, /* 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; @@ -294,12 +296,18 @@ static int hook_prepare(struct libmnt_context *cxt, 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 =