From 266a77dd0b376ea460e4112eb141b3833116bf0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?I=C3=B1aki=20Baz=20Castillo?= Date: Wed, 28 Feb 2024 13:55:27 +0100 Subject: [PATCH 1/2] Add DTLS fuzzer ### Details - Fuzz our `DtlsTransport` class. - NOTE: It's basically impossible to get into DTLS 'connected' state due to all the crypto coincidences that must happen, but anyway. --- doc/Fuzzer.md | 7 ++ .../include/RTC/FuzzerDtlsTransport.hpp | 39 ++++++ worker/fuzzer/src/RTC/FuzzerDtlsTransport.cpp | 118 ++++++++++++++++++ worker/fuzzer/src/fuzzer.cpp | 19 ++- worker/meson.build | 3 +- 5 files changed, 184 insertions(+), 2 deletions(-) create mode 100644 worker/fuzzer/include/RTC/FuzzerDtlsTransport.hpp create mode 100644 worker/fuzzer/src/RTC/FuzzerDtlsTransport.cpp diff --git a/doc/Fuzzer.md b/doc/Fuzzer.md index d993e43684..ef05f406ef 100644 --- a/doc/Fuzzer.md +++ b/doc/Fuzzer.md @@ -40,6 +40,7 @@ For memory leak detection enable the following environment variable: The mediasoup-worker fuzzer reads some custom environment variables to decide which kind of fuzzing perform: - `MS_FUZZ_STUN=1`: Do STUN fuzzing. +- `MS_FUZZ_DTLS=1`: Do DTLS fuzzing. - `MS_FUZZ_RTP=1`: Do RTP fuzzing. - `MS_FUZZ_RTCP=1`: Do RTCP fuzzing. - `MS_FUZZ_UTILS=1`: Do C++ utils fuzzing. @@ -55,6 +56,12 @@ The log level can also be set by setting the `MS_FUZZ_LOG_LEVEL` environment var MS_FUZZ_STUN=1 LSAN_OPTIONS=verbosity=1:log_threads=1 ./out/Release/mediasoup-worker-fuzzer -artifact_prefix=fuzzer/reports/ -max_len=1400 fuzzer/new-corpus deps/webrtc-fuzzer-corpora/corpora/stun-corpus ``` +- Detect memory leaks and just fuzz DTLS: + +```bash +MS_FUZZ_DTLS=1 LSAN_OPTIONS=verbosity=1:log_threads=1 ./out/Release/mediasoup-worker-fuzzer -artifact_prefix=fuzzer/reports/ -max_len=1400 fuzzer/new-corpus +``` + - Detect memory leaks and just fuzz RTP: ```bash diff --git a/worker/fuzzer/include/RTC/FuzzerDtlsTransport.hpp b/worker/fuzzer/include/RTC/FuzzerDtlsTransport.hpp new file mode 100644 index 0000000000..f5f6baa780 --- /dev/null +++ b/worker/fuzzer/include/RTC/FuzzerDtlsTransport.hpp @@ -0,0 +1,39 @@ +#ifndef MS_FUZZER_RTC_DTLS_TRANSPORT_HPP +#define MS_FUZZER_RTC_DTLS_TRANSPORT_HPP + +#include "common.hpp" +#include "RTC/DtlsTransport.hpp" + +namespace Fuzzer +{ + namespace RTC + { + namespace DtlsTransport + { + class DtlsTransportListener : public ::RTC::DtlsTransport::Listener + { + /* Pure virtual methods inherited from RTC::DtlsTransport::Listener. */ + public: + void OnDtlsTransportConnecting(const ::RTC::DtlsTransport* dtlsTransport) override; + void OnDtlsTransportConnected( + const ::RTC::DtlsTransport* dtlsTransport, + ::RTC::SrtpSession::CryptoSuite srtpCryptoSuite, + uint8_t* srtpLocalKey, + size_t srtpLocalKeyLen, + uint8_t* srtpRemoteKey, + size_t srtpRemoteKeyLen, + std::string& remoteCert) override; + void OnDtlsTransportFailed(const ::RTC::DtlsTransport* dtlsTransport) override; + void OnDtlsTransportClosed(const ::RTC::DtlsTransport* dtlsTransport) override; + void OnDtlsTransportSendData( + const ::RTC::DtlsTransport* dtlsTransport, const uint8_t* data, size_t len) override; + void OnDtlsTransportApplicationDataReceived( + const ::RTC::DtlsTransport* dtlsTransport, const uint8_t* data, size_t len) override; + }; + + void Fuzz(const uint8_t* data, size_t len); + } // namespace DtlsTransport + } // namespace RTC +} // namespace Fuzzer + +#endif diff --git a/worker/fuzzer/src/RTC/FuzzerDtlsTransport.cpp b/worker/fuzzer/src/RTC/FuzzerDtlsTransport.cpp new file mode 100644 index 0000000000..91e1993897 --- /dev/null +++ b/worker/fuzzer/src/RTC/FuzzerDtlsTransport.cpp @@ -0,0 +1,118 @@ +#define MS_CLASS "Fuzzer::RTC::DtlsTransport" +// #define MS_LOG_DEV_LEVEL 3 + +#include "RTC/FuzzerDtlsTransport.hpp" +#include "Logger.hpp" +#include "Utils.hpp" + +// DtlsTransport singleton. It's reset every time DTLS handshake fails or DTLS +// is closed. +thread_local static ::RTC::DtlsTransport* dtlsTransportSingleton{ nullptr }; +// DtlsTransport Listener singleton. It's reset every time the DtlsTransport +// singletonDTLS is reset. +thread_local static Fuzzer::RTC::DtlsTransport::DtlsTransportListener* dtlsTransportListenerSingleton{ + nullptr +}; + +void Fuzzer::RTC::DtlsTransport::Fuzz(const uint8_t* data, size_t len) +{ + if (!::RTC::DtlsTransport::IsDtls(data, len)) + { + return; + } + + if (!dtlsTransportSingleton) + { + MS_DEBUG_DEV("no DtlsTransport singleton, creating it"); + + delete dtlsTransportListenerSingleton; + dtlsTransportListenerSingleton = new DtlsTransportListener(); + + dtlsTransportSingleton = new ::RTC::DtlsTransport(dtlsTransportListenerSingleton); + + ::RTC::DtlsTransport::Role localRole; + ::RTC::DtlsTransport::Fingerprint dtlsRemoteFingerprint; + + // Local DTLS role must be 'server' or 'client'. Choose it based on + // randomness of first given byte. + if (data[0] / 2 == 0) + { + localRole = ::RTC::DtlsTransport::Role::SERVER; + } + else + { + localRole = ::RTC::DtlsTransport::Role::CLIENT; + } + + // Remote DTLS fingerprint random generation. + // NOTE: Use a random integer in range 1..5 since FingerprintAlgorithm enum + // has 5 possible values starting with value 1. + dtlsRemoteFingerprint.algorithm = + static_cast<::RTC::DtlsTransport::FingerprintAlgorithm>(::Utils::Crypto::GetRandomUInt(1u, 5u)); + + dtlsRemoteFingerprint.value = + ::Utils::Crypto::GetRandomString(::Utils::Crypto::GetRandomUInt(3u, 20u)); + + dtlsTransportSingleton->Run(localRole); + dtlsTransportSingleton->SetRemoteFingerprint(dtlsRemoteFingerprint); + } + + dtlsTransportSingleton->ProcessDtlsData(data, len); + + // DTLS may have failed or closed after ProcessDtlsData(). If so, unset it. + if ( + dtlsTransportSingleton->GetState() == ::RTC::DtlsTransport::DtlsState::FAILED || + dtlsTransportSingleton->GetState() == ::RTC::DtlsTransport::DtlsState::CLOSED) + { + MS_DEBUG_DEV("DtlsTransport singleton state is 'failed' or 'closed', unsetting it"); + + delete dtlsTransportSingleton; + dtlsTransportSingleton = nullptr; + } + else + { + dtlsTransportSingleton->SendApplicationData(data, len); + } +} + +void Fuzzer::RTC::DtlsTransport::DtlsTransportListener::OnDtlsTransportConnecting( + const ::RTC::DtlsTransport* /*dtlsTransport*/) +{ + MS_DEBUG_DEV("DtlsTransport singleton connecting"); +} + +void Fuzzer::RTC::DtlsTransport::DtlsTransportListener::OnDtlsTransportConnected( + const ::RTC::DtlsTransport* /*dtlsTransport*/, + ::RTC::SrtpSession::CryptoSuite /*srtpCryptoSuite*/, + uint8_t* /*srtpLocalKey*/, + size_t /*srtpLocalKeyLen*/, + uint8_t* /*srtpRemoteKey*/, + size_t /*srtpRemoteKeyLen*/, + std::string& /*remoteCert*/) +{ + MS_DEBUG_DEV("DtlsTransport singleton connected"); +} + +void Fuzzer::RTC::DtlsTransport::DtlsTransportListener::OnDtlsTransportFailed( + const ::RTC::DtlsTransport* /*dtlsTransport*/) +{ + MS_DEBUG_DEV("DtlsTransport singleton failed"); +} + +void Fuzzer::RTC::DtlsTransport::DtlsTransportListener::OnDtlsTransportClosed( + const ::RTC::DtlsTransport* /*dtlsTransport*/) +{ + MS_DEBUG_DEV("DtlsTransport singleton closed"); +} + +void Fuzzer::RTC::DtlsTransport::DtlsTransportListener::OnDtlsTransportSendData( + const ::RTC::DtlsTransport* /*dtlsTransport*/, const uint8_t* /*data*/, size_t /*len*/) +{ + MS_DEBUG_DEV("DtlsTransport singleton wants to send data"); +} + +void Fuzzer::RTC::DtlsTransport::DtlsTransportListener::OnDtlsTransportApplicationDataReceived( + const ::RTC::DtlsTransport* /*dtlsTransport*/, const uint8_t* /*data*/, size_t /*len*/) +{ + MS_DEBUG_DEV("DtlsTransport singleton received application data"); +} diff --git a/worker/fuzzer/src/fuzzer.cpp b/worker/fuzzer/src/fuzzer.cpp index 26e3ee6957..c5a89b1702 100644 --- a/worker/fuzzer/src/fuzzer.cpp +++ b/worker/fuzzer/src/fuzzer.cpp @@ -9,6 +9,8 @@ #include "LogLevel.hpp" #include "Settings.hpp" #include "Utils.hpp" +#include "RTC/DtlsTransport.hpp" +#include "RTC/FuzzerDtlsTransport.hpp" #include "RTC/FuzzerRtpPacket.hpp" #include "RTC/FuzzerRtpRetransmissionBuffer.hpp" #include "RTC/FuzzerRtpStreamSend.hpp" @@ -22,6 +24,7 @@ #include bool fuzzStun = false; +bool fuzzDtls = false; bool fuzzRtp = false; bool fuzzRtcp = false; bool fuzzUtils = false; @@ -41,6 +44,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t len) Fuzzer::RTC::StunPacket::Fuzz(data, len); } + if (fuzzDtls) + { + Fuzzer::RTC::DtlsTransport::Fuzz(data, len); + } + if (fuzzRtp) { Fuzzer::RTC::RtpPacket::Fuzz(data, len); @@ -85,12 +93,19 @@ int Init() } // Select what to fuzz. + if (std::getenv("MS_FUZZ_STUN") && std::string(std::getenv("MS_FUZZ_STUN")) == "1") { std::cout << "[fuzzer] STUN fuzzers enabled" << std::endl; fuzzStun = true; } + if (std::getenv("MS_FUZZ_DTLS") && std::string(std::getenv("MS_FUZZ_DTLS")) == "1") + { + std::cout << "[fuzzer] DTLS fuzzers enabled" << std::endl; + + fuzzDtls = true; + } if (std::getenv("MS_FUZZ_RTP") && std::string(std::getenv("MS_FUZZ_RTP")) == "1") { std::cout << "[fuzzer] RTP fuzzers enabled" << std::endl; @@ -109,11 +124,12 @@ int Init() fuzzUtils = true; } - if (!fuzzUtils && !fuzzStun && !fuzzRtcp && !fuzzRtp) + if (!fuzzStun && !fuzzDtls && !fuzzRtcp && !fuzzRtp && !fuzzUtils) { std::cout << "[fuzzer] all fuzzers enabled" << std::endl; fuzzStun = true; + fuzzDtls = true; fuzzRtp = true; fuzzRtcp = true; fuzzUtils = true; @@ -128,6 +144,7 @@ int Init() DepUsrSCTP::ClassInit(); DepLibWebRTC::ClassInit(); Utils::Crypto::ClassInit(); + ::RTC::DtlsTransport::ClassInit(); return 0; } diff --git a/worker/meson.build b/worker/meson.build index 77125be6e0..bc4ff9eb00 100644 --- a/worker/meson.build +++ b/worker/meson.build @@ -431,11 +431,12 @@ executable( sources: common_sources + [ 'fuzzer/src/fuzzer.cpp', 'fuzzer/src/FuzzerUtils.cpp', - 'fuzzer/src/RTC/FuzzerStunPacket.cpp', + 'fuzzer/src/RTC/FuzzerDtlsTransport.cpp', 'fuzzer/src/RTC/FuzzerRtpPacket.cpp', 'fuzzer/src/RTC/FuzzerRtpRetransmissionBuffer.cpp', 'fuzzer/src/RTC/FuzzerRtpStreamSend.cpp', 'fuzzer/src/RTC/FuzzerSeqManager.cpp', + 'fuzzer/src/RTC/FuzzerStunPacket.cpp', 'fuzzer/src/RTC/FuzzerTrendCalculator.cpp', 'fuzzer/src/RTC/RTCP/FuzzerBye.cpp', 'fuzzer/src/RTC/RTCP/FuzzerFeedbackPs.cpp', From bc72442bcb29ea187960a03684223374be8de52e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?I=C3=B1aki=20Baz=20Castillo?= Date: Wed, 28 Feb 2024 15:40:09 +0100 Subject: [PATCH 2/2] cosmetic --- doc/Fuzzer.md | 10 +++++----- worker/fuzzer/src/fuzzer.cpp | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/doc/Fuzzer.md b/doc/Fuzzer.md index ef05f406ef..0e94468faa 100644 --- a/doc/Fuzzer.md +++ b/doc/Fuzzer.md @@ -39,11 +39,11 @@ For memory leak detection enable the following environment variable: The mediasoup-worker fuzzer reads some custom environment variables to decide which kind of fuzzing perform: -- `MS_FUZZ_STUN=1`: Do STUN fuzzing. -- `MS_FUZZ_DTLS=1`: Do DTLS fuzzing. -- `MS_FUZZ_RTP=1`: Do RTP fuzzing. -- `MS_FUZZ_RTCP=1`: Do RTCP fuzzing. -- `MS_FUZZ_UTILS=1`: Do C++ utils fuzzing. +- `MS_FUZZ_STUN=1`: Enable STUN fuzzer. +- `MS_FUZZ_DTLS=1`: Enable DTLS fuzzer. +- `MS_FUZZ_RTP=1`: Enable RTP fuzzer. +- `MS_FUZZ_RTCP=1`: Enable RTCP fuzzer. +- `MS_FUZZ_UTILS=1`: Enable C++ utils fuzzer. - If none of them is given, then **all** fuzzers are enabled. The log level can also be set by setting the `MS_FUZZ_LOG_LEVEL` environment variable to "debug", "warn" or "error" (it is "none" if unset). diff --git a/worker/fuzzer/src/fuzzer.cpp b/worker/fuzzer/src/fuzzer.cpp index c5a89b1702..403ef2c417 100644 --- a/worker/fuzzer/src/fuzzer.cpp +++ b/worker/fuzzer/src/fuzzer.cpp @@ -96,31 +96,31 @@ int Init() if (std::getenv("MS_FUZZ_STUN") && std::string(std::getenv("MS_FUZZ_STUN")) == "1") { - std::cout << "[fuzzer] STUN fuzzers enabled" << std::endl; + std::cout << "[fuzzer] STUN fuzzer enabled" << std::endl; fuzzStun = true; } if (std::getenv("MS_FUZZ_DTLS") && std::string(std::getenv("MS_FUZZ_DTLS")) == "1") { - std::cout << "[fuzzer] DTLS fuzzers enabled" << std::endl; + std::cout << "[fuzzer] DTLS fuzzer enabled" << std::endl; fuzzDtls = true; } if (std::getenv("MS_FUZZ_RTP") && std::string(std::getenv("MS_FUZZ_RTP")) == "1") { - std::cout << "[fuzzer] RTP fuzzers enabled" << std::endl; + std::cout << "[fuzzer] RTP fuzzer enabled" << std::endl; fuzzRtp = true; } if (std::getenv("MS_FUZZ_RTCP") && std::string(std::getenv("MS_FUZZ_RTCP")) == "1") { - std::cout << "[fuzzer] RTCP fuzzers enabled" << std::endl; + std::cout << "[fuzzer] RTCP fuzzer enabled" << std::endl; fuzzRtcp = true; } if (std::getenv("MS_FUZZ_UTILS") && std::string(std::getenv("MS_FUZZ_UTILS")) == "1") { - std::cout << "[fuzzer] Utils fuzzers enabled" << std::endl; + std::cout << "[fuzzer] Utils fuzzer enabled" << std::endl; fuzzUtils = true; }