Skip to content

Commit

Permalink
Add DTLS fuzzer
Browse files Browse the repository at this point in the history
### 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.
  • Loading branch information
ibc committed Feb 28, 2024
1 parent a6ba853 commit 266a77d
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 2 deletions.
7 changes: 7 additions & 0 deletions doc/Fuzzer.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand Down
39 changes: 39 additions & 0 deletions worker/fuzzer/include/RTC/FuzzerDtlsTransport.hpp
Original file line number Diff line number Diff line change
@@ -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
118 changes: 118 additions & 0 deletions worker/fuzzer/src/RTC/FuzzerDtlsTransport.cpp
Original file line number Diff line number Diff line change
@@ -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");
}
19 changes: 18 additions & 1 deletion worker/fuzzer/src/fuzzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -22,6 +24,7 @@
#include <stdint.h>

bool fuzzStun = false;
bool fuzzDtls = false;
bool fuzzRtp = false;
bool fuzzRtcp = false;
bool fuzzUtils = false;
Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -128,6 +144,7 @@ int Init()
DepUsrSCTP::ClassInit();
DepLibWebRTC::ClassInit();
Utils::Crypto::ClassInit();
::RTC::DtlsTransport::ClassInit();

return 0;
}
3 changes: 2 additions & 1 deletion worker/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down

0 comments on commit 266a77d

Please sign in to comment.