Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
strategy:
fail-fast: false
matrix:
config: [default, llvm, gnu32, sanitize]
config: [default, llvm, gnu32, sanitize, olddeps]

name: build • ${{ matrix.config }}

Expand Down
23 changes: 22 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,29 @@ endif()

include("cmake/compat_find.cmake")

find_package(CapnProto 0.7.0 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't ipc a trusted interface, where anyone having access can already fully control the process (like calling createTransaction), so leaking memory should not make anything worse? A warning seems fine here? Also, a cve check seems a bit unrelated from a C++20 code workaround (from the title).

Just a nit and not a blocker, but I wanted to mention it, since this will lead to a compile error on Ubuntu 22.04 (bitcoin/bitcoin#33176 (comment)), for an option that will be enabled by default?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For ubuntu 22.04 if this will create confusion, I feel like a good solution might be to improve error message and documentation to specifically suggest disabling ENABLE_IPC, or installing a newer version of capnproto. Ideally it seems like ubuntu could update from 0.8.0 to 0.8.1 given 0.8.1 was released to fix the CVE and doesn't have any other changes.

On IPC being a trusted interface, it's definitely true with the current interface, a malicious client could do a lot of things to crash the node and maybe even take control of it. But this doesn't have to be the case. We could provide capnproto interfaces that do rigorously check all their inputs and enforce resource constraints. It would even be possible to adapt the Mining interface to do this, but it hasn't been a reason to make the extra effort. I also feel like showing an error after discovering a package with a CVE is kind of a public service, since we don't know if there may be other software using the package.

"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.")

Expand Down
1 change: 1 addition & 0 deletions ci/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
5 changes: 5 additions & 0 deletions ci/configs/olddeps.bash
Original file line number Diff line number Diff line change
@@ -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)
29 changes: 29 additions & 0 deletions ci/patches/spaceship.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
commit e3da7da967b94f373c29a198ce45f30fb9f0e517
Author: Ed Catmur <[email protected]>
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); }
2 changes: 1 addition & 1 deletion doc/install.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
29 changes: 28 additions & 1 deletion shell.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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 ];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

88d9504: do I read this correctly as: apply patch to versions 0.9.0 <= ... < 0.10.4?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re: #194 (comment)

88d9504: do I read this correctly as: apply patch to versions 0.9.0 <= ... < 0.10.4?

Yes that's right. These versions of capnproto added some c++20 support which didn't actually work with later compiler versions.

} // (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 {
Expand Down
10 changes: 5 additions & 5 deletions src/mp/gen.cpp
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In commit "mpgen: Work around c++20 / capnproto 0.8 incompatibility" (c4cb758)

I think commit message is wrong in suggesting that with c++20 the operator== function is buggy and will call itself recursively. It seems the reason this happens is not really because of c++20 but because of a gcc bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53499. See also bitcoin/bitcoin#33176 (comment)

Original file line number Diff line number Diff line change
Expand Up @@ -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()] != '/') {
Expand All @@ -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()] != '/') {
Expand Down Expand Up @@ -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
{
Expand Down Expand Up @@ -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;
}
Expand Down