Branch data Line data Source code
1 : : // Copyright (c) 2026-present The Bitcoin Core developers
2 : : // Distributed under the MIT software license, see the accompanying
3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 : :
5 : : #include <primitives/transaction.h>
6 : : #include <capnp/capability.h>
7 : : #include <capnp/rpc.h>
8 : : #include <ipc/util.h>
9 : : #include <kj/memory.h>
10 : : #include <mp/proxy-io.h>
11 : : #include <mp/proxy.h>
12 : : #include <test/fuzz/FuzzedDataProvider.h>
13 : : #include <test/fuzz/fuzz.h>
14 : : #include <ipc/test/fuzz/ipc_fuzz.capnp.h>
15 : : #include <ipc/test/fuzz/ipc_fuzz.capnp.proxy.h>
16 : : #include <ipc/test/fuzz/ipc_fuzz.h>
17 : : #include <test/fuzz/util.h>
18 : : #include <test/util/setup_common.h>
19 : :
20 : : #include <future>
21 : : #include <memory>
22 : : #include <stdexcept>
23 : : #include <thread>
24 : :
25 : : namespace {
26 : : class IpcFuzzSetup
27 : : {
28 : : public:
29 : 1 : IpcFuzzSetup()
30 [ + - ]: 1 : {
31 [ + - ]: 1 : std::promise<std::unique_ptr<mp::ProxyClient<test::fuzz::messages::IpcFuzzInterface>>> client_promise;
32 [ + - ]: 1 : auto client_future{client_promise.get_future()};
33 : 1 : m_loop_thread = std::thread([&client_promise] {
34 [ + - ]: 1 : mp::EventLoop loop("ipc-fuzz", [](mp::LogMessage message) {
35 [ - + - - ]: 6123 : if (message.level == mp::Log::Raise) throw std::runtime_error(message.message);
36 [ + - ]: 6124 : });
37 [ + - ]: 1 : auto pipe = loop.m_io_context.provider->newTwoWayPipe();
38 : :
39 : 1 : auto server_connection = std::make_unique<mp::Connection>(
40 : : loop,
41 : : kj::mv(pipe.ends[0]),
42 : 1 : [&](mp::Connection& connection) {
43 : 1 : auto server_proxy = kj::heap<mp::ProxyServer<test::fuzz::messages::IpcFuzzInterface>>(
44 [ + - ]: 1 : std::make_shared<IpcFuzzImplementation>(), connection);
45 [ + - + - ]: 1 : return capnp::Capability::Client(kj::mv(server_proxy));
46 [ + - ]: 2 : });
47 [ + - + - ]: 2 : server_connection->onDisconnect([&] { server_connection.reset(); });
48 : :
49 [ + - ]: 1 : auto client_connection = std::make_unique<mp::Connection>(loop, kj::mv(pipe.ends[1]));
50 : 1 : auto client_proxy = std::make_unique<mp::ProxyClient<test::fuzz::messages::IpcFuzzInterface>>(
51 [ + - + - : 1 : client_connection->m_rpc_system->bootstrap(mp::ServerVatId().vat_id)
+ - ]
52 [ + - ]: 1 : .castAs<test::fuzz::messages::IpcFuzzInterface>(),
53 [ + - ]: 1 : client_connection.get(),
54 [ + - + - ]: 2 : /* destroy_connection= */ true);
55 [ + - ]: 1 : (void)client_connection.release();
56 : :
57 [ + - ]: 1 : client_promise.set_value(std::move(client_proxy));
58 [ + - ]: 1 : loop.loop();
59 [ + - + - ]: 2 : });
60 [ + - - + ]: 1 : m_client = client_future.get();
61 : 1 : }
62 : :
63 : 1 : ~IpcFuzzSetup()
64 : : {
65 [ + - ]: 1 : m_client.reset();
66 [ + - ]: 1 : if (m_loop_thread.joinable()) m_loop_thread.join();
67 : 1 : }
68 : :
69 : : std::unique_ptr<mp::ProxyClient<test::fuzz::messages::IpcFuzzInterface>> m_client;
70 : :
71 : : private:
72 : : std::thread m_loop_thread;
73 : : };
74 : :
75 : : static IpcFuzzSetup* g_ipc;
76 : :
77 : 1 : static void initialize_ipc()
78 : : {
79 [ + - + - : 1 : static const auto testing_setup = MakeNoLogFileContext<>();
+ - ]
80 : 1 : (void)testing_setup;
81 : :
82 : : // Ensure the thread's ThreadContext is created before the IPC setup, so
83 : : // it is destroyed after it, since C++ destroys thread_local objects in
84 : : // reverse construction order.
85 : 1 : mp::CurrentThread();
86 : :
87 [ + - ]: 1 : thread_local static IpcFuzzSetup ipc; // NOLINT(bitcoin-nontrivial-threadlocal)
88 : 1 : g_ipc = &ipc;
89 : 1 : }
90 : :
91 [ + - ]: 1447 : FUZZ_TARGET(ipc, .init = initialize_ipc)
92 : : {
93 : 973 : auto& ipc = *g_ipc;
94 : 973 : FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
95 [ + + + + ]: 1973 : LIMITED_WHILE (fuzzed_data_provider.ConsumeBool(), 64) {
96 : 1000 : CallOneOf(
97 : : fuzzed_data_provider,
98 : 34 : [&] {
99 : 34 : static constexpr int MIN_ADD{-1'000'000};
100 : 34 : static constexpr int MAX_ADD{1'000'000};
101 : 34 : const int a = fuzzed_data_provider.ConsumeIntegralInRange<int>(MIN_ADD, MAX_ADD);
102 : 34 : const int b = fuzzed_data_provider.ConsumeIntegralInRange<int>(MIN_ADD, MAX_ADD);
103 [ - + ]: 34 : assert(ipc.m_client->add(a, b) == a + b);
104 : 34 : },
105 : 105 : [&] {
106 : 105 : COutPoint outpoint{Txid::FromUint256(ConsumeUInt256(fuzzed_data_provider)),
107 : 105 : fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
108 : 105 : COutPoint expected{outpoint.hash, outpoint.n ^ 0xFFFFFFFFu};
109 [ - + ]: 105 : assert(ipc.m_client->passOutPoint(outpoint) == expected);
110 : 105 : },
111 : 43 : [&] {
112 : 43 : std::vector<uint8_t> value = ConsumeRandomLengthByteVector<uint8_t>(fuzzed_data_provider, 512);
113 [ + - ]: 43 : std::vector<uint8_t> expected{value.rbegin(), value.rend()};
114 [ + - + - : 86 : assert(ipc.m_client->passVectorUint8(value) == expected);
- + ]
115 : 43 : },
116 : 188 : [&] {
117 : 188 : CScript script{ConsumeScript(fuzzed_data_provider)};
118 : 188 : CScript expected{script};
119 [ + - ]: 188 : expected << OP_NOP;
120 [ + - - + ]: 376 : assert(ipc.m_client->passScript(script) == expected);
121 : 188 : },
122 : 163 : [&] {
123 [ + - ]: 163 : UniValue value;
124 [ + - + - : 326 : if (!value.read(fuzzed_data_provider.ConsumeRandomLengthString(512))) return;
+ + ]
125 [ + - + - : 72 : assert(ipc.m_client->passUniValue(value).write() == value.write());
+ - + - -
+ ]
126 : 163 : },
127 : 467 : [&] {
128 : 467 : const CMutableTransaction mutable_tx = ConsumeTransaction(fuzzed_data_provider, std::nullopt);
129 [ + + ]: 467 : if (mutable_tx.vin.empty()) return;
130 [ + - ]: 358 : const CTransactionRef tx = MakeTransactionRef(mutable_tx);
131 [ + - + - : 1432 : assert(*ipc.m_client->passTransaction(tx) == *tx);
- + + - +
- ]
132 : 825 : });
133 : : }
134 : 973 : }
135 : : } // namespace
|