Skip to content

Commit d39f15a

Browse files
committed
Merge bitcoin/bitcoin#30211: fuzz: Make FuzzedSock fuzz friendlier
22d0f1a [fuzz] Avoid endless waiting in FuzzedSock::{Wait,WaitMany} (marcofleon) a7fceda [fuzz] Make peeking through FuzzedSock::Recv fuzzer friendly (dergoegge) 865cdf3 [fuzz] Use fuzzer friendly ConsumeRandomLengthByteVector in FuzzedSock::Recv (dergoegge) Pull request description: `FuzzedSock` has a few issues that block a fuzzer from making progress. See commit messages for details. ACKs for top commit: marcofleon: Tested ACK 22d0f1a brunoerg: utACK 22d0f1a Tree-SHA512: 2d66fc94ba58b6652ae234bd1dcd33b7d685b5054fe83e0cd624b053dd51519c23148f43a865ab8c8bc5fc2dc25e701952831b99159687474978a90348faa4c5
2 parents 9efc2af + 22d0f1a commit d39f15a

File tree

2 files changed

+19
-10
lines changed

2 files changed

+19
-10
lines changed

src/test/fuzz/util/net.cpp

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -193,21 +193,20 @@ ssize_t FuzzedSock::Recv(void* buf, size_t len, int flags) const
193193
bool pad_to_len_bytes{m_fuzzed_data_provider.ConsumeBool()};
194194
if (m_peek_data.has_value()) {
195195
// `MSG_PEEK` was used in the preceding `Recv()` call, return `m_peek_data`.
196-
random_bytes.assign({m_peek_data.value()});
196+
random_bytes = m_peek_data.value();
197197
if ((flags & MSG_PEEK) == 0) {
198198
m_peek_data.reset();
199199
}
200200
pad_to_len_bytes = false;
201201
} else if ((flags & MSG_PEEK) != 0) {
202202
// New call with `MSG_PEEK`.
203-
random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>(1);
203+
random_bytes = ConsumeRandomLengthByteVector(m_fuzzed_data_provider, len);
204204
if (!random_bytes.empty()) {
205-
m_peek_data = random_bytes[0];
205+
m_peek_data = random_bytes;
206206
pad_to_len_bytes = false;
207207
}
208208
} else {
209-
random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>(
210-
m_fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, len));
209+
random_bytes = ConsumeRandomLengthByteVector(m_fuzzed_data_provider, len);
211210
}
212211
if (random_bytes.empty()) {
213212
const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
@@ -216,7 +215,11 @@ ssize_t FuzzedSock::Recv(void* buf, size_t len, int flags) const
216215
}
217216
return r;
218217
}
219-
std::memcpy(buf, random_bytes.data(), random_bytes.size());
218+
// `random_bytes` might exceed the size of `buf` if e.g. Recv is called with
219+
// len=N and MSG_PEEK first and afterwards called with len=M (M < N) and
220+
// without MSG_PEEK.
221+
size_t recv_len{std::min(random_bytes.size(), len)};
222+
std::memcpy(buf, random_bytes.data(), recv_len);
220223
if (pad_to_len_bytes) {
221224
if (len > random_bytes.size()) {
222225
std::memset((char*)buf + random_bytes.size(), 0, len - random_bytes.size());
@@ -226,7 +229,7 @@ ssize_t FuzzedSock::Recv(void* buf, size_t len, int flags) const
226229
if (m_fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) {
227230
std::this_thread::sleep_for(std::chrono::milliseconds{2});
228231
}
229-
return random_bytes.size();
232+
return recv_len;
230233
}
231234

232235
int FuzzedSock::Connect(const sockaddr*, socklen_t) const
@@ -380,7 +383,10 @@ bool FuzzedSock::Wait(std::chrono::milliseconds timeout, Event requested, Event*
380383
return false;
381384
}
382385
if (occurred != nullptr) {
383-
*occurred = m_fuzzed_data_provider.ConsumeBool() ? requested : 0;
386+
// We simulate the requested event as occured when ConsumeBool()
387+
// returns false. This avoids simulating endless waiting if the
388+
// FuzzedDataProvider runs out of data.
389+
*occurred = m_fuzzed_data_provider.ConsumeBool() ? 0 : requested;
384390
}
385391
return true;
386392
}
@@ -389,7 +395,10 @@ bool FuzzedSock::WaitMany(std::chrono::milliseconds timeout, EventsPerSock& even
389395
{
390396
for (auto& [sock, events] : events_per_sock) {
391397
(void)sock;
392-
events.occurred = m_fuzzed_data_provider.ConsumeBool() ? events.requested : 0;
398+
// We simulate the requested event as occured when ConsumeBool()
399+
// returns false. This avoids simulating endless waiting if the
400+
// FuzzedDataProvider runs out of data.
401+
events.occurred = m_fuzzed_data_provider.ConsumeBool() ? 0 : events.requested;
393402
}
394403
return true;
395404
}

src/test/fuzz/util/net.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class FuzzedSock : public Sock
4343
* If `MSG_PEEK` is used, then our `Recv()` returns some random data as usual, but on the next
4444
* `Recv()` call we must return the same data, thus we remember it here.
4545
*/
46-
mutable std::optional<uint8_t> m_peek_data;
46+
mutable std::optional<std::vector<uint8_t>> m_peek_data;
4747

4848
/**
4949
* Whether to pretend that the socket is select(2)-able. This is randomly set in the

0 commit comments

Comments
 (0)