Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions debian/changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
util-linux (2.40.4-3deepin11) unstable; urgency=medium

* fix CVE-2026-3184: Use original FQDN for PAM_RHOST in login

-- deepin-ci-robot <packages@deepin.org> Tue, 26 May 2026 23:23:00 +0800

util-linux (2.40.4-3deepin10) unstable; urgency=medium

* fix CVE-2026-27456: Add LOOPDEV_FL_NOFOLLOW to prevent symlink attacks

-- deepin-ci-robot <packages@deepin.org> Tue, 26 May 2026 23:19:00 +0800

util-linux (2.40.4-3deepin9) unstable; urgency=medium

* fix CVE-2025-14104
Expand Down
73 changes: 73 additions & 0 deletions debian/patches/CVE-2026-27456.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
From: Karel Zak <kzak@redhat.com>
Date: Thu, 19 Feb 2026 13:59:46 +0100
Subject: loopdev: add LOOPDEV_FL_NOFOLLOW to prevent symlink attacks
Origin: https://github.com/util-linux/util-linux/commit/5e390467b26a3cf3fecc04e1a0d482dff3162fc4
Bug: https://github.com/util-linux/util-linux/security/advisories/GHSA-qq4x-vfq4-9h9g

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
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().

diff --git a/include/loopdev.h b/include/loopdev.h
index d5ef851..c686e71 100644
--- a/include/loopdev.h
+++ b/include/loopdev.h
@@ -140,7 +140,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 baa7368..40768e7 100644
--- a/lib/loopdev.c
+++ b/lib/loopdev.c
@@ -1267,7 +1267,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;

@@ -1406,6 +1409,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 811685b..0c3832b 100644
--- a/libmount/src/hook_loopdev.c
+++ b/libmount/src/hook_loopdev.c
@@ -272,7 +272,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)) {
46 changes: 46 additions & 0 deletions debian/patches/CVE-2026-3184.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
From: Karel Zak <kzak@redhat.com>
Date: Thu, 19 Feb 2026 12:20:28 +0100
Subject: login: use original FQDN for PAM_RHOST
Origin: https://github.com/util-linux/util-linux/commit/8b29aeb081e297e48c4c1ac53d88ae07e1331984
Bug: https://bugzilla.redhat.com/show_bug.cgi?id=2442570

When login -h <remotehost> is invoked, init_remote_info() strips the
local domain suffix from the hostname (FQDN to short name) before
storing it in cxt->hostname. This truncated value is then used for
PAM_RHOST, which can bypass pam_access host deny rules that match on
the FQDN.

Preserve the original -h hostname in a new cmd_hostname field and use
it for PAM_RHOST, while keeping the truncated hostname for utmp/wtmp
and logging unchanged.

diff --git a/login-utils/login.c b/login-utils/login.c
index 74c42f4..0990d5e 100644
--- a/login-utils/login.c
+++ b/login-utils/login.c
@@ -128,6 +128,7 @@ struct login_context {
char *thishost; /* this machine */
char *thisdomain; /* this machine's domain */
char *hostname; /* remote machine */
+ char *cmd_hostname; /* remote machine as specified on command line */
char hostaddress[16]; /* remote address */

pid_t pid;
@@ -903,7 +904,7 @@ static pam_handle_t *init_loginpam(struct login_context *cxt)

/* hostname & tty are either set to NULL or their correct values,
* depending on how much we know. */
- rc = pam_set_item(pamh, PAM_RHOST, cxt->hostname);
+ rc = pam_set_item(pamh, PAM_RHOST, cxt->cmd_hostname);
if (is_pam_failure(rc))
loginpam_err(pamh, rc);

@@ -1233,6 +1234,8 @@ static void init_remote_info(struct login_context *cxt, char *remotehost)

cxt->remote = 1;

+ cxt->cmd_hostname = xstrdup(remotehost);
+
get_thishost(cxt, &domain);

if (domain && (p = strchr(remotehost, '.')) &&
3 changes: 2 additions & 1 deletion debian/patches/series
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@ add-sunway-support.patch
uniontech-fix-arm-lscpu-modename.patch
CVE-2025-14104-1.patch
CVE-2025-14104-2.patch

CVE-2026-27456.patch
CVE-2026-3184.patch
Loading