@@ -55,6 +55,7 @@ SRC_URI = "${KERNELORG_MIRROR}/linux/utils/util-linux/v${MAJOR_VERSION}/util-lin
file://0001-lib-fileutils-fix-unused-parameter-warnings-without-.patch \
file://0001-lib-fileutils-fix-RESOLVE_NO_SYMLINKS-fallback-value.patch \
file://CVE-2026-53613.patch \
+ file://CVE-2026-53612.patch \
"
SRC_URI[sha256sum] = "7b6605e48d1a49f43cc4b4cfc59f313d0dd5402fa40b96810bd572e167dfed0f"
new file mode 100644
@@ -0,0 +1,92 @@
+From 897a08c2b11dfa66975c3d24d63c7bf5f5be1a7c Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Tue, 16 Jun 2026 11:15:19 +0200
+Subject: [PATCH] libmount: use fd-based fchownat/chmod in hook_owner
+
+Replace path-based lchown()/chmod() with fd-based operations in the
+X-mount.{owner,group,mode} post-mount hook.
+
+For restricted users the fd_target is pinned in prepare_target() and
+re-opened after mount in hook_attach_target() to point to the mounted
+filesystem root. For root a local O_PATH fd is opened. Ownership is
+changed via fchownat(fd, "", ..., AT_EMPTY_PATH), mode via
+/proc/self/fd/N.
+
+This prevents TOCTOU attacks where an ancestor directory is swapped
+between mount and the chmod/chown operations.
+
+CVE-2026-53612
+
+Reported-by: Xinyao Hu <ctf_0x01@foxmail.com>
+Signed-off-by: Karel Zak <kzak@redhat.com>
+(cherry picked from commit 24da33905c7115c4cbccd0afb2a469804e96467a)
+
+CVE: CVE-2026-53612
+Upstream-Status: Backport [https://github.com/util-linux/util-linux/commit/897a08c2b11dfa66975c3d24d63c7bf5f5be1a7c]
+Signed-off-by: Peter Marko <peter.marko@siemens.com>
+---
+ libmount/src/hook_owner.c | 32 ++++++++++++++++++++++++--------
+ 1 file changed, 24 insertions(+), 8 deletions(-)
+
+diff --git a/libmount/src/hook_owner.c b/libmount/src/hook_owner.c
+index 11b238c89..99f0e705d 100644
+--- a/libmount/src/hook_owner.c
++++ b/libmount/src/hook_owner.c
+@@ -17,6 +17,7 @@
+ #include <sched.h>
+
+ #include "mountP.h"
++#include "pathnames.h"
+ #include "fileutils.h"
+
+ struct hook_data {
+@@ -48,7 +49,7 @@ static int hook_post(
+ {
+ struct hook_data *hd = (struct hook_data *) data;
+ const char *target;
+- int rc = 0;
++ int rc = 0, fd;
+
+ assert(cxt);
+
+@@ -59,18 +60,33 @@ static int hook_post(
+ if (!target)
+ return 0;
+
++ /* fd_target is pinned in restricted mode (see prepare_target()),
++ * for root open it here to keep chmod/chown fd-based too */
++ if (mnt_context_target_fd_required(cxt))
++ fd = mnt_context_get_target_fd(cxt);
++ else
++ fd = open(target, O_PATH | O_CLOEXEC);
++
++ if (fd < 0)
++ return -MNT_ERR_CHMOD;
++
+ if (hd->owner != (uid_t) -1 || hd->group != (uid_t) -1) {
+- DBG(CXT, ul_debugobj(cxt, " lchown(%s, %u, %u)", target, hd->owner, hd->group));
+- if (lchown(target, hd->owner, hd->group) == -1)
+- return -MNT_ERR_CHOWN;
++ DBG(CXT, ul_debugobj(cxt, " fchownat(%s, %u, %u)", target, hd->owner, hd->group));
++ if (fchownat(fd, "", hd->owner, hd->group, AT_EMPTY_PATH) == -1)
++ rc = -MNT_ERR_CHOWN;
+ }
+
+- if (hd->mode != (mode_t) -1) {
+- DBG(CXT, ul_debugobj(cxt, " chmod(%s, %04o)", target, hd->mode));
+- if (chmod(target, hd->mode) == -1)
+- return -MNT_ERR_CHMOD;
++ if (!rc && hd->mode != (mode_t) -1) {
++ char buf[sizeof(_PATH_PROC_FDDIR) + 1 + sizeof(stringify_value(INT_MAX))];
++
++ snprintf(buf, sizeof(buf), _PATH_PROC_FDDIR "/%d", fd);
++ DBG(CXT, ul_debugobj(cxt, " chmod(%s, %04o)", buf, hd->mode));
++ if (chmod(buf, hd->mode) == -1)
++ rc = -MNT_ERR_CHMOD;
+ }
+
++ if (!mnt_context_target_fd_required(cxt))
++ close(fd);
+ return rc;
+ }
+