From: Karel Zak Date: Tue, 16 Jun 2026 08:58:32 +0000 (+0200) Subject: libmount: fix SUID bypass via LIBMOUNT_FORCE_MOUNT2 and legacy mount path X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9cbfb823500f510b34767edabd3ffd5b436987b4;p=thirdparty%2Futil-linux.git 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 Signed-off-by: Karel Zak --- diff --git a/libmount/src/hook_mount.c b/libmount/src/hook_mount.c index 322f726cc..d46313646 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 "mangle.h" @@ -657,7 +658,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) diff --git a/libmount/src/hook_mount_legacy.c b/libmount/src/hook_mount_legacy.c index 7d22066c0..9b2485a74 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_OBJ(HOOK, hs, ul_debug( + "multi-step mount(2) refused for non-root user")); + return -EPERM; } const struct libmnt_hookset hookset_mount_legacy =