1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-08 19:46:02 +01:00

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.
This commit is contained in:
Eelco Dolstra 2025-09-03 15:32:56 +02:00
parent 1935c19705
commit 2fe629c5d4
2 changed files with 6 additions and 7 deletions

View file

@ -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<AutoDelete> tmpDir;
struct State
{
#ifndef _WIN32 // TODO re-enable on Windows, once we can start processes.
Pid sshMaster;
#endif
std::unique_ptr<AutoDelete> tmpDir;
Path socketPath;
};

View file

@ -84,23 +84,20 @@ SSHMaster::SSHMaster(
, useMaster(useMaster && !fakeSSH)
, compress(compress)
, logFD(logFD)
, tmpDir(make_ref<AutoDelete>(createTempDir("", "nix", 0700)))
{
checkValidAuthority(authority);
auto state(state_.lock());
state->tmpDir = std::make_unique<AutoDelete>(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();