Skip to content

Commit d0cb516

Browse files
committed
Merge bitcoin/bitcoin#30230: fuzz: add I2P harness
193c748 fuzz: add I2P harness (marcofleon) Pull request description: Addresses bitcoin/bitcoin#28803. This updated harness sets mock time at the beginning of each iteration and deletes the private key file at the end of each iteration. Mock time is used to make the fuzz test more stable, as `GetTime` is called at points in `i2p`. Deleting the private key file ensures that each iteration is independent from the last. Now, a new key is generated in `i2p` every time, so the fuzzer can eventually make progress through the target code. Re-working this harness also led me and dergoegge to resolve a couple of issues in `FuzzedSock`, which allows for full coverage of the `i2p` code. Those changes can be seen in bitcoin/bitcoin#30211. The SAM protocol for interacting with I2P requires some specifc inputs so it's best to use a dictionary when running this harness. <details> <summary>I2P dict</summary> ``` "HELLO VERSION" "HELLO REPLY RESULT=OK VERSION=" "HELLO REPLY RESULT=NOVERSION" "HELLO REPLY RESULT=I2P_ERROR" "SESSION CREATE" "SESSION STATUS RESULT=OK DESTINATION=" "SESSION STATUS RESULT=DUPLICATED_ID" "SESSION STATUS RESULT=DUPLICATED_DEST" "SESSION STATUS RESULT=INVALID_ID" "SESSION STATUS RESULT=INVALID_KEY" "SESSION STATUS RESULT=I2P_ERROR MESSAGE=" "SESSION ADD" "SESSION REMOVE" "STREAM CONNECT" "STREAM STATUS RESULT=OK" "STREAM STATUS RESULT=INVALID_ID" "STREAM STATUS RESULT=INVALID_KEY" "STREAM STATUS RESULT=CANT_REACH_PEER" "STREAM STATUS RESULT=I2P_ERROR MESSAGE=" "STREAM ACCEPT" "STREAM FORWARD" "DATAGRAM SEND" "RAW SEND" "DEST GENERATE" "DEST REPLY PUB= PRIV=" "DEST REPLY RESULT=I2P_ERROR" "NAMING LOOKUP" "NAMING REPLY RESULT=OK NAME= VALUE=" "DATAGRAM RECEIVED DESTINATION= SIZE=" "RAW RECEIVED SIZE=" "NAMING REPLY RESULT=INVALID_KEY NAME=" "NAMING REPLY RESULT=KEY_NOT_FOUND NAME=" "MIN" "MAX" "STYLE" "ID" "SILENT" "DESTINATION" "NAME" "SIGNATURE_TYPE" "CRYPTO_TYPE" "SIZE" "HOST" "PORT" "FROM_PORT" "TRANSIENT" "STREAM" "DATAGRAM" "RAW" "MASTER" "true" "false" ``` </details> I'll add this dict to qa-assets later on. ACKs for top commit: dergoegge: tACK 193c748 brunoerg: ACK 193c748 vasild: ACK 193c748 Tree-SHA512: 09ae4b3fa0738aa6f159f4d920493bdbce786b489bc8148e7a135a881e9dba93d727b40f5400c9510e218dd2cfdccc7ce2d3ac9450654fb29c78aac59af92ec3
2 parents aa6b876 + 193c748 commit d0cb516

File tree

2 files changed

+64
-0
lines changed

2 files changed

+64
-0
lines changed

src/Makefile.test.include

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ test_fuzz_fuzz_SOURCES = \
328328
test/fuzz/headerssync.cpp \
329329
test/fuzz/hex.cpp \
330330
test/fuzz/http_request.cpp \
331+
test/fuzz/i2p.cpp \
331332
test/fuzz/integer.cpp \
332333
test/fuzz/key.cpp \
333334
test/fuzz/key_io.cpp \

src/test/fuzz/i2p.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright (c) 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 <common/args.h>
6+
#include <i2p.h>
7+
#include <netaddress.h>
8+
#include <netbase.h>
9+
#include <test/fuzz/FuzzedDataProvider.h>
10+
#include <test/fuzz/fuzz.h>
11+
#include <test/fuzz/util.h>
12+
#include <test/fuzz/util/net.h>
13+
#include <test/util/setup_common.h>
14+
#include <util/fs_helpers.h>
15+
#include <util/threadinterrupt.h>
16+
17+
void initialize_i2p()
18+
{
19+
static const auto testing_setup = MakeNoLogFileContext<>();
20+
}
21+
22+
FUZZ_TARGET(i2p, .init = initialize_i2p)
23+
{
24+
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
25+
26+
SetMockTime(ConsumeTime(fuzzed_data_provider));
27+
28+
// Mock CreateSock() to create FuzzedSock.
29+
auto CreateSockOrig = CreateSock;
30+
CreateSock = [&fuzzed_data_provider](const sa_family_t&) {
31+
return std::make_unique<FuzzedSock>(fuzzed_data_provider);
32+
};
33+
34+
const fs::path private_key_path = gArgs.GetDataDirNet() / "fuzzed_i2p_private_key";
35+
const CService addr{in6_addr(IN6ADDR_LOOPBACK_INIT), 7656};
36+
const Proxy sam_proxy{addr, false};
37+
CThreadInterrupt interrupt;
38+
39+
i2p::sam::Session session{private_key_path, sam_proxy, &interrupt};
40+
i2p::Connection conn;
41+
42+
if (session.Listen(conn)) {
43+
if (session.Accept(conn)) {
44+
try {
45+
(void)conn.sock->RecvUntilTerminator('\n', 10ms, interrupt, i2p::sam::MAX_MSG_SIZE);
46+
} catch (const std::runtime_error&) {
47+
}
48+
}
49+
}
50+
51+
bool proxy_error;
52+
53+
if (session.Connect(CService{}, conn, proxy_error)) {
54+
try {
55+
conn.sock->SendComplete("verack\n", 10ms, interrupt);
56+
} catch (const std::runtime_error&) {
57+
}
58+
}
59+
60+
fs::remove_all(private_key_path);
61+
62+
CreateSock = CreateSockOrig;
63+
}

0 commit comments

Comments
 (0)