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!"

Reply via email to