ipc, refactor: Update mp::SpawnProcess call
What changed, and why it matters
This is a routine code refactor in Bitcoin Core's inter-process communication (IPC) layer. It updates how child processes are launched so the code can work with a future version of a supporting library that adds Microsoft Windows support. The change replaces an older function call with a newer one and adjusts how the child process receives its communication socket identifier. There is no indication this fixes a security vulnerability.
No security action required. Treat as a normal dependency-compatibility refactor. Reviewers may optionally verify that the new StartSpawned validation preserves prior error behavior and that the wrapper correctly propagates the socket descriptor.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit refactors the mp::SpawnProcess call in src/ipc/process.cpp, src/ipc/interfaces.cpp, src/ipc/process.h, and src/ipc/util.h. Previously, spawn() returned a SocketId and wrote a ProcessId via an out-parameter. The new API returns a std::tuple
Changed components
src/ipc/interfaces.cppsrc/ipc/process.cppsrc/ipc/process.hsrc/ipc/util.hInspect captured patch +28 / −11
diff --git a/src/ipc/interfaces.cpp b/src/ipc/interfaces.cpp
index 75a854c2..40cddb4b 100644
--- a/src/ipc/interfaces.cpp
+++ b/src/ipc/interfaces.cpp
@@ -62,10 +62,9 @@ public:
}
std::unique_ptr<interfaces::Init> spawnProcess(const char* new_exe_name) override
{
- mp::ProcessId pid;
- mp::SocketId fd = m_process->spawn(new_exe_name, m_process_argv0, pid);
+ const auto [pid, socket] = m_process->spawn(new_exe_name, m_process_argv0);
LogDebug(::BCLog::IPC, "Process %s pid %i launched\n", new_exe_name, pid);
- auto init = m_protocol->connect(m_protocol->makeStream(fd));
+ auto init = m_protocol->connect(m_protocol->makeStream(socket));
Ipc::addCleanup(*init, [this, new_exe_name, pid] {
int status = m_process->waitSpawned(pid);
LogDebug(::BCLog::IPC, "Process %s pid %i exited with status %i\n", new_exe_name, pid, status);
diff --git a/src/ipc/process.cpp b/src/ipc/process.cpp
index d7f04078..a9aa47ae 100644
--- a/src/ipc/process.cpp
+++ b/src/ipc/process.cpp
@@ -32,13 +32,13 @@ namespace {
class ProcessImpl : public Process
{
public:
- mp::SocketId spawn(const std::string& new_exe_name, const fs::path& argv0_path, mp::ProcessId& pid) override
+ std::tuple<mp::ProcessId, mp::SocketId> spawn(const std::string& new_exe_name, const fs::path& argv0_path) override
{
- return mp::SpawnProcess(pid, [&](int fd) {
+ return mp::SpawnProcess([&](std::string connect_info) {
fs::path path = argv0_path;
path.remove_filename();
path /= fs::PathFromString(new_exe_name);
- return std::vector<std::string>{fs::PathToString(path), "-ipcfd", strprintf("%i", fd)};
+ return std::vector<std::string>{fs::PathToString(path), "-ipcfd", std::move(connect_info)};
});
}
int waitSpawned(mp::ProcessId pid) override { return mp::WaitProcess(pid); }
@@ -56,11 +56,11 @@ public:
// in combination with other arguments because the parent process
// should be able to control the child process through the IPC protocol
// without passing information out of band.
- const auto maybe_fd{ToIntegral<int32_t>(argv[2])};
- if (!maybe_fd) {
- throw std::runtime_error(strprintf("Invalid -ipcfd number '%s'", argv[2]));
+ try {
+ socket = mp::StartSpawned(argv[2]);
+ } catch (const std::exception& e) {
+ throw std::runtime_error(strprintf("Invalid -ipcfd number '%s' (%s)", argv[2], e.what()));
}
- socket = *maybe_fd;
return true;
}
mp::SocketId connect(const fs::path& data_dir,
diff --git a/src/ipc/process.h b/src/ipc/process.h
index 54ca204c..ac597cb0 100644
--- a/src/ipc/process.h
+++ b/src/ipc/process.h
@@ -25,7 +25,7 @@ public:
virtual ~Process() = default;
//! Spawn process and return socket id for communicating with it.
- virtual mp::SocketId spawn(const std::string& new_exe_name, const fs::path& argv0_path, mp::ProcessId& pid) = 0;
+ virtual std::tuple<mp::ProcessId, mp::SocketId> spawn(const std::string& new_exe_name, const fs::path& argv0_path) = 0;
//! Wait for spawned process to exit and return its exit code.
virtual int waitSpawned(mp::ProcessId pid) = 0;
diff --git a/src/ipc/util.h b/src/ipc/util.h
index ec36b418..3fd3ff16 100644
--- a/src/ipc/util.h
+++ b/src/ipc/util.h
@@ -5,8 +5,12 @@
#ifndef BITCOIN_IPC_UTIL_H
#define BITCOIN_IPC_UTIL_H
+#include <tinyformat.h>
+#include <util/strencodings.h>
+
#include <array>
#include <cstdint>
+#include <functional>
#include <kj/debug.h>
#include <mp/util.h>
#include <mp/version.h>
@@ -34,6 +38,20 @@ inline std::array<SocketId, 2> SocketPair()
KJ_SYSCALL(socketpair(AF_UNIX, SOCK_STREAM, 0, pair));
return {pair[0], pair[1]};
}
+
+inline std::tuple<ProcessId, SocketId> SpawnProcess(const std::function<std::vector<std::string>(std::string)>& spawn_argv)
+{
+ ProcessId pid;
+ SocketId socket = SpawnProcess(pid, [&](int fd) { return spawn_argv(strprintf("%d", fd)); });
+ return {pid, socket};
+}
+
+inline SocketId StartSpawned(const std::string& connect_info)
+{
+ auto socket = ToIntegral<SocketId>(connect_info);
+ if (!socket) throw std::invalid_argument(strprintf("Invalid socket descriptor '%s'", connect_info));
+ return *socket;
+}
#endif
} // namespace mp
Why this scored 12/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.