mirror of
https://git.yoctoproject.org/poky
synced 2026-07-15 15:37:03 +00:00
util-linux: Fix CVE-2026-27456
Pick patch from [1] as 2.39.x upstream backport of [2] mentioned in Debian report in [3]. [1] https://github.com/util-linux/util-linux/commit/79164668a412b71fcb1495c7d299cc5e9741fa30 [2] https://github.com/util-linux/util-linux/commit/0ba0f14caa812349424df0da00ac2d97fee9d972 [3] https://security-tracker.debian.org/tracker/CVE-2026-27456 (From OE-Core rev: 9da42b7e29d39a2650d146d9e4a1ffcdb8c1f1ca) Signed-off-by: Hugo SIMELIERE (Schneider Electric) <hsimeliere.opensource@witekio.com> Reviewed-by: Bruno VERNAY <bruno.vernay@se.com> Signed-off-by: Jeremy Rosen <jeremy.rosen@smile.fr> Signed-off-by: Paul Barker <paul@pbarker.dev>
This commit is contained in:
committed by
Paul Barker
parent
7204e2e6d6
commit
83670737fd
@@ -46,6 +46,7 @@ SRC_URI = "${KERNELORG_MIRROR}/linux/utils/util-linux/v${MAJOR_VERSION}/util-lin
|
||||
file://sys-utils-hwclock-rtc-fix-pointer-usage.patch \
|
||||
file://CVE-2025-14104-01.patch \
|
||||
file://CVE-2025-14104-02.patch \
|
||||
file://CVE-2026-27456.patch \
|
||||
"
|
||||
|
||||
SRC_URI[sha256sum] = "7b6605e48d1a49f43cc4b4cfc59f313d0dd5402fa40b96810bd572e167dfed0f"
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
From af0b619f8eb15f738c69e33e0bb3a794e9cccf17 Mon Sep 17 00:00:00 2001
|
||||
From: Karel Zak <kzak@redhat.com>
|
||||
Date: Thu, 19 Feb 2026 13:59:46 +0100
|
||||
Subject: [PATCH] loopdev: add LOOPDEV_FL_NOFOLLOW to prevent symlink attacks
|
||||
|
||||
Add a new LOOPDEV_FL_NOFOLLOW flag for loop device context that
|
||||
prevents symlink following in both path canonicalization and file open.
|
||||
|
||||
When set:
|
||||
- loopcxt_set_backing_file() uses strdup() instead of
|
||||
ul_canonicalize_path() (which calls realpath() and follows symlinks)
|
||||
- loopcxt_setup_device() adds O_NOFOLLOW to open() flags
|
||||
|
||||
The flag is set for non-root (restricted) mount operations in
|
||||
libmount's loop device hook. This prevents a TOCTOU race condition
|
||||
where an attacker could replace the backing file (specified in
|
||||
/etc/fstab) with a symlink to an arbitrary root-owned file between
|
||||
path resolution and open().
|
||||
|
||||
Vulnerable Code Flow:
|
||||
|
||||
mount /mnt/point (non-root, SUID)
|
||||
mount.c: sanitize_paths() on user args (mountpoint only)
|
||||
mnt_context_mount()
|
||||
mnt_context_prepare_mount()
|
||||
mnt_context_apply_fstab() <-- source path from fstab
|
||||
hooks run at MNT_STAGE_PREP_SOURCE
|
||||
hook_loopdev.c: setup_loopdev()
|
||||
backing_file = fstab source path ("/home/user/disk.img")
|
||||
loopcxt_set_backing_file() <-- calls realpath() as ROOT
|
||||
ul_canonicalize_path() <-- follows symlinks!
|
||||
loopcxt_setup_device()
|
||||
open(lc->filename, O_RDWR|O_CLOEXEC) <-- no O_NOFOLLOW
|
||||
|
||||
Two vulnerabilities in the path:
|
||||
|
||||
1) loopcxt_set_backing_file() calls ul_canonicalize_path() which uses
|
||||
realpath() -- this follows symlinks as euid=0. If the attacker swaps
|
||||
the file to a symlink before this call, lc->filename becomes the
|
||||
resolved target path (e.g., /root/secret.img).
|
||||
|
||||
2) loopcxt_setup_device() opens lc->filename without O_NOFOLLOW. Even
|
||||
if canonicalization happened correctly, the file can be swapped to a
|
||||
symlink between canonicalize and open.
|
||||
|
||||
CVE: CVE-2026-27456
|
||||
Upstream-Status: Backport [https://github.com/util-linux/util-linux/commit/79164668a412b71fcb1495c7d299cc5e9741fa30]
|
||||
|
||||
Addresses: https://github.com/util-linux/util-linux/security/advisories/GHSA-qq4x-vfq4-9h9g
|
||||
Signed-off-by: Karel Zak <kzak@redhat.com>
|
||||
(cherry picked from commit 5e390467b26a3cf3fecc04e1a0d482dff3162fc4)
|
||||
(cherry picked from commit 79164668a412b71fcb1495c7d299cc5e9741fa30)
|
||||
Signed-off-by: Hugo SIMELIERE (Schneider Electric) <hsimeliere.opensource@witekio.com>
|
||||
---
|
||||
include/loopdev.h | 3 ++-
|
||||
lib/loopdev.c | 7 ++++++-
|
||||
libmount/src/hook_loopdev.c | 3 ++-
|
||||
3 files changed, 10 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/include/loopdev.h b/include/loopdev.h
|
||||
index 903adc491..d03e9b65e 100644
|
||||
--- a/include/loopdev.h
|
||||
+++ b/include/loopdev.h
|
||||
@@ -139,7 +139,8 @@ enum {
|
||||
LOOPDEV_FL_NOIOCTL = (1 << 6),
|
||||
LOOPDEV_FL_DEVSUBDIR = (1 << 7),
|
||||
LOOPDEV_FL_CONTROL = (1 << 8), /* system with /dev/loop-control */
|
||||
- LOOPDEV_FL_SIZELIMIT = (1 << 9)
|
||||
+ LOOPDEV_FL_SIZELIMIT = (1 << 9),
|
||||
+ LOOPDEV_FL_NOFOLLOW = (1 << 10) /* O_NOFOLLOW, don't follow symlinks */
|
||||
};
|
||||
|
||||
/*
|
||||
diff --git a/lib/loopdev.c b/lib/loopdev.c
|
||||
index dd9ead3ee..4da251812 100644
|
||||
--- a/lib/loopdev.c
|
||||
+++ b/lib/loopdev.c
|
||||
@@ -1193,7 +1193,10 @@ int loopcxt_set_backing_file(struct loopdev_cxt *lc, const char *filename)
|
||||
if (!lc)
|
||||
return -EINVAL;
|
||||
|
||||
- lc->filename = canonicalize_path(filename);
|
||||
+ if (lc->flags & LOOPDEV_FL_NOFOLLOW)
|
||||
+ lc->filename = strdup(filename);
|
||||
+ else
|
||||
+ lc->filename = canonicalize_path(filename);
|
||||
if (!lc->filename)
|
||||
return -errno;
|
||||
|
||||
@@ -1332,6 +1335,8 @@ int loopcxt_setup_device(struct loopdev_cxt *lc)
|
||||
|
||||
if (lc->config.info.lo_flags & LO_FLAGS_DIRECT_IO)
|
||||
flags |= O_DIRECT;
|
||||
+ if (lc->flags & LOOPDEV_FL_NOFOLLOW)
|
||||
+ flags |= O_NOFOLLOW;
|
||||
|
||||
if ((file_fd = open(lc->filename, mode | flags)) < 0) {
|
||||
if (mode != O_RDONLY && (errno == EROFS || errno == EACCES))
|
||||
diff --git a/libmount/src/hook_loopdev.c b/libmount/src/hook_loopdev.c
|
||||
index 8c8f7f218..ce39a7a70 100644
|
||||
--- a/libmount/src/hook_loopdev.c
|
||||
+++ b/libmount/src/hook_loopdev.c
|
||||
@@ -276,7 +276,8 @@ static int setup_loopdev(struct libmnt_context *cxt,
|
||||
}
|
||||
|
||||
DBG(LOOP, ul_debugobj(cxt, "not found; create a new loop device"));
|
||||
- rc = loopcxt_init(&lc, 0);
|
||||
+ rc = loopcxt_init(&lc,
|
||||
+ mnt_context_is_restricted(cxt) ? LOOPDEV_FL_NOFOLLOW : 0);
|
||||
if (rc)
|
||||
goto done_no_deinit;
|
||||
if (mnt_opt_has_value(loopopt)) {
|
||||
--
|
||||
2.43.0
|
||||
|
||||
Reference in New Issue
Block a user