1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-09 12:06:01 +01:00

Merge pull request #14110 from Mic92/ptsname

Fix thread-safety issue with ptsname() usage
This commit is contained in:
Jörg Thalheim 2025-09-29 13:49:58 +02:00 committed by GitHub
commit b6f4788a8f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 39 additions and 3 deletions

View file

@ -18,6 +18,7 @@
#include "nix/store/user-lock.hh" #include "nix/store/user-lock.hh"
#include "nix/store/globals.hh" #include "nix/store/globals.hh"
#include "nix/store/build/derivation-env-desugar.hh" #include "nix/store/build/derivation-env-desugar.hh"
#include "nix/util/terminal.hh"
#include <queue> #include <queue>
@ -808,8 +809,7 @@ std::optional<Descriptor> DerivationBuilderImpl::startBuild()
if (!builderOut) if (!builderOut)
throw SysError("opening pseudoterminal master"); throw SysError("opening pseudoterminal master");
// FIXME: not thread-safe, use ptsname_r std::string slaveName = getPtsName(builderOut.get());
std::string slaveName = ptsname(builderOut.get());
if (buildUser) { if (buildUser) {
if (chmod(slaveName.c_str(), 0600)) if (chmod(slaveName.c_str(), 0600))
@ -923,7 +923,7 @@ void DerivationBuilderImpl::prepareSandbox()
void DerivationBuilderImpl::openSlave() void DerivationBuilderImpl::openSlave()
{ {
std::string slaveName = ptsname(builderOut.get()); std::string slaveName = getPtsName(builderOut.get());
AutoCloseFD builderOut = open(slaveName.c_str(), O_RDWR | O_NOCTTY); AutoCloseFD builderOut = open(slaveName.c_str(), O_RDWR | O_NOCTTY);
if (!builderOut) if (!builderOut)

View file

@ -36,4 +36,12 @@ void updateWindowSize();
*/ */
std::pair<unsigned short, unsigned short> getWindowSize(); std::pair<unsigned short, unsigned short> getWindowSize();
/**
* Get the slave name of a pseudoterminal in a thread-safe manner.
*
* @param fd The file descriptor of the pseudoterminal master
* @return The slave device name as a string
*/
std::string getPtsName(int fd);
} // namespace nix } // namespace nix

View file

@ -1,6 +1,7 @@
#include "nix/util/terminal.hh" #include "nix/util/terminal.hh"
#include "nix/util/environment-variables.hh" #include "nix/util/environment-variables.hh"
#include "nix/util/sync.hh" #include "nix/util/sync.hh"
#include "nix/util/error.hh"
#ifdef _WIN32 #ifdef _WIN32
# include <io.h> # include <io.h>
@ -12,6 +13,8 @@
#endif #endif
#include <unistd.h> #include <unistd.h>
#include <widechar_width.h> #include <widechar_width.h>
#include <mutex>
#include <cstdlib> // for ptsname and ptsname_r
namespace { namespace {
@ -176,4 +179,29 @@ std::pair<unsigned short, unsigned short> getWindowSize()
return *windowSize.lock(); return *windowSize.lock();
} }
std::string getPtsName(int fd)
{
#ifdef __APPLE__
static std::mutex ptsnameMutex;
// macOS doesn't have ptsname_r, use mutex-protected ptsname
std::lock_guard<std::mutex> lock(ptsnameMutex);
const char * name = ptsname(fd);
if (!name) {
throw SysError("getting pseudoterminal slave name");
}
return name;
#else
// Use thread-safe ptsname_r on platforms that support it
// PTY names are typically short:
// - Linux: /dev/pts/N (where N is usually < 1000)
// - FreeBSD: /dev/pts/N
// 64 bytes is more than sufficient for any Unix PTY name
char buf[64];
if (ptsname_r(fd, buf, sizeof(buf)) != 0) {
throw SysError("getting pseudoterminal slave name");
}
return buf;
#endif
}
} // namespace nix } // namespace nix