From 2fe629c5d49ef9ab7de9ea43f3b5ecd871ccb4e7 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 3 Sep 2025 15:32:56 +0200 Subject: [PATCH 1/2] Fix deadlock in SSHMaster::addCommonSSHOpts() When useMaster is true, startMaster() acquires the state lock, then calls isMasterRunning(), which calls addCommonSSHOpts(), which tries to acquire the state lock again, causing a deadlock. The solution is to move tmpDir out of the state. It doesn't need to be there in the first place because it never changes. --- src/libstore/include/nix/store/ssh.hh | 4 +++- src/libstore/ssh.cc | 9 +++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/libstore/include/nix/store/ssh.hh b/src/libstore/include/nix/store/ssh.hh index c7228464b..7e27a0d3e 100644 --- a/src/libstore/include/nix/store/ssh.hh +++ b/src/libstore/include/nix/store/ssh.hh @@ -1,6 +1,7 @@ #pragma once ///@file +#include "nix/util/ref.hh" #include "nix/util/sync.hh" #include "nix/util/url.hh" #include "nix/util/processes.hh" @@ -26,12 +27,13 @@ private: const bool compress; const Descriptor logFD; + ref tmpDir; + struct State { #ifndef _WIN32 // TODO re-enable on Windows, once we can start processes. Pid sshMaster; #endif - std::unique_ptr tmpDir; Path socketPath; }; diff --git a/src/libstore/ssh.cc b/src/libstore/ssh.cc index 8a4614a0d..0f1dba1e9 100644 --- a/src/libstore/ssh.cc +++ b/src/libstore/ssh.cc @@ -84,23 +84,20 @@ SSHMaster::SSHMaster( , useMaster(useMaster && !fakeSSH) , compress(compress) , logFD(logFD) + , tmpDir(make_ref(createTempDir("", "nix", 0700))) { checkValidAuthority(authority); - auto state(state_.lock()); - state->tmpDir = std::make_unique(createTempDir("", "nix", 0700)); } void SSHMaster::addCommonSSHOpts(Strings & args) { - auto state(state_.lock()); - auto sshArgs = getNixSshOpts(); args.insert(args.end(), sshArgs.begin(), sshArgs.end()); if (!keyFile.empty()) args.insert(args.end(), {"-i", keyFile}); if (!sshPublicHostKey.empty()) { - std::filesystem::path fileName = state->tmpDir->path() / "host-key"; + std::filesystem::path fileName = tmpDir->path() / "host-key"; writeFile(fileName.string(), authority.host + " " + sshPublicHostKey + "\n"); args.insert(args.end(), {"-oUserKnownHostsFile=" + fileName.string()}); } @@ -241,7 +238,7 @@ Path SSHMaster::startMaster() if (state->sshMaster != INVALID_DESCRIPTOR) return state->socketPath; - state->socketPath = (Path) *state->tmpDir + "/ssh.sock"; + state->socketPath = (Path) *tmpDir + "/ssh.sock"; Pipe out; out.create(); From c7603c61c8052b47ab7cc5be327cca3f573a5330 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 3 Sep 2025 20:16:39 +0200 Subject: [PATCH 2/2] Mark tmpDir as const --- src/libstore/include/nix/store/ssh.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstore/include/nix/store/ssh.hh b/src/libstore/include/nix/store/ssh.hh index 7e27a0d3e..574cb5cf4 100644 --- a/src/libstore/include/nix/store/ssh.hh +++ b/src/libstore/include/nix/store/ssh.hh @@ -27,7 +27,7 @@ private: const bool compress; const Descriptor logFD; - ref tmpDir; + const ref tmpDir; struct State {