]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libmount: fix SUID bypass via LIBMOUNT_FORCE_MOUNT2 and legacy mount path
authorKarel Zak <kzak@redhat.com>
Tue, 16 Jun 2026 08:58:32 +0000 (10:58 +0200)
committerKarel Zak <kzak@redhat.com>
Tue, 16 Jun 2026 08:58:32 +0000 (10:58 +0200)
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
libmount/src/hook_mount_legacy.c

index 322f726ccd5fb38bb73a5f0b8b01cb174718d885..d46313646f6bbdd2f5e08560a9a8c5833782a04e 100644 (file)
@@ -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)
index 7d22066c048ddcb09d813ffe81a038474f3ab529..9b2485a74193f96f26af564b03e46d8598026332 100644 (file)
@@ -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 =