Squashed 'src/ipc/libmultiprocess/' changes from b4120d34bad2..1b8d4a6f1e54
What changed, and why it matters
This commit updates the libmultiprocess subtree used by Bitcoin Core. The most notable change is a build-time guard that refuses to compile against specific old versions of the Cap'n Proto library because those versions contain a known memory-access vulnerability (CVE-2022-46149). The commit also adds CI testing for older Cap'n Proto versions and OpenBSD, fixes a C++20/Cap'n Proto 0.8 compatibility issue in the code generator, removes an obsolete linker flag, and adds a missing include. It is primarily a hardening and compatibility update, not a fix for a new vulnerability in Bitcoin Core itself.
No immediate action is required for Bitcoin Core users; the change is defensive. Builders and packagers should ensure Cap'n Proto is not one of the blocked vulnerable versions (0.7.0, 0.8.0, 0.9.0, 0.9.1, 0.10.0, 0.10.1, 0.10.2). Downstream maintainers may want to verify their Cap'n Proto package version and consider the new minimum version requirement (0.7).
Security signals we found
Build-time rejection of dependency versions known to be vulnerable to CVE-2022-46149
New CI job (olddeps) to ensure compatibility with patched older Cap'n Proto releases
C++20 compatibility fixes that prevent ambiguous operator== comparisons involving kj::StringPtr and string literals
Addition of missing <thread> header include
Evidence from the diff
The squashed subtree update pulls in several libmultiprocess changes. The security-relevant change is in CMakeLists.txt: it now requires Cap’n Proto >= 0.7.0 and explicitly FATAL_ERRORs at configure time for versions 0.7.0, 0.8.0, 0.9.0-0.9.1, and 0.10.0-0.10.2, all affected by CVE-2022-46149 (out-of-bounds memory access in pointer lists). A new olddeps CI job tests against Cap’n Proto 0.7.1 (a patched version). Other changes include OpenBSD CI, a C++20 spaceship-operator compatibility patch for older Cap’n Proto, removal of -lstdc++fs, a missing
Changed components
src/ipc/libmultiprocess (subtree)libmultiprocess CMake build configurationlibmultiprocess code generator (mpgen / src/mp/gen.cpp)libmultiprocess utility code (src/mp/util.cpp)libmultiprocess example build (example/CMakeLists.txt)libmultiprocess CI workflowsInspect captured patch +128 / −11
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 2e751c5f..55bab53b 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -5,18 +5,47 @@ on:
pull_request:
jobs:
+ build-openbsd:
+ runs-on: ubuntu-latest
+ name: build • openbsd
+ defaults:
+ run:
+ shell: openbsd {0}
+ steps:
+ - uses: actions/checkout@v5
+
+ - name: Start OpenBSD VM
+ uses: vmactions/openbsd-vm@v1
+ with:
+ prepare: |
+ pkg_add -v cmake ninja git python bash
+ run: |
+ git clone --depth=1 https://codeberg.org/OpenBSD/ports.git /usr/ports
+ sync: 'rsync'
+ copyback: false
+
+ - name: Install capnproto
+ run: |
+ cd /usr/ports/devel/capnproto/
+ make install
+
+ - name: Run CI script
+ run: |
+ cd ${{ github.workspace }}
+ CI_CONFIG="ci/configs/openbsd.bash" bash ci/scripts/ci.sh
+
build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
- config: [default, llvm, gnu32, sanitize]
+ config: [default, llvm, gnu32, sanitize, olddeps]
name: build • ${{ matrix.config }}
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- name: Install Nix
uses: cachix/install-nix-action@v31 # 2025-05-27, from https://github.com/cachix/install-nix-action/tags
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d29eb490..ef694412 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -12,8 +12,29 @@ endif()
include("cmake/compat_find.cmake")
-find_package(CapnProto REQUIRED)
find_package(Threads REQUIRED)
+find_package(CapnProto 0.7 REQUIRED)
+
+# Check for list-of-pointers memory access bug from Nov 2022
+# https://nvd.nist.gov/vuln/detail/CVE-2022-46149
+# https://github.com/advisories/GHSA-qqff-4vw4-f6hx
+# https://github.com/capnproto/capnproto/security/advisories/GHSA-qqff-4vw4-f6hx
+# https://github.com/capnproto/capnproto/blob/master/security-advisories/2022-11-30-0-pointer-list-bounds.md
+# https://capnproto.org/news/2022-11-30-CVE-2022-46149-security-advisory.html
+# https://dwrensha.github.io/capnproto-rust/2022/11/30/out_of_bounds_memory_access_bug.html
+if(CapnProto_VERSION STREQUAL "0.7.0"
+ OR CapnProto_VERSION STREQUAL "0.8.0"
+ OR CapnProto_VERSION STREQUAL "0.9.0"
+ OR CapnProto_VERSION STREQUAL "0.9.1"
+ OR CapnProto_VERSION STREQUAL "0.10.0"
+ OR CapnProto_VERSION STREQUAL "0.10.1"
+ OR CapnProto_VERSION STREQUAL "0.10.2")
+ message(FATAL_ERROR
+ "Cap'n Proto ${CapnProto_VERSION} is affected by CVE-2022-46149.\n"
+ "Please install an updated package.\n"
+ "Details: https://github.com/advisories/GHSA-qqff-4vw4-f6hx
+ ")
+endif()
set(MPGEN_EXECUTABLE "" CACHE FILEPATH "If specified, should be full path to an external mpgen binary to use rather than the one built internally.")
diff --git a/ci/README.md b/ci/README.md
index 85eb467c..2ddaa9e1 100644
--- a/ci/README.md
+++ b/ci/README.md
@@ -20,6 +20,7 @@ CI_CONFIG=ci/configs/default.bash ci/scripts/run.sh
CI_CONFIG=ci/configs/llvm.bash ci/scripts/run.sh
CI_CONFIG=ci/configs/gnu32.bash ci/scripts/run.sh
CI_CONFIG=ci/configs/sanitize.bash ci/scripts/run.sh
+CI_CONFIG=ci/configs/olddeps.bash ci/scripts/run.sh
```
By default CI jobs will reuse their build directories. `CI_CLEAN=1` can be specified to delete them before running instead.
diff --git a/ci/configs/olddeps.bash b/ci/configs/olddeps.bash
new file mode 100644
index 00000000..4684bd58
--- /dev/null
+++ b/ci/configs/olddeps.bash
@@ -0,0 +1,5 @@
+CI_DESC="CI job using old Cap'n Proto version"
+CI_DIR=build-olddeps
+export CXXFLAGS="-Werror -Wall -Wextra -Wpedantic -Wno-unused-parameter -Wno-error=array-bounds"
+NIX_ARGS=(--argstr capnprotoVersion "0.7.1")
+BUILD_ARGS=(-k)
diff --git a/ci/configs/openbsd.bash b/ci/configs/openbsd.bash
new file mode 100644
index 00000000..a404e2bc
--- /dev/null
+++ b/ci/configs/openbsd.bash
@@ -0,0 +1,5 @@
+CI_DESC="CI config for OpenBSD"
+CI_DIR=build-openbsd
+export CXXFLAGS="-Werror -Wall -Wextra -Wpedantic -Wno-unused-parameter"
+CMAKE_ARGS=(-G Ninja)
+BUILD_ARGS=(-k 0)
diff --git a/ci/patches/spaceship.patch b/ci/patches/spaceship.patch
new file mode 100644
index 00000000..08a885dd
--- /dev/null
+++ b/ci/patches/spaceship.patch
@@ -0,0 +1,29 @@
+commit e3da7da967b94f373c29a198ce45f30fb9f0e517
+Author: Ed Catmur <ed@catmur.uk>
+Date: Tue Jan 31 16:27:04 2023 +0000
+
+ Remove operator!= synthesized by spaceship
+
+ An operator!= suppresses the reversed equality comparison candidate generation.
+
+ This is visible in clang 16 (rc0 just released) and in gcc trunk (so probably gcc 13).
+
+diff --git a/c++/src/kj/string.h b/c++/src/kj/string.h
+index 193442aa..17835892 100644
+--- a/c++/src/kj/string.h
++++ b/c++/src/kj/string.h
+@@ -122,10 +122,14 @@ public:
+ inline constexpr const char* end() const { return content.end() - 1; }
+
+ inline constexpr bool operator==(decltype(nullptr)) const { return content.size() <= 1; }
++#if !__cpp_impl_three_way_comparison
+ inline constexpr bool operator!=(decltype(nullptr)) const { return content.size() > 1; }
++#endif
+
+ inline bool operator==(const StringPtr& other) const;
++#if !__cpp_impl_three_way_comparison
+ inline bool operator!=(const StringPtr& other) const { return !(*this == other); }
++#endif
+ inline bool operator< (const StringPtr& other) const;
+ inline bool operator> (const StringPtr& other) const { return other < *this; }
+ inline bool operator<=(const StringPtr& other) const { return !(other < *this); }
diff --git a/doc/install.md b/doc/install.md
index 3fe7c7b2..ac2f7f6a 100644
--- a/doc/install.md
+++ b/doc/install.md
@@ -1,6 +1,6 @@
# libmultiprocess Installation
-Installation currently requires Cap'n Proto:
+Installation currently requires Cap'n Proto 0.7 or higher:
```sh
apt install libcapnp-dev capnproto
diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt
index 0e758d57..7da049c3 100644
--- a/example/CMakeLists.txt
+++ b/example/CMakeLists.txt
@@ -24,6 +24,5 @@ add_executable(mpexample
target_capnp_sources(mpexample ${CMAKE_CURRENT_SOURCE_DIR} init.capnp calculator.capnp printer.capnp)
target_include_directories(mpexample PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(mpexample PRIVATE Threads::Threads)
-target_link_libraries(mpexample PRIVATE stdc++fs)
add_custom_target(mpexamples DEPENDS mpexample mpcalculator mpprinter)
diff --git a/shell.nix b/shell.nix
index eacfdc2a..0b7dce89 100644
--- a/shell.nix
+++ b/shell.nix
@@ -2,12 +2,39 @@
, crossPkgs ? import <nixpkgs> {}
, enableLibcxx ? false # Whether to use libc++ toolchain and libraries instead of libstdc++
, minimal ? false # Whether to create minimal shell without extra tools (faster when cross compiling)
+, capnprotoVersion ? null
}:
let
lib = pkgs.lib;
llvm = crossPkgs.llvmPackages_20;
- capnproto = crossPkgs.capnproto.override (lib.optionalAttrs enableLibcxx { clangStdenv = llvm.libcxxStdenv; });
+ capnprotoHashes = {
+ "0.7.0" = "sha256-Y/7dUOQPDHjniuKNRw3j8dG1NI9f/aRWpf8V0WzV9k8=";
+ "0.7.1" = "sha256-3cBpVmpvCXyqPUXDp12vCFCk32ZXWpkdOliNH37UwWE=";
+ "0.8.0" = "sha256-rfiqN83begjJ9eYjtr21/tk1GJBjmeVfa3C3dZBJ93w=";
+ "0.8.1" = "sha256-OZqNVYdyszro5rIe+w6YN00g6y8U/1b8dKYc214q/2o=";
+ "0.9.0" = "sha256-yhbDcWUe6jp5PbIXzn5EoKabXiWN8lnS08hyfxUgEQ0=";
+ "0.9.2" = "sha256-BspWOPZcP5nCTvmsDE62Zutox+aY5pw42d6hpH3v4cM=";
+ "0.10.0" = "sha256-++F4l54OMTDnJ+FO3kV/Y/VLobKVRk461dopanuU3IQ=";
+ "0.10.4" = "sha256-45sxnVyyYIw9i3sbFZ1naBMoUzkpP21WarzR5crg4X8=";
+ "1.0.0" = "sha256-NLTFJdeOzqhk4ATvkc17Sh6g/junzqYBBEoXYGH/czo=";
+ "1.0.2" = "sha256-LVdkqVBTeh8JZ1McdVNtRcnFVwEJRNjt0JV2l7RkuO8=";
+ "1.1.0" = "sha256-gxkko7LFyJNlxpTS+CWOd/p9x/778/kNIXfpDGiKM2A=";
+ "1.2.0" = "sha256-aDcn4bLZGq8915/NPPQsN5Jv8FRWd8cAspkG3078psc=";
+ };
+ capnprotoBase = if capnprotoVersion == null then crossPkgs.capnproto else crossPkgs.capnproto.overrideAttrs (old: {
+ version = capnprotoVersion;
+ src = crossPkgs.fetchFromGitHub {
+ owner = "capnproto";
+ repo = "capnproto";
+ rev = "v${capnprotoVersion}";
+ hash = lib.attrByPath [capnprotoVersion] "" capnprotoHashes;
+ };
+ patches = lib.optionals (lib.versionAtLeast capnprotoVersion "0.9.0" && lib.versionOlder capnprotoVersion "0.10.4") [ ./ci/patches/spaceship.patch ];
+ } // (lib.optionalAttrs (lib.versionOlder capnprotoVersion "0.10") {
+ env = { }; # Drop -std=c++20 flag forced by nixpkgs
+ }));
+ capnproto = capnprotoBase.override (lib.optionalAttrs enableLibcxx { clangStdenv = llvm.libcxxStdenv; });
clang = if enableLibcxx then llvm.libcxxClang else llvm.clang;
clang-tools = llvm.clang-tools.override { inherit enableLibcxx; };
in crossPkgs.mkShell {
diff --git a/src/mp/gen.cpp b/src/mp/gen.cpp
index 21a4d931..18400710 100644
--- a/src/mp/gen.cpp
+++ b/src/mp/gen.cpp
@@ -146,7 +146,7 @@ static void Generate(kj::StringPtr src_prefix,
const std::vector<kj::Own<const kj::ReadableDirectory>>& import_dirs)
{
std::string output_path;
- if (src_prefix == ".") {
+ if (src_prefix == kj::StringPtr{"."}) {
output_path = src_file;
} else if (!src_file.startsWith(src_prefix) || src_file.size() <= src_prefix.size() ||
src_file[src_prefix.size()] != '/') {
@@ -156,7 +156,7 @@ static void Generate(kj::StringPtr src_prefix,
}
std::string include_path;
- if (include_prefix == ".") {
+ if (include_prefix == kj::StringPtr{"."}) {
include_path = src_file;
} else if (!src_file.startsWith(include_prefix) || src_file.size() <= include_prefix.size() ||
src_file[include_prefix.size()] != '/') {
@@ -425,8 +425,8 @@ static void Generate(kj::StringPtr src_prefix,
const std::string method_prefix = Format() << message_namespace << "::" << method_interface.getShortDisplayName()
<< "::" << Cap(method_name);
- const bool is_construct = method_name == "construct";
- const bool is_destroy = method_name == "destroy";
+ const bool is_construct = method_name == kj::StringPtr{"construct"};
+ const bool is_destroy = method_name == kj::StringPtr{"destroy"};
struct Field
{
@@ -465,7 +465,7 @@ static void Generate(kj::StringPtr src_prefix,
field.result_is_set = true;
}
- if (!param && field_name == "result") {
+ if (!param && field_name == kj::StringPtr{"result"}) {
field.retval = true;
has_result = true;
}
diff --git a/src/mp/util.cpp b/src/mp/util.cpp
index a9485399..da7c3b0b 100644
--- a/src/mp/util.cpp
+++ b/src/mp/util.cpp
@@ -16,6 +16,7 @@
#include <sys/socket.h>
#include <sys/wait.h>
#include <system_error>
+#include <thread> // NOLINT(misc-include-cleaner) // IWYU pragma: keep
#include <unistd.h>
#include <utility>
#include <vector>
Why this scored 25/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.