Skip to content

Commit b6f4788

Browse files
authored
Merge pull request #14110 from Mic92/ptsname
Fix thread-safety issue with ptsname() usage
2 parents f816b9b + a9ffa42 commit b6f4788

File tree

3 files changed

+39
-3
lines changed

3 files changed

+39
-3
lines changed

src/libstore/unix/build/derivation-builder.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "nix/store/user-lock.hh"
1919
#include "nix/store/globals.hh"
2020
#include "nix/store/build/derivation-env-desugar.hh"
21+
#include "nix/util/terminal.hh"
2122

2223
#include <queue>
2324

@@ -808,8 +809,7 @@ std::optional<Descriptor> DerivationBuilderImpl::startBuild()
808809
if (!builderOut)
809810
throw SysError("opening pseudoterminal master");
810811

811-
// FIXME: not thread-safe, use ptsname_r
812-
std::string slaveName = ptsname(builderOut.get());
812+
std::string slaveName = getPtsName(builderOut.get());
813813

814814
if (buildUser) {
815815
if (chmod(slaveName.c_str(), 0600))
@@ -923,7 +923,7 @@ void DerivationBuilderImpl::prepareSandbox()
923923

924924
void DerivationBuilderImpl::openSlave()
925925
{
926-
std::string slaveName = ptsname(builderOut.get());
926+
std::string slaveName = getPtsName(builderOut.get());
927927

928928
AutoCloseFD builderOut = open(slaveName.c_str(), O_RDWR | O_NOCTTY);
929929
if (!builderOut)

src/libutil/include/nix/util/terminal.hh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,12 @@ void updateWindowSize();
3636
*/
3737
std::pair<unsigned short, unsigned short> getWindowSize();
3838

39+
/**
40+
* Get the slave name of a pseudoterminal in a thread-safe manner.
41+
*
42+
* @param fd The file descriptor of the pseudoterminal master
43+
* @return The slave device name as a string
44+
*/
45+
std::string getPtsName(int fd);
46+
3947
} // namespace nix

src/libutil/terminal.cc

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "nix/util/terminal.hh"
22
#include "nix/util/environment-variables.hh"
33
#include "nix/util/sync.hh"
4+
#include "nix/util/error.hh"
45

56
#ifdef _WIN32
67
# include <io.h>
@@ -12,6 +13,8 @@
1213
#endif
1314
#include <unistd.h>
1415
#include <widechar_width.h>
16+
#include <mutex>
17+
#include <cstdlib> // for ptsname and ptsname_r
1518

1619
namespace {
1720

@@ -176,4 +179,29 @@ std::pair<unsigned short, unsigned short> getWindowSize()
176179
return *windowSize.lock();
177180
}
178181

182+
std::string getPtsName(int fd)
183+
{
184+
#ifdef __APPLE__
185+
static std::mutex ptsnameMutex;
186+
// macOS doesn't have ptsname_r, use mutex-protected ptsname
187+
std::lock_guard<std::mutex> lock(ptsnameMutex);
188+
const char * name = ptsname(fd);
189+
if (!name) {
190+
throw SysError("getting pseudoterminal slave name");
191+
}
192+
return name;
193+
#else
194+
// Use thread-safe ptsname_r on platforms that support it
195+
// PTY names are typically short:
196+
// - Linux: /dev/pts/N (where N is usually < 1000)
197+
// - FreeBSD: /dev/pts/N
198+
// 64 bytes is more than sufficient for any Unix PTY name
199+
char buf[64];
200+
if (ptsname_r(fd, buf, sizeof(buf)) != 0) {
201+
throw SysError("getting pseudoterminal slave name");
202+
}
203+
return buf;
204+
#endif
205+
}
206+
179207
} // namespace nix

0 commit comments

Comments
 (0)