Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package fuse-overlayfs for openSUSE:Factory
checked in at 2026-10-22 19:24:46
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/fuse-overlayfs (Old)
and /work/SRC/openSUSE:Factory/.fuse-overlayfs.new.2252680 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "fuse-overlayfs"
Thu Oct 22 19:24:46 2026 rev:24 rq:1386776 version:1.18
Changes:
--------
--- /work/SRC/openSUSE:Factory/fuse-overlayfs/fuse-overlayfs.changes
2026-08-06 16:18:51.937461474 +0200
+++
/work/SRC/openSUSE:Factory/.fuse-overlayfs.new.2252680/fuse-overlayfs.changes
2026-10-22 19:24:48.622541378 +0200
@@ -1,0 +2,7 @@
+Wed Oct 21 09:29:27 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 1.18 (bsc#1286378, CVE-2026-77478):
+ * main: fix operations on hardlinked lower-layer files
+ resolving to the wrong layer (CVE-2026-77478).
+
+-------------------------------------------------------------------
Old:
----
v1.17.tar.gz
New:
----
v1.18.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ fuse-overlayfs.spec ++++++
--- /var/tmp/diff_new_pack.8JErGH/_old 2026-10-22 19:24:49.490577657 +0200
+++ /var/tmp/diff_new_pack.8JErGH/_new 2026-10-22 19:24:49.492577741 +0200
@@ -17,7 +17,7 @@
Name: fuse-overlayfs
-Version: 1.17
+Version: 1.18
Release: 0
Summary: FUSE implementation for overlayfs
License: GPL-2.0-or-later
++++++ v1.17.tar.gz -> v1.18.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/fuse-overlayfs-1.17/NEWS new/fuse-overlayfs-1.18/NEWS
--- old/fuse-overlayfs-1.17/NEWS 2026-06-09 12:09:26.000000000 +0200
+++ new/fuse-overlayfs-1.18/NEWS 2026-08-30 18:46:57.000000000 +0200
@@ -1,3 +1,8 @@
+* fuse-overlayfs-1.18
+
+- main: fix operations on hardlinked lower-layer files resolving
+ to the wrong layer (CVE-2026-77478).
+
* fuse-overlayfs-1.17
- main: clear SUID/SGID bits on truncate (CVE-2026-52791).
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/fuse-overlayfs-1.17/configure.ac
new/fuse-overlayfs-1.18/configure.ac
--- old/fuse-overlayfs-1.17/configure.ac 2026-06-09 12:09:26.000000000
+0200
+++ new/fuse-overlayfs-1.18/configure.ac 2026-08-30 18:46:57.000000000
+0200
@@ -1,5 +1,5 @@
AC_PREREQ([2.69])
-AC_INIT([fuse-overlayfs], [1.17], [[email protected]])
+AC_INIT([fuse-overlayfs], [1.18], [[email protected]])
AC_CONFIG_SRCDIR([main.c])
AC_CONFIG_HEADERS([config.h])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/fuse-overlayfs-1.17/fuse-overlayfs.h
new/fuse-overlayfs-1.18/fuse-overlayfs.h
--- old/fuse-overlayfs-1.17/fuse-overlayfs.h 2026-06-09 12:09:26.000000000
+0200
+++ new/fuse-overlayfs-1.18/fuse-overlayfs.h 2026-08-30 18:46:57.000000000
+0200
@@ -35,6 +35,7 @@
dev_t dev;
int lookups;
mode_t mode;
+ bool underlying_hardlink;
};
struct ovl_node
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/fuse-overlayfs-1.17/main.c
new/fuse-overlayfs-1.18/main.c
--- old/fuse-overlayfs-1.17/main.c 2026-06-09 12:09:26.000000000 +0200
+++ new/fuse-overlayfs-1.18/main.c 2026-08-30 18:46:57.000000000 +0200
@@ -193,6 +193,14 @@
return lo->timeout;
}
+static double
+get_entry_timeout (struct ovl_data *lo, struct ovl_node *node)
+{
+ if (node->ino && node->ino->underlying_hardlink)
+ return 0;
+ return lo->timeout;
+}
+
static const struct fuse_opt ovl_opts[] = {
{ "redirect_dir=%s",
offsetof (struct ovl_data, redirect_dir), 0 },
@@ -1309,10 +1317,38 @@
}
}
- n->next_link = ino->node;
- ino->node = n;
+ if (n->layer->low)
+ {
+ struct ovl_ino *new_ino;
+
+ ino->underlying_hardlink = true;
+
+ new_ino = calloc (1, sizeof (*new_ino));
+ if (new_ino == NULL)
+ return NULL;
+
+ new_ino->ino = n->tmp_ino;
+ new_ino->dev = n->tmp_dev;
+ new_ino->node = n;
+ new_ino->mode = mode;
+ new_ino->underlying_hardlink = true;
+ n->ino = new_ino;
+ n->next_link = NULL;
+
+ stats.inodes++;
+ return n;
+ }
+
+ {
+ struct ovl_node *last;
+ for (last = ino->node; last->next_link; last = last->next_link)
+ ;
+ last->next_link = n;
+ }
+ n->next_link = NULL;
ino->mode = mode;
n->ino = ino;
+
return n;
}
@@ -2173,13 +2209,7 @@
pnode = inode_to_node (lo, parent);
if (name == NULL)
- {
- /* Prefer a version that is loaded. */
- for (node = pnode; node; node = node->next_link)
- if (node->parent)
- return node;
- return pnode;
- }
+ return pnode;
if (has_prefix (name, ".wh."))
{
@@ -2339,7 +2369,7 @@
e.ino = node_to_inode (node);
node->ino->lookups++;
e.attr_timeout = get_timeout (lo);
- e.entry_timeout = get_timeout (lo);
+ e.entry_timeout = get_entry_timeout (lo, node);
fuse_reply_entry (req, &e);
}
@@ -2629,7 +2659,7 @@
}
e.attr_timeout = get_timeout (lo);
- e.entry_timeout = get_timeout (lo);
+ e.entry_timeout = get_entry_timeout (lo, node);
e.ino = node_to_inode (node);
entsize = fuse_add_direntry_plus (req, p, remaining, name, &e,
offset + 1);
if (entsize <= remaining)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/fuse-overlayfs-1.17/tests/fedora-installs.sh
new/fuse-overlayfs-1.18/tests/fedora-installs.sh
--- old/fuse-overlayfs-1.17/tests/fedora-installs.sh 2026-06-09
12:09:26.000000000 +0200
+++ new/fuse-overlayfs-1.18/tests/fedora-installs.sh 2026-08-30
18:46:57.000000000 +0200
@@ -297,3 +297,23 @@
cp -r merged/base/test/tmp merged/base/test/test1
umount merged
+
+# chmod on hardlinked lower-layer files must copy up the correct file.
+rm -rf lower upper workdir merged
+mkdir lower upper workdir merged
+
+mkdir -p lower/o lower/usr/lib lower/usr/share/x
+echo x > lower/o/orig
+ln lower/o/orig lower/usr/lib/link
+ln lower/o/orig lower/usr/share/x/l3
+chmod 664 lower/o/orig
+
+fuse-overlayfs -o lowerdir=lower,upperdir=upper,workdir=workdir merged
+
+ls merged/o/ merged/usr/lib/ merged/usr/share/x/ > /dev/null
+chmod go-w merged/usr/lib/link
+test "$(stat -c %a merged/usr/lib/link)" = "644"
+
+umount merged
+test -f upper/usr/lib/link
+test "$(stat -c %a upper/usr/lib/link)" = "644"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/fuse-overlayfs-1.17/tests/test-hardlinks.sh
new/fuse-overlayfs-1.18/tests/test-hardlinks.sh
--- old/fuse-overlayfs-1.17/tests/test-hardlinks.sh 2026-06-09
12:09:26.000000000 +0200
+++ new/fuse-overlayfs-1.18/tests/test-hardlinks.sh 2026-08-30
18:46:57.000000000 +0200
@@ -173,4 +173,110 @@
umount merged
rm -rf lower upper workdir merged
+# ========================================
+# Test 9: chmod on hardlinked lower-layer file (same dir, 2 links)
+# ========================================
+echo "=== Test 9: chmod on hardlinked lower file (2 links, same dir) ==="
+mkdir -p lower/d upper workdir merged
+
+echo x > lower/d/a
+ln lower/d/a lower/d/b
+chmod 664 lower/d/a
+
+fuse-overlayfs -o lowerdir=lower,upperdir=upper,workdir=workdir merged
+
+# Force directory load so both hardlink nodes are registered
+ls merged/d/ > /dev/null
+chmod go-w merged/d/a
+test "$(stat -c %a merged/d/a)" = "644"
+
+# Verify the correct file was copied up (not d/b)
+umount merged
+test -f upper/d/a
+test "$(stat -c %a upper/d/a)" = "644"
+rm -rf lower upper workdir merged
+
+# ========================================
+# Test 10: chmod on hardlinked lower-layer file (cross-dir, 3 links)
+# ========================================
+echo "=== Test 10: chmod on hardlinked lower file (3 links, cross-dir) ==="
+mkdir -p lower/o lower/usr/lib lower/usr/share/x upper workdir merged
+
+echo x > lower/o/orig
+ln lower/o/orig lower/usr/lib/link
+ln lower/o/orig lower/usr/share/x/l3
+chmod 664 lower/o/orig
+
+fuse-overlayfs -o lowerdir=lower,upperdir=upper,workdir=workdir merged
+
+# Force all dirs loaded so all three hardlink nodes are registered
+ls merged/o/ merged/usr/lib/ merged/usr/share/x/ > /dev/null
+chmod go-w merged/usr/lib/link
+test "$(stat -c %a merged/usr/lib/link)" = "644"
+
+# Verify the correct file was copied up (not o/orig or usr/share/x/l3)
+umount merged
+test -f upper/usr/lib/link
+test "$(stat -c %a upper/usr/lib/link)" = "644"
+rm -rf lower upper workdir merged
+
+# ========================================
+# Test 11: chmod with multi-layer hardlinks
+# ========================================
+echo "=== Test 11: chmod with hardlinks across overlay layers ==="
+mkdir -p l2/d l1/d upper workdir merged
+
+echo x > l1/d/a
+ln l1/d/a l1/d/b
+chmod 664 l1/d/a
+
+# l2 has a copy of d/a with new mode (simulating a previous copy-up)
+cp l1/d/a l2/d/a
+chmod 644 l2/d/a
+
+fuse-overlayfs -o lowerdir=l2:l1,upperdir=upper,workdir=workdir merged
+
+# d/a should show mode from higher-priority layer l2 (644), not l1 (664)
+test "$(stat -c %a merged/d/a)" = "644"
+
+# Access both links to force inode registration of both, then re-check
+stat merged/d/b > /dev/null
+test "$(stat -c %a merged/d/a)" = "644"
+
+umount merged
+rm -rf l1 l2 upper workdir merged
+
+# ========================================
+# Test 12: simulate podman layer commit with hardlinks
+# ========================================
+echo "=== Test 12: podman-style layer commit with hardlinks ==="
+mkdir -p l1/d upper1 workdir1 merged1
+
+echo x > l1/d/a
+ln l1/d/a l1/d/b
+chmod 664 l1/d/a
+
+fuse-overlayfs -o lowerdir=l1,upperdir=upper1,workdir=workdir1 merged1
+
+# Simulate podman: readdir then chmod
+ls merged1/d/ > /dev/null
+chmod go-w merged1/d/a
+umount merged1
+
+# Verify correct file was copied up to the layer
+test -f upper1/d/a
+test "$(stat -c %a upper1/d/a)" = "644"
+
+# Now mount L2 over L1 (simulates running the built image)
+mkdir -p upper2 workdir2 merged2
+fuse-overlayfs -o lowerdir=upper1:l1,upperdir=upper2,workdir=workdir2 merged2
+
+# Both before and after readdir, d/a must show 644
+test "$(stat -c %a merged2/d/a)" = "644"
+ls merged2/d/ > /dev/null
+test "$(stat -c %a merged2/d/a)" = "644"
+
+umount merged2
+rm -rf l1 upper1 upper2 workdir1 workdir2 merged1 merged2
+
echo "All hard link tests passed!"