Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package nix for openSUSE:Factory checked in 
at 2026-04-08 17:15:46
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/nix (Old)
 and      /work/SRC/openSUSE:Factory/.nix.new.21863 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "nix"

Wed Apr  8 17:15:46 2026 rev:16 rq:1345082 version:2.34.5

Changes:
--------
--- /work/SRC/openSUSE:Factory/nix/nix.changes  2026-03-28 20:15:49.951567742 
+0100
+++ /work/SRC/openSUSE:Factory/.nix.new.21863/nix.changes       2026-04-08 
17:16:06.852867664 +0200
@@ -1,0 +2,8 @@
+Tue Apr  7 20:26:10 UTC 2026 - Marcus Rueckert <[email protected]>
+
+- Update to version 2.34.5:
+  
https://discourse.nixos.org/t/nix-security-advisory-privilege-escalation-via-symlink-following-during-fod-output-registration/76900
+  - libstore: Use landlock with LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET
+    for new enough kernels
+
+-------------------------------------------------------------------

Old:
----
  nix-2.34.4.tar.gz

New:
----
  nix-2.34.5.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ nix.spec ++++++
--- /var/tmp/diff_new_pack.RdLFfz/_old  2026-04-08 17:16:07.480893485 +0200
+++ /var/tmp/diff_new_pack.RdLFfz/_new  2026-04-08 17:16:07.484893649 +0200
@@ -26,7 +26,7 @@
 %endif
 
 Name:           nix
-Version:        2.34.4
+Version:        2.34.5
 Release:        0
 Summary:        The purely functional package manager
 License:        LGPL-2.1-only

++++++ nix-2.34.4.tar.gz -> nix-2.34.5.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.34.4/.version new/nix-2.34.5/.version
--- old/nix-2.34.4/.version     2026-03-25 22:29:36.000000000 +0100
+++ new/nix-2.34.5/.version     2026-04-06 20:27:24.000000000 +0200
@@ -1 +1 @@
-2.34.4
+2.34.5
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.34.4/packaging/binary-tarball.nix 
new/nix-2.34.5/packaging/binary-tarball.nix
--- old/nix-2.34.4/packaging/binary-tarball.nix 2026-03-25 22:29:36.000000000 
+0100
+++ new/nix-2.34.5/packaging/binary-tarball.nix 2026-04-06 20:27:24.000000000 
+0200
@@ -79,7 +79,8 @@
   fn=$out/$dir.tar.xz
   mkdir -p $out/nix-support
   echo "file binary-dist $fn" >> $out/nix-support/hydra-build-products
-  tar cfJ $fn \
+  tar cf - \
+    --sort=name \
     --owner=0 --group=0 --mode=u+rw,uga+r \
     --mtime='1970-01-01' \
     --absolute-names \
@@ -95,5 +96,5 @@
     $TMPDIR/install-freebsd-multi-user.sh \
     $TMPDIR/install-multi-user \
     $TMPDIR/reginfo \
-    $(cat ${installerClosureInfo}/store-paths)
+    $(cat ${installerClosureInfo}/store-paths) | xz --threads=1 > $fn
 ''
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.34.4/src/libstore/filetransfer.cc 
new/nix-2.34.5/src/libstore/filetransfer.cc
--- old/nix-2.34.4/src/libstore/filetransfer.cc 2026-03-25 22:29:36.000000000 
+0100
+++ new/nix-2.34.5/src/libstore/filetransfer.cc 2026-04-06 20:27:24.000000000 
+0200
@@ -794,7 +794,7 @@
         };
 
         std::priority_queue<ref<TransferItem>, std::vector<ref<TransferItem>>, 
EmbargoComparator> incoming;
-        std::vector<ref<TransferItem>> unpause;
+        std::vector<std::weak_ptr<Item>> unpause;
     private:
         bool quitting = false;
     public:
@@ -967,8 +967,15 @@
                 return res;
             }();
 
