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
41 changes: 33 additions & 8 deletions fuzz/src/fuzz_target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -436,28 +436,53 @@ impl FuzzTargetRunner {
mut stream: UnixStream,
) -> Result<(), FuzzTargetError> {
// First message must be the PeerInfo handshake
self.handle_handshake(&mut stream).await?;
if let Err(e) = self.handle_handshake(&mut stream).await {
if Self::is_session_disconnect_error(&e) {
tracing::info!("Fuzzer disconnected (handshake)");
return Ok(());
}
return Err(e);
}

// Handle incoming messages
loop {
match StreamUtils::read_message(&mut stream).await {
Ok(message_kind) => self.process_message(&mut stream, message_kind).await?,
Err(e) => {
if let FuzzTargetError::IoError(io_error) = e {
// Normal disconnection (EOF)
if io_error.kind() == std::io::ErrorKind::UnexpectedEof {
tracing::info!("Fuzzer session disconnected gracefully");
Ok(message_kind) => {
if let Err(e) = self.process_message(&mut stream, message_kind).await {
if Self::is_session_disconnect_error(&e) {
tracing::info!("Fuzzer session disconnected (read_message)");
return Ok(());
}
return Err(e);
}
}
Err(e) => {
if Self::is_session_disconnect_error(&e) {
tracing::info!("Fuzzer session disconnected gracefully");
return Ok(());
} else {
// Other errors
return Err(e);
}
}
}
}
}

fn is_session_disconnect_error(error: &FuzzTargetError) -> bool {
if let FuzzTargetError::IoError(io_error) = error {
return matches!(
io_error.kind(),
std::io::ErrorKind::UnexpectedEof
| std::io::ErrorKind::BrokenPipe
| std::io::ErrorKind::ConnectionReset
| std::io::ErrorKind::ConnectionAborted
| std::io::ErrorKind::NotConnected
| std::io::ErrorKind::WriteZero
);
}
false
}

async fn handle_handshake(&mut self, stream: &mut UnixStream) -> Result<(), FuzzTargetError> {
let message_kind = StreamUtils::read_message(stream).await?;

Expand Down
66 changes: 66 additions & 0 deletions fuzz/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -658,4 +658,70 @@ mod fuzz_target_tests {
cleanup_socket(&socket_path);
Ok(())
}

#[cfg(feature = "tiny")]
#[tokio::test]
async fn test_fuzz_disconnect_during_session() -> Result<(), FuzzTargetError> {
setup_tracing();
let _temp_dir_sock = tempdir().unwrap();
let socket_path = _temp_dir_sock
.path()
.join("fuzz_socket")
.to_str()
.unwrap()
.to_string();

let _server_jh = run_fuzz_target(socket_path.clone())?;
tokio::time::sleep(Duration::from_millis(100)).await;

// Session #1: send GetState and disconnect before reading response.
{
let mut client = UnixStream::connect(socket_path.clone()).await?;
let _ = MockFuzzer::handshake(&mut client).await?;

let test_case_1 = load_test_case(1);
let test_case_2 = load_test_case(2);
let test_case_3 = load_test_case(3);

let _ = MockFuzzer::initialize(
&mut client,
Initialize {
header: test_case_1.block.header.clone().into(),
state: test_case_1.post_state.clone().into(),
ancestry: Ancestry::default(),
},
)
.await?;

let _ = MockFuzzer::import_block(&mut client, ImportBlock(test_case_2.block.into()))
.await?;
let _ = MockFuzzer::import_block(
&mut client,
ImportBlock(test_case_3.block.clone().into()),
)
.await?;

let last_header_hash = BlockHeader::from(test_case_3.block.header).hash()?;
StreamUtils::send_message(
&mut client,
FuzzMessageKind::GetState(GetState(last_header_hash)),
)
.await?;

// Drop the socket immediately to simulate fuzzer-side early disconnect.
drop(client);
}

tokio::time::sleep(Duration::from_millis(200)).await;

// Session #2: server should still accept new connections.
{
let mut client = UnixStream::connect(socket_path.clone()).await?;
let peer_info = MockFuzzer::handshake(&mut client).await?;
assert_eq!(peer_info, create_test_peer_info("TestFastRoll"));
}

cleanup_socket(&socket_path);
Ok(())
}
}
2 changes: 1 addition & 1 deletion integration/jam-conformance
Submodule jam-conformance updated 53 files
+ fuzz-reports/0.7.2/reports/fastroll/1766243315_2277/report.bin
+11 −11 fuzz-reports/0.7.2/reports/fastroll/1766243315_2277/report.json
+ fuzz-reports/0.7.2/reports/fastroll/1766244122_5414/report.bin
+1 −1 fuzz-reports/0.7.2/reports/fastroll/1766244122_5414/report.json
+ fuzz-reports/0.7.2/reports/fastroll/1766244251_1816/report.bin
+1 −1 fuzz-reports/0.7.2/reports/fastroll/1766244251_1816/report.json
+ fuzz-reports/0.7.2/reports/fastroll/1767872928_1994/report.bin
+1 −1 fuzz-reports/0.7.2/reports/fastroll/1767872928_1994/report.json
+ fuzz-reports/0.7.2/reports/pbnjam/1766243315_2078/report.bin
+26 −15 fuzz-reports/0.7.2/reports/pbnjam/1766243315_2078/report.json
+ fuzz-reports/0.7.2/reports/pbnjam/1766479507_5115/report.bin
+7 −10 fuzz-reports/0.7.2/reports/pbnjam/1766479507_5115/report.json
+ fuzz-reports/0.7.2/reports/pbnjam/1766479507_7943/report.bin
+101 −17 fuzz-reports/0.7.2/reports/pbnjam/1766479507_7943/report.json
+ fuzz-reports/0.7.2/reports/pbnjam/1766565819_4337/report.bin
+31 −20 fuzz-reports/0.7.2/reports/pbnjam/1766565819_4337/report.json
+ fuzz-reports/0.7.2/reports/pbnjam/1767871405_1773/report.bin
+5 −5 fuzz-reports/0.7.2/reports/pbnjam/1767871405_1773/report.json
+ fuzz-reports/0.7.2/reports/pbnjam/1767871405_3282/report.bin
+32 −21 fuzz-reports/0.7.2/reports/pbnjam/1767871405_3282/report.json
+ fuzz-reports/0.7.2/reports/pbnjam/1767891325_5123/report.bin
+31 −17 fuzz-reports/0.7.2/reports/pbnjam/1767891325_5123/report.json
+ fuzz-reports/0.7.2/reports/pbnjam/1767895984_4076/report.bin
+30 −19 fuzz-reports/0.7.2/reports/pbnjam/1767895984_4076/report.json
+ fuzz-reports/0.7.2/reports/pbnjam/1767895984_9131/report.bin
+32 −21 fuzz-reports/0.7.2/reports/pbnjam/1767895984_9131/report.json
+ fuzz-reports/0.7.2/reports/pbnjam/1767896003_2541/report.bin
+32 −21 fuzz-reports/0.7.2/reports/pbnjam/1767896003_2541/report.json
+ fuzz-reports/0.7.2/reports/pbnjam/1768066437_2547/report.bin
+5 −5 fuzz-reports/0.7.2/reports/pbnjam/1768066437_2547/report.json
+ fuzz-reports/0.7.2/reports/tessera/1766241968/report.bin
+16 −16 fuzz-reports/0.7.2/reports/tessera/1766241968/report.json
+ fuzz-reports/0.7.2/reports/tessera/1766243861_2056/report.bin
+16 −16 fuzz-reports/0.7.2/reports/tessera/1766243861_2056/report.json
+ fuzz-reports/0.7.2/reports/tessera/1766244122_3562/report.bin
+16 −16 fuzz-reports/0.7.2/reports/tessera/1766244122_3562/report.json
+ fuzz-reports/0.7.2/reports/tessera/1766565819_4337/report.bin
+16 −16 fuzz-reports/0.7.2/reports/tessera/1766565819_4337/report.json
+ fuzz-reports/0.7.2/reports/tessera/1766565819_9942/report.bin
+16 −16 fuzz-reports/0.7.2/reports/tessera/1766565819_9942/report.json
+ fuzz-reports/0.7.2/reports/tessera/1767889897_4774/report.bin
+16 −16 fuzz-reports/0.7.2/reports/tessera/1767889897_4774/report.json
+ fuzz-reports/0.7.2/reports/tessera/1767895984_8315/report.bin
+17 −17 fuzz-reports/0.7.2/reports/tessera/1767895984_8315/report.json
+1 −1 fuzz-reports/0.7.2/summaries/summary_fastroll.txt
+44 −44 fuzz-reports/0.7.2/summaries/summary_gossamer.txt
+207 −0 fuzz-reports/0.7.2/summaries/summary_jamzilla-int.txt
+15 −15 fuzz-reports/0.7.2/summaries/summary_new-jamneration.txt
+97 −97 fuzz-reports/0.7.2/summaries/summary_pbnjam.txt
+4 −4 fuzz-reports/0.7.2/summaries/summary_strawberry.txt
+3 −3 fuzz-reports/0.7.2/summaries/summary_typeberry.txt
+7 −4 scripts/target.py
+9 −0 scripts/targets.json