fuzzers: Add WebSocket fuzzer

It immediately found an issue with &transient, but fairly stable thereafter.

This is a separate fuzzer implementation as there's a custom Configure()
call for the analyzer as well as disabling all other analyzers so we
don't fuzz unrelated protocols.
This commit is contained in:
Arne Welzel 2024-01-19 20:17:57 +01:00
parent 5eb380d74a
commit 1775b01b58
3 changed files with 108 additions and 0 deletions

View file

@ -94,6 +94,7 @@ target_link_libraries(zeek_fuzzer_shared PUBLIC ${zeek_fuzzer_shared_deps}
add_fuzz_target(packet) add_fuzz_target(packet)
add_fuzz_target(dns) add_fuzz_target(dns)
add_fuzz_target(websocket)
add_generic_analyzer_fuzz_target(ftp) add_generic_analyzer_fuzz_target(ftp)
add_generic_analyzer_fuzz_target(http) add_generic_analyzer_fuzz_target(http)

Binary file not shown.

View file

@ -0,0 +1,107 @@
#include <binpac.h>
#include "zeek/Conn.h"
#include "zeek/ID.h"
#include "zeek/RunState.h"
#include "zeek/analyzer/Analyzer.h"
#include "zeek/analyzer/Manager.h"
#include "zeek/analyzer/protocol/pia/PIA.h"
#include "zeek/analyzer/protocol/tcp/TCP.h"
#include "zeek/analyzer/protocol/websocket/WebSocket.h"
#include "zeek/fuzzers/FuzzBuffer.h"
#include "zeek/fuzzers/fuzzer-setup.h"
#include "zeek/packet_analysis/protocol/tcp/TCPSessionAdapter.h"
#include "zeek/session/Manager.h"
static constexpr auto FUZZ_ANALYZER_NAME = "websocket";
static zeek::Connection* add_connection() {
static constexpr double network_time_start = 1439471031;
zeek::run_state::detail::update_network_time(network_time_start);
zeek::Packet p;
zeek::ConnTuple conn_id;
conn_id.src_addr = zeek::IPAddr("1.2.3.4");
conn_id.dst_addr = zeek::IPAddr("5.6.7.8");
conn_id.src_port = htons(23132);
conn_id.dst_port = htons(80);
conn_id.is_one_way = false;
conn_id.proto = TRANSPORT_TCP;
zeek::detail::ConnKey key(conn_id);
zeek::Connection* conn = new zeek::Connection(key, network_time_start, &conn_id, 1, &p);
conn->SetTransport(TRANSPORT_TCP);
zeek::session_mgr->Insert(conn);
return conn;
}
static std::tuple<zeek::analyzer::Analyzer*, zeek::packet_analysis::IP::SessionAdapter*> add_analyzer(
zeek::Connection* conn, const zeek::Tag& analyzer_tag) {
auto* tcp = new zeek::packet_analysis::TCP::TCPSessionAdapter(conn);
auto* pia = new zeek::analyzer::pia::PIA_TCP(conn);
auto a = zeek::analyzer_mgr->InstantiateAnalyzer(analyzer_tag, conn);
tcp->AddChildAnalyzer(a);
tcp->AddChildAnalyzer(pia->AsAnalyzer());
conn->SetSessionAdapter(tcp, pia);
return {a, tcp};
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
static auto analyzer_tag = zeek::analyzer_mgr->GetComponentTag(FUZZ_ANALYZER_NAME);
if ( ! analyzer_tag ) {
std::fprintf(stderr, "Unable to find component tag for '%s'", FUZZ_ANALYZER_NAME);
abort();
}
// Would be nice to have that in LLVMFuzzerInitialize, oh well...
static bool one_time_setup = false;
if ( ! one_time_setup ) {
zeek::analyzer_mgr->DisableAllAnalyzers();
zeek::analyzer_mgr->EnableAnalyzer(analyzer_tag);
const auto& pia_tcp_tag = zeek::analyzer_mgr->GetComponentTag("PIA_TCP");
zeek::analyzer_mgr->EnableAnalyzer(pia_tcp_tag);
one_time_setup = true;
}
zeek::detail::FuzzBuffer fb{data, size};
if ( ! fb.Valid() )
return 0;
auto conn = add_connection();
if ( new_connection )
conn->Event(new_connection, nullptr);
auto [a, adapter] = add_analyzer(conn, analyzer_tag);
// WebSocket specific initialization. May also want to fuzz
// this in the future.
static const auto& config_type = zeek::id::find_type<zeek::RecordType>("WebSocket::AnalyzerConfig");
static const auto& config_rec = zeek::make_intrusive<zeek::RecordVal>(config_type);
auto wsa = static_cast<zeek::analyzer::websocket::WebSocket_Analyzer*>(a);
wsa->Configure(config_rec);
for ( ;; ) {
auto chunk = fb.Next();
if ( ! chunk )
break;
try {
a->NextStream(chunk->size, chunk->data.get(), chunk->is_orig);
} catch ( const binpac::Exception& e ) {
}
chunk = {}; // Release buffer before draining events.
zeek::event_mgr.Drain();
// Has the analyzer been disabled during event processing?
if ( ! adapter->HasChildAnalyzer(analyzer_tag) )
break;
}
zeek::event_mgr.Drain();
zeek::detail::fuzzer_cleanup_one_input();
return 0;
}