-            for (auto & item : unpause)
-                item->unpause();
+            for (auto & item : unpause) {
+                /* The transfer might have completed (failed) between it 
getting
+                   enqueued for unpause and by the time the worker thread 
picked
+                   it up. */
+                auto ptr = item.lock();
+                if (!ptr)
+                    continue;
+                static_cast<TransferItem &>(*ptr).unpause();
+            }
         }
 
         debug("download thread shutting down");
@@ -1008,7 +1015,7 @@
         }
 
         wakeupMulti();
-        return ItemHandle(static_cast<Item &>(*item));
+        return ItemHandle(item.get_ptr());
     }
 
     ItemHandle enqueueFileTransfer(const FileTransferRequest & request, 
Callback<FileTransferResult> callback) override
@@ -1023,7 +1030,7 @@
         return enqueueItem(make_ref<TransferItem>(*this, request, 
std::move(callback)));
     }
 
-    void unpauseTransfer(ref<TransferItem> item)
+    void unpauseTransfer(std::weak_ptr<Item> item)
     {
         auto state(state_.lock());
         state->unpause.push_back(std::move(item));
@@ -1032,7 +1039,9 @@
 
     void unpauseTransfer(ItemHandle handle) override
     {
-        unpauseTransfer(ref{static_cast<TransferItem 
&>(handle.item.get()).shared_from_this()});
+        /* The transfer might have completed (more likely failed) when we want
+           to wake it up. That's why we must use a weak_ptr throughout. */
+        unpauseTransfer(handle.item);
     }
 };
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/nix-2.34.4/src/libstore/include/nix/store/filetransfer.hh 
new/nix-2.34.5/src/libstore/include/nix/store/filetransfer.hh
--- old/nix-2.34.4/src/libstore/include/nix/store/filetransfer.hh       
2026-03-25 22:29:36.000000000 +0100
+++ new/nix-2.34.5/src/libstore/include/nix/store/filetransfer.hh       
2026-04-06 20:27:24.000000000 +0200
@@ -337,10 +337,10 @@
      */
     struct ItemHandle
     {
-        std::reference_wrapper<Item> item;
+        std::weak_ptr<Item> item;
         friend struct FileTransfer;
 
-        ItemHandle(Item & item)
+        explicit ItemHandle(std::weak_ptr<Item> item)
             : item(item)
         {
         }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/nix-2.34.4/src/libstore/include/nix/store/local-store.hh 
new/nix-2.34.5/src/libstore/include/nix/store/local-store.hh
--- old/nix-2.34.4/src/libstore/include/nix/store/local-store.hh        
2026-03-25 22:29:36.000000000 +0100
+++ new/nix-2.34.5/src/libstore/include/nix/store/local-store.hh        
2026-04-06 20:27:24.000000000 +0200
@@ -505,6 +505,8 @@
 
     friend struct PathSubstitutionGoal;
     friend struct DerivationGoal;
+    /* Only used for createTempDirInStore. */
+    friend class DerivationBuilderImpl;
 };
 
 } // namespace nix
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.34.4/src/libstore/local-store.cc 
new/nix-2.34.5/src/libstore/local-store.cc
--- old/nix-2.34.4/src/libstore/local-store.cc  2026-03-25 22:29:36.000000000 
+0100
+++ new/nix-2.34.5/src/libstore/local-store.cc  2026-04-06 20:27:24.000000000 
+0200
@@ -1283,8 +1283,9 @@
     do {
         /* There is a slight possibility that `tmpDir' gets deleted by
            the GC between createTempDir() and when we acquire a lock on it.
-           We'll repeat until 'tmpDir' exists and we've locked it. */
-        tmpDirFn = 
createTempDir(std::filesystem::path{config->realStoreDir.get()}, "tmp");
+           We'll repeat until 'tmpDir' exists and we've locked it.
+           Make the directory accessible only to the current user. */
+        tmpDirFn = 
createTempDir(std::filesystem::path{config->realStoreDir.get()}, "tmp", 
/*mode=*/0700);
         tmpDirFd = openDirectory(tmpDirFn);
         if (!tmpDirFd) {
             continue;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.34.4/src/libstore/meson.build 
new/nix-2.34.5/src/libstore/meson.build
--- old/nix-2.34.4/src/libstore/meson.build     2026-03-25 22:29:36.000000000 
+0100
+++ new/nix-2.34.5/src/libstore/meson.build     2026-04-06 20:27:24.000000000 
+0200
@@ -79,6 +79,11 @@
   configdata_priv.set(define_name, define_value)
 endforeach
 
+if host_machine.system() == 'linux'
+  has_landlock = cxx.has_header('linux/landlock.h')
+  configdata_priv.set('HAVE_LANDLOCK', has_landlock.to_int())
+endif
+
 has_acl_support = cxx.has_header('sys/xattr.h') \
   and cxx.has_function('llistxattr') \
   and cxx.has_function('lremovexattr')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/nix-2.34.4/src/libstore/unix/build/derivation-builder.cc 
new/nix-2.34.5/src/libstore/unix/build/derivation-builder.cc
--- old/nix-2.34.4/src/libstore/unix/build/derivation-builder.cc        
2026-03-25 22:29:36.000000000 +0100
+++ new/nix-2.34.5/src/libstore/unix/build/derivation-builder.cc        
2026-04-06 20:27:24.000000000 +0200
@@ -1595,6 +1595,13 @@
         assert(output && scratchPath);
         auto actualPath = realPathInHost(store.printStorePath(*scratchPath));
 
+        /* An optional file descriptor of a directory used for intermediate
+           operations. */
+        AutoCloseFD tempDirFd;
+        /* RAII cleanup of a temporary directory inside the store that is used
+           for intermediate operations. */
+        AutoDelete delTempDir;
+
         auto finish = [&](StorePath finalStorePath) {
             /* Store the final path */
             finalOutputs.insert_or_assign(outputName, finalStorePath);
@@ -1742,6 +1749,25 @@
             return newInfo0;
         };
 
+        auto moveOutputToTempDir = [&]() -> void {
+            std::filesystem::path tempDir;
+            std::tie(tempDir, tempDirFd) = store.createTempDirInStore();
+            delTempDir = AutoDelete(tempDir);
+
+            auto tmpOutput = tempDir / "x";
+
+            /* Serialise and create a fresh copy of the output to break
+               any stale writable file descriptors. Copy through the
+               serialisation/deserialisation. TODO: Use copyRecursive here and
+               make use of reflinking. */
+            auto source = sinkToSource([&](Sink & nextSink) { 
dumpPath(actualPath, nextSink); });
+            restorePath(tmpOutput, *source, 
store.config->getLocalSettings().fsyncStorePaths);
+            /* This makes it slightly harder to make sense of the control 
flow. The rule
+               of thumb is that actualPath points to the current location of 
the stuff
+               that we'll end up registering. */
+            actualPath = std::move(tmpOutput);
+        };
+
         ValidPathInfo newInfo = std::visit(
             overloaded{
 
@@ -1769,14 +1795,7 @@
 
                 [&](const DerivationOutput::CAFixed & dof) {
                     auto & wanted = dof.ca.hash;
-
-                    // Replace the output by a fresh copy of itself to make 
sure
-                    // that there's no stale file descriptor pointing to it
-                    std::filesystem::path tmpOutput = actualPath.native() + 
".tmp";
-                    copyFile(actualPath, tmpOutput, true);
-
-                    std::filesystem::rename(tmpOutput, actualPath);
-
+                    moveOutputToTempDir();
                     return newInfoFromCA(
                         DerivationOutput::CAFloating{
                             .method = dof.ca.method,
@@ -1793,6 +1812,7 @@
                 },
 
                 [&](const DerivationOutput::Impure & doi) {
+                    moveOutputToTempDir();
                     return newInfoFromCA(
                         DerivationOutput::CAFloating{
                             .method = doi.method,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/nix-2.34.4/src/libstore/unix/build/linux-derivation-builder.cc 
new/nix-2.34.5/src/libstore/unix/build/linux-derivation-builder.cc
--- old/nix-2.34.4/src/libstore/unix/build/linux-derivation-builder.cc  
2026-03-25 22:29:36.000000000 +0100
+++ new/nix-2.34.5/src/libstore/unix/build/linux-derivation-builder.cc  
2026-04-06 20:27:24.000000000 +0200
@@ -1,5 +1,7 @@
 #ifdef __linux__
 
+#  include "store-config-private.hh"
+
 #  include "nix/store/globals.hh"
 #  include "nix/store/personality.hh"
 #  include "nix/store/filetransfer.hh"
@@ -9,6 +11,10 @@
 #  include "nix/util/serialise.hh"
 #  include "linux/fchmodat2-compat.hh"
 
+#  include <algorithm>
+#  include <string_view>
+#  include <cstdint>
+
 #  include <sys/ioctl.h>
 #  include <net/if.h>
 #  include <netinet/ip.h>
@@ -17,11 +23,16 @@
 #  include <sys/param.h>
 #  include <sys/mount.h>
 #  include <sys/syscall.h>
+#  include <sys/prctl.h>
 
 #  if HAVE_SECCOMP
 #    include <seccomp.h>
 #  endif
 
+#  if HAVE_LANDLOCK
+#    include <linux/landlock.h>
+#  endif
+
 #  define pivot_root(new_root, put_old) (syscall(SYS_pivot_root, new_root, 
put_old))
 
 namespace nix {
@@ -125,6 +136,77 @@
 #  endif
 }
 
+#  if HAVE_LANDLOCK && defined(LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET)
+
+#    define DO_LANDLOCK 1
+
+/* We are using LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET on best-effort basis. 
There are no glibc wrappers for now. */
+
+static int landlockCreateRuleset(const ::landlock_ruleset_attr * attr, 
std::size_t size, std::uint32_t flags)
+{
+    return ::syscall(__NR_landlock_create_ruleset, attr, size, flags);
+}
+
+static int landlockRestrictSelf(Descriptor rulesetFd, std::uint32_t flags)
+{
+    return ::syscall(__NR_landlock_restrict_self, rulesetFd, flags);
+}
+
+static int getLandlockAbiVersion()
+{
+    int abiVersion = landlockCreateRuleset(nullptr, 0, 
LANDLOCK_CREATE_RULESET_VERSION);
+    return abiVersion;
+}
+
+static void setupLandlock()
+{
+    bool landlockSupportsScopeAbstractUnixSocket = []() {
+        int abiVersion = getLandlockAbiVersion();
+        if (abiVersion >= 6)
+            /* All good, we can use LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET. See
+               
https://docs.kernel.org/userspace-api/landlock.html#abstract-unix-socket-abi-6 
*/
+            return true;
+
+        if (abiVersion == -1) {
+            debug("landlock is not available");
+            return false;
+        }
+
+        debug("landlock version %d does not support 
LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET", abiVersion);
+        return false;
+    }();
+
+    /* Bail out early if landlock is not enabled or 
LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET wouldn't work.
+       TODO: Consider adding more landlock rules for filesystem access as 
defense-in-depth on top. */
+    if (!landlockSupportsScopeAbstractUnixSocket)
+        return;
+
+    ::landlock_ruleset_attr attr = {
+        /* This prevents multiple FODs from communicating with each other
+           via abstract sockets. Note that cooperating processes outside the
+           sandbox can still connect to an abstract socket created by the FOD. 
To
+           mitigate that issue entirely we'd still need network namespaces. */
+        .scoped = LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET,
+    };
+
+    /* This better not fail - if the kernel reports a new enough ABI version we
+       should treat any errors as fatal from now on. */
+    AutoCloseFD rulesetFd = landlockCreateRuleset(&attr, sizeof(attr), 0);
+    if (!rulesetFd)
+        throw SysError("failed to create a landlock ruleset");
+
+    if (landlockRestrictSelf(rulesetFd.get(), 0) == -1)
+        throw SysError("failed to apply landlock");
+
+    debug("applied landlock sandboxing");
+}
+
+#  else
+
+#    define DO_LANDLOCK 0
+
+#  endif
+
 static void doBind(const std::filesystem::path & source, const 
std::filesystem::path & target, bool optional = false)
 {
     debug("bind mounting %1% to %2%", PathFmt(source), PathFmt(target));
@@ -165,8 +247,27 @@
     {
         auto & localSettings = store.config->getLocalSettings();
 
+        /* Set the NO_NEW_PRIVS before doing seccomp/landlock setup.
+           landlock_restrict_self requires either NO_NEW_PRIVS or 
CAP_SYS_ADMIN.
+           With user namespaces we do get CAP_SYS_ADMIN. */
+        if (!localSettings.allowNewPrivileges)
+            if (::prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
+                throw SysError("failed to set PR_SET_NO_NEW_PRIVS");
+
         setupSeccomp(localSettings);
 
+#  if DO_LANDLOCK
+        try {
+            setupLandlock();
+        } catch (SysError & e) {
+            if (e.errNo != EPERM)
+                throw;
+            /* If allowNewPrivileges is true and we don't have CAP_SYS_ADMIN
+               this code path might be hit. */
+            warn("setting up landlock: %s", e.message());
+        }
+#  endif
+
         linux::setPersonality({
             .system = drv.platform,
             .impersonateLinux26 = localSettings.impersonateLinux26,
@@ -760,4 +861,6 @@
 
 } // namespace nix
 
+#  undef DO_LANDLOCK
+
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/nix-2.34.4/tests/functional/local-overlay-store/stale-file-handle-inner.sh 
new/nix-2.34.5/tests/functional/local-overlay-store/stale-file-handle-inner.sh
--- 
old/nix-2.34.4/tests/functional/local-overlay-store/stale-file-handle-inner.sh  
    2026-03-25 22:29:36.000000000 +0100
+++ 
new/nix-2.34.5/tests/functional/local-overlay-store/stale-file-handle-inner.sh  
    2026-04-06 20:27:24.000000000 +0200
@@ -36,8 +36,12 @@
     buildInStore "$storeB"
 }
 
-# Without remounting, we should encounter errors
-expectStderr 1 triggerStaleFileHandle | grepQuiet 'Stale file handle'
+# Without remounting, we should encounter errors.  However, this doesn't seem 
to
+# happen on Linux 6.19+ anymore.
+#
+# See https://github.com/NixOS/nixpkgs/issues/496466
+( expectStderr 1 triggerStaleFileHandle | grepQuiet 'Stale file handle' ) || \
+    skipTest "Couldn't trigger the error"
 
 # Configure remount-hook and reset OverlayFS
 storeB="$storeB&remount-hook=$PWD/remount.sh"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.34.4/tests/nixos/ca-fd-leak/default.nix 
new/nix-2.34.5/tests/nixos/ca-fd-leak/default.nix
--- old/nix-2.34.4/tests/nixos/ca-fd-leak/default.nix   2026-03-25 
22:29:36.000000000 +0100
+++ new/nix-2.34.5/tests/nixos/ca-fd-leak/default.nix   2026-04-06 
20:27:24.000000000 +0200
@@ -78,7 +78,7 @@
 
       # Build the smuggled derivation.
       # This will connect to the smuggler server and send it the file 
descriptor
-      machine.succeed(r"""
+      sender_output = machine.succeed(r"""
         nix-build -E '
           builtins.derivation {
             name = "smuggled";
@@ -89,9 +89,13 @@
             outputHash = builtins.hashString "sha256" "hello, world\n";
             builder = "${pkgs.busybox-sandbox-shell}/bin/sh";
             args = [ "-c" "echo \"hello, world\" > $out; ''${${sender}} 
${socketName}" ];
-        }'
+        }' 2>&1
       """.strip())
 
+      # Landlock's LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET prevents a sandboxed 
process
+      # from connecting to an abstract socket created in an unrelated landlock 
domain.
+      # There's no such flag for preventing inbound connections.
+      assert "connect: Operation not permitted" in sender_output
 
       # Tell the smuggler server that we're done
       machine.execute("echo done | ${pkgs.socat}/bin/socat - 
ABSTRACT-CONNECT:${socketName}")

Reply via email to