1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker * Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker *
4*d9f75844SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker */
10*d9f75844SAndroid Build Coastguard Worker #include "net/dcsctp/fuzzers/dcsctp_fuzzers.h"
11*d9f75844SAndroid Build Coastguard Worker
12*d9f75844SAndroid Build Coastguard Worker #include <string>
13*d9f75844SAndroid Build Coastguard Worker #include <utility>
14*d9f75844SAndroid Build Coastguard Worker #include <vector>
15*d9f75844SAndroid Build Coastguard Worker
16*d9f75844SAndroid Build Coastguard Worker #include "net/dcsctp/common/math.h"
17*d9f75844SAndroid Build Coastguard Worker #include "net/dcsctp/packet/chunk/cookie_ack_chunk.h"
18*d9f75844SAndroid Build Coastguard Worker #include "net/dcsctp/packet/chunk/cookie_echo_chunk.h"
19*d9f75844SAndroid Build Coastguard Worker #include "net/dcsctp/packet/chunk/data_chunk.h"
20*d9f75844SAndroid Build Coastguard Worker #include "net/dcsctp/packet/chunk/forward_tsn_chunk.h"
21*d9f75844SAndroid Build Coastguard Worker #include "net/dcsctp/packet/chunk/forward_tsn_common.h"
22*d9f75844SAndroid Build Coastguard Worker #include "net/dcsctp/packet/chunk/shutdown_chunk.h"
23*d9f75844SAndroid Build Coastguard Worker #include "net/dcsctp/packet/error_cause/protocol_violation_cause.h"
24*d9f75844SAndroid Build Coastguard Worker #include "net/dcsctp/packet/error_cause/user_initiated_abort_cause.h"
25*d9f75844SAndroid Build Coastguard Worker #include "net/dcsctp/packet/parameter/forward_tsn_supported_parameter.h"
26*d9f75844SAndroid Build Coastguard Worker #include "net/dcsctp/packet/parameter/outgoing_ssn_reset_request_parameter.h"
27*d9f75844SAndroid Build Coastguard Worker #include "net/dcsctp/packet/parameter/state_cookie_parameter.h"
28*d9f75844SAndroid Build Coastguard Worker #include "net/dcsctp/public/dcsctp_message.h"
29*d9f75844SAndroid Build Coastguard Worker #include "net/dcsctp/public/types.h"
30*d9f75844SAndroid Build Coastguard Worker #include "net/dcsctp/socket/dcsctp_socket.h"
31*d9f75844SAndroid Build Coastguard Worker #include "net/dcsctp/socket/state_cookie.h"
32*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
33*d9f75844SAndroid Build Coastguard Worker
34*d9f75844SAndroid Build Coastguard Worker namespace dcsctp {
35*d9f75844SAndroid Build Coastguard Worker namespace dcsctp_fuzzers {
36*d9f75844SAndroid Build Coastguard Worker namespace {
37*d9f75844SAndroid Build Coastguard Worker static constexpr int kRandomValue = FuzzerCallbacks::kRandomValue;
38*d9f75844SAndroid Build Coastguard Worker static constexpr size_t kMinInputLength = 5;
39*d9f75844SAndroid Build Coastguard Worker static constexpr size_t kMaxInputLength = 1024;
40*d9f75844SAndroid Build Coastguard Worker
41*d9f75844SAndroid Build Coastguard Worker // A starting state for the socket, when fuzzing.
42*d9f75844SAndroid Build Coastguard Worker enum class StartingState : int {
43*d9f75844SAndroid Build Coastguard Worker kConnectNotCalled,
44*d9f75844SAndroid Build Coastguard Worker // When socket initiating Connect
45*d9f75844SAndroid Build Coastguard Worker kConnectCalled,
46*d9f75844SAndroid Build Coastguard Worker kReceivedInitAck,
47*d9f75844SAndroid Build Coastguard Worker kReceivedCookieAck,
48*d9f75844SAndroid Build Coastguard Worker // When socket initiating Shutdown
49*d9f75844SAndroid Build Coastguard Worker kShutdownCalled,
50*d9f75844SAndroid Build Coastguard Worker kReceivedShutdownAck,
51*d9f75844SAndroid Build Coastguard Worker // When peer socket initiated Connect
52*d9f75844SAndroid Build Coastguard Worker kReceivedInit,
53*d9f75844SAndroid Build Coastguard Worker kReceivedCookieEcho,
54*d9f75844SAndroid Build Coastguard Worker // When peer initiated Shutdown
55*d9f75844SAndroid Build Coastguard Worker kReceivedShutdown,
56*d9f75844SAndroid Build Coastguard Worker kReceivedShutdownComplete,
57*d9f75844SAndroid Build Coastguard Worker kNumberOfStates,
58*d9f75844SAndroid Build Coastguard Worker };
59*d9f75844SAndroid Build Coastguard Worker
60*d9f75844SAndroid Build Coastguard Worker // State about the current fuzzing iteration
61*d9f75844SAndroid Build Coastguard Worker class FuzzState {
62*d9f75844SAndroid Build Coastguard Worker public:
FuzzState(rtc::ArrayView<const uint8_t> data)63*d9f75844SAndroid Build Coastguard Worker explicit FuzzState(rtc::ArrayView<const uint8_t> data) : data_(data) {}
64*d9f75844SAndroid Build Coastguard Worker
GetByte()65*d9f75844SAndroid Build Coastguard Worker uint8_t GetByte() {
66*d9f75844SAndroid Build Coastguard Worker uint8_t value = 0;
67*d9f75844SAndroid Build Coastguard Worker if (offset_ < data_.size()) {
68*d9f75844SAndroid Build Coastguard Worker value = data_[offset_];
69*d9f75844SAndroid Build Coastguard Worker ++offset_;
70*d9f75844SAndroid Build Coastguard Worker }
71*d9f75844SAndroid Build Coastguard Worker return value;
72*d9f75844SAndroid Build Coastguard Worker }
73*d9f75844SAndroid Build Coastguard Worker
GetNextTSN()74*d9f75844SAndroid Build Coastguard Worker TSN GetNextTSN() { return TSN(tsn_++); }
GetNextMID()75*d9f75844SAndroid Build Coastguard Worker MID GetNextMID() { return MID(mid_++); }
76*d9f75844SAndroid Build Coastguard Worker
empty() const77*d9f75844SAndroid Build Coastguard Worker bool empty() const { return offset_ >= data_.size(); }
78*d9f75844SAndroid Build Coastguard Worker
79*d9f75844SAndroid Build Coastguard Worker private:
80*d9f75844SAndroid Build Coastguard Worker uint32_t tsn_ = kRandomValue;
81*d9f75844SAndroid Build Coastguard Worker uint32_t mid_ = 0;
82*d9f75844SAndroid Build Coastguard Worker rtc::ArrayView<const uint8_t> data_;
83*d9f75844SAndroid Build Coastguard Worker size_t offset_ = 0;
84*d9f75844SAndroid Build Coastguard Worker };
85*d9f75844SAndroid Build Coastguard Worker
SetSocketState(DcSctpSocketInterface & socket,FuzzerCallbacks & socket_cb,StartingState state)86*d9f75844SAndroid Build Coastguard Worker void SetSocketState(DcSctpSocketInterface& socket,
87*d9f75844SAndroid Build Coastguard Worker FuzzerCallbacks& socket_cb,
88*d9f75844SAndroid Build Coastguard Worker StartingState state) {
89*d9f75844SAndroid Build Coastguard Worker // We'll use another temporary peer socket for the establishment.
90*d9f75844SAndroid Build Coastguard Worker FuzzerCallbacks peer_cb;
91*d9f75844SAndroid Build Coastguard Worker DcSctpSocket peer("peer", peer_cb, nullptr, {});
92*d9f75844SAndroid Build Coastguard Worker
93*d9f75844SAndroid Build Coastguard Worker switch (state) {
94*d9f75844SAndroid Build Coastguard Worker case StartingState::kConnectNotCalled:
95*d9f75844SAndroid Build Coastguard Worker return;
96*d9f75844SAndroid Build Coastguard Worker case StartingState::kConnectCalled:
97*d9f75844SAndroid Build Coastguard Worker socket.Connect();
98*d9f75844SAndroid Build Coastguard Worker return;
99*d9f75844SAndroid Build Coastguard Worker case StartingState::kReceivedInitAck:
100*d9f75844SAndroid Build Coastguard Worker socket.Connect();
101*d9f75844SAndroid Build Coastguard Worker peer.ReceivePacket(socket_cb.ConsumeSentPacket()); // INIT
102*d9f75844SAndroid Build Coastguard Worker socket.ReceivePacket(peer_cb.ConsumeSentPacket()); // INIT_ACK
103*d9f75844SAndroid Build Coastguard Worker return;
104*d9f75844SAndroid Build Coastguard Worker case StartingState::kReceivedCookieAck:
105*d9f75844SAndroid Build Coastguard Worker socket.Connect();
106*d9f75844SAndroid Build Coastguard Worker peer.ReceivePacket(socket_cb.ConsumeSentPacket()); // INIT
107*d9f75844SAndroid Build Coastguard Worker socket.ReceivePacket(peer_cb.ConsumeSentPacket()); // INIT_ACK
108*d9f75844SAndroid Build Coastguard Worker peer.ReceivePacket(socket_cb.ConsumeSentPacket()); // COOKIE_ECHO
109*d9f75844SAndroid Build Coastguard Worker socket.ReceivePacket(peer_cb.ConsumeSentPacket()); // COOKIE_ACK
110*d9f75844SAndroid Build Coastguard Worker return;
111*d9f75844SAndroid Build Coastguard Worker case StartingState::kShutdownCalled:
112*d9f75844SAndroid Build Coastguard Worker socket.Connect();
113*d9f75844SAndroid Build Coastguard Worker peer.ReceivePacket(socket_cb.ConsumeSentPacket()); // INIT
114*d9f75844SAndroid Build Coastguard Worker socket.ReceivePacket(peer_cb.ConsumeSentPacket()); // INIT_ACK
115*d9f75844SAndroid Build Coastguard Worker peer.ReceivePacket(socket_cb.ConsumeSentPacket()); // COOKIE_ECHO
116*d9f75844SAndroid Build Coastguard Worker socket.ReceivePacket(peer_cb.ConsumeSentPacket()); // COOKIE_ACK
117*d9f75844SAndroid Build Coastguard Worker socket.Shutdown();
118*d9f75844SAndroid Build Coastguard Worker return;
119*d9f75844SAndroid Build Coastguard Worker case StartingState::kReceivedShutdownAck:
120*d9f75844SAndroid Build Coastguard Worker socket.Connect();
121*d9f75844SAndroid Build Coastguard Worker peer.ReceivePacket(socket_cb.ConsumeSentPacket()); // INIT
122*d9f75844SAndroid Build Coastguard Worker socket.ReceivePacket(peer_cb.ConsumeSentPacket()); // INIT_ACK
123*d9f75844SAndroid Build Coastguard Worker peer.ReceivePacket(socket_cb.ConsumeSentPacket()); // COOKIE_ECHO
124*d9f75844SAndroid Build Coastguard Worker socket.ReceivePacket(peer_cb.ConsumeSentPacket()); // COOKIE_ACK
125*d9f75844SAndroid Build Coastguard Worker socket.Shutdown();
126*d9f75844SAndroid Build Coastguard Worker peer.ReceivePacket(socket_cb.ConsumeSentPacket()); // SHUTDOWN
127*d9f75844SAndroid Build Coastguard Worker socket.ReceivePacket(peer_cb.ConsumeSentPacket()); // SHUTDOWN_ACK
128*d9f75844SAndroid Build Coastguard Worker return;
129*d9f75844SAndroid Build Coastguard Worker case StartingState::kReceivedInit:
130*d9f75844SAndroid Build Coastguard Worker peer.Connect();
131*d9f75844SAndroid Build Coastguard Worker socket.ReceivePacket(peer_cb.ConsumeSentPacket()); // INIT
132*d9f75844SAndroid Build Coastguard Worker return;
133*d9f75844SAndroid Build Coastguard Worker case StartingState::kReceivedCookieEcho:
134*d9f75844SAndroid Build Coastguard Worker peer.Connect();
135*d9f75844SAndroid Build Coastguard Worker socket.ReceivePacket(peer_cb.ConsumeSentPacket()); // INIT
136*d9f75844SAndroid Build Coastguard Worker peer.ReceivePacket(socket_cb.ConsumeSentPacket()); // INIT_ACK
137*d9f75844SAndroid Build Coastguard Worker socket.ReceivePacket(peer_cb.ConsumeSentPacket()); // COOKIE_ECHO
138*d9f75844SAndroid Build Coastguard Worker return;
139*d9f75844SAndroid Build Coastguard Worker case StartingState::kReceivedShutdown:
140*d9f75844SAndroid Build Coastguard Worker socket.Connect();
141*d9f75844SAndroid Build Coastguard Worker peer.ReceivePacket(socket_cb.ConsumeSentPacket()); // INIT
142*d9f75844SAndroid Build Coastguard Worker socket.ReceivePacket(peer_cb.ConsumeSentPacket()); // INIT_ACK
143*d9f75844SAndroid Build Coastguard Worker peer.ReceivePacket(socket_cb.ConsumeSentPacket()); // COOKIE_ECHO
144*d9f75844SAndroid Build Coastguard Worker socket.ReceivePacket(peer_cb.ConsumeSentPacket()); // COOKIE_ACK
145*d9f75844SAndroid Build Coastguard Worker peer.Shutdown();
146*d9f75844SAndroid Build Coastguard Worker socket.ReceivePacket(peer_cb.ConsumeSentPacket()); // SHUTDOWN
147*d9f75844SAndroid Build Coastguard Worker return;
148*d9f75844SAndroid Build Coastguard Worker case StartingState::kReceivedShutdownComplete:
149*d9f75844SAndroid Build Coastguard Worker socket.Connect();
150*d9f75844SAndroid Build Coastguard Worker peer.ReceivePacket(socket_cb.ConsumeSentPacket()); // INIT
151*d9f75844SAndroid Build Coastguard Worker socket.ReceivePacket(peer_cb.ConsumeSentPacket()); // INIT_ACK
152*d9f75844SAndroid Build Coastguard Worker peer.ReceivePacket(socket_cb.ConsumeSentPacket()); // COOKIE_ECHO
153*d9f75844SAndroid Build Coastguard Worker socket.ReceivePacket(peer_cb.ConsumeSentPacket()); // COOKIE_ACK
154*d9f75844SAndroid Build Coastguard Worker peer.Shutdown();
155*d9f75844SAndroid Build Coastguard Worker socket.ReceivePacket(peer_cb.ConsumeSentPacket()); // SHUTDOWN
156*d9f75844SAndroid Build Coastguard Worker peer.ReceivePacket(socket_cb.ConsumeSentPacket()); // SHUTDOWN_ACK
157*d9f75844SAndroid Build Coastguard Worker socket.ReceivePacket(peer_cb.ConsumeSentPacket()); // SHUTDOWN_COMPLETE
158*d9f75844SAndroid Build Coastguard Worker return;
159*d9f75844SAndroid Build Coastguard Worker case StartingState::kNumberOfStates:
160*d9f75844SAndroid Build Coastguard Worker RTC_CHECK(false);
161*d9f75844SAndroid Build Coastguard Worker return;
162*d9f75844SAndroid Build Coastguard Worker }
163*d9f75844SAndroid Build Coastguard Worker }
164*d9f75844SAndroid Build Coastguard Worker
MakeDataChunk(FuzzState & state,SctpPacket::Builder & b)165*d9f75844SAndroid Build Coastguard Worker void MakeDataChunk(FuzzState& state, SctpPacket::Builder& b) {
166*d9f75844SAndroid Build Coastguard Worker DataChunk::Options options;
167*d9f75844SAndroid Build Coastguard Worker options.is_unordered = IsUnordered(state.GetByte() != 0);
168*d9f75844SAndroid Build Coastguard Worker options.is_beginning = Data::IsBeginning(state.GetByte() != 0);
169*d9f75844SAndroid Build Coastguard Worker options.is_end = Data::IsEnd(state.GetByte() != 0);
170*d9f75844SAndroid Build Coastguard Worker b.Add(DataChunk(state.GetNextTSN(), StreamID(state.GetByte()),
171*d9f75844SAndroid Build Coastguard Worker SSN(state.GetByte()), PPID(53), std::vector<uint8_t>(10),
172*d9f75844SAndroid Build Coastguard Worker options));
173*d9f75844SAndroid Build Coastguard Worker }
174*d9f75844SAndroid Build Coastguard Worker
MakeInitChunk(FuzzState & state,SctpPacket::Builder & b)175*d9f75844SAndroid Build Coastguard Worker void MakeInitChunk(FuzzState& state, SctpPacket::Builder& b) {
176*d9f75844SAndroid Build Coastguard Worker Parameters::Builder builder;
177*d9f75844SAndroid Build Coastguard Worker builder.Add(ForwardTsnSupportedParameter());
178*d9f75844SAndroid Build Coastguard Worker
179*d9f75844SAndroid Build Coastguard Worker b.Add(InitChunk(VerificationTag(kRandomValue), 10000, 1000, 1000,
180*d9f75844SAndroid Build Coastguard Worker TSN(kRandomValue), builder.Build()));
181*d9f75844SAndroid Build Coastguard Worker }
182*d9f75844SAndroid Build Coastguard Worker
MakeInitAckChunk(FuzzState & state,SctpPacket::Builder & b)183*d9f75844SAndroid Build Coastguard Worker void MakeInitAckChunk(FuzzState& state, SctpPacket::Builder& b) {
184*d9f75844SAndroid Build Coastguard Worker Parameters::Builder builder;
185*d9f75844SAndroid Build Coastguard Worker builder.Add(ForwardTsnSupportedParameter());
186*d9f75844SAndroid Build Coastguard Worker
187*d9f75844SAndroid Build Coastguard Worker uint8_t state_cookie[] = {1, 2, 3, 4, 5};
188*d9f75844SAndroid Build Coastguard Worker Parameters::Builder params_builder =
189*d9f75844SAndroid Build Coastguard Worker Parameters::Builder().Add(StateCookieParameter(state_cookie));
190*d9f75844SAndroid Build Coastguard Worker
191*d9f75844SAndroid Build Coastguard Worker b.Add(InitAckChunk(VerificationTag(kRandomValue), 10000, 1000, 1000,
192*d9f75844SAndroid Build Coastguard Worker TSN(kRandomValue), builder.Build()));
193*d9f75844SAndroid Build Coastguard Worker }
194*d9f75844SAndroid Build Coastguard Worker
MakeSackChunk(FuzzState & state,SctpPacket::Builder & b)195*d9f75844SAndroid Build Coastguard Worker void MakeSackChunk(FuzzState& state, SctpPacket::Builder& b) {
196*d9f75844SAndroid Build Coastguard Worker std::vector<SackChunk::GapAckBlock> gap_ack_blocks;
197*d9f75844SAndroid Build Coastguard Worker uint16_t last_end = 0;
198*d9f75844SAndroid Build Coastguard Worker while (gap_ack_blocks.size() < 20) {
199*d9f75844SAndroid Build Coastguard Worker uint8_t delta_start = state.GetByte();
200*d9f75844SAndroid Build Coastguard Worker if (delta_start < 0x80) {
201*d9f75844SAndroid Build Coastguard Worker break;
202*d9f75844SAndroid Build Coastguard Worker }
203*d9f75844SAndroid Build Coastguard Worker uint8_t delta_end = state.GetByte();
204*d9f75844SAndroid Build Coastguard Worker
205*d9f75844SAndroid Build Coastguard Worker uint16_t start = last_end + delta_start;
206*d9f75844SAndroid Build Coastguard Worker uint16_t end = start + delta_end;
207*d9f75844SAndroid Build Coastguard Worker last_end = end;
208*d9f75844SAndroid Build Coastguard Worker gap_ack_blocks.emplace_back(start, end);
209*d9f75844SAndroid Build Coastguard Worker }
210*d9f75844SAndroid Build Coastguard Worker
211*d9f75844SAndroid Build Coastguard Worker TSN cum_ack_tsn(kRandomValue + state.GetByte());
212*d9f75844SAndroid Build Coastguard Worker b.Add(SackChunk(cum_ack_tsn, 10000, std::move(gap_ack_blocks), {}));
213*d9f75844SAndroid Build Coastguard Worker }
214*d9f75844SAndroid Build Coastguard Worker
MakeHeartbeatRequestChunk(FuzzState & state,SctpPacket::Builder & b)215*d9f75844SAndroid Build Coastguard Worker void MakeHeartbeatRequestChunk(FuzzState& state, SctpPacket::Builder& b) {
216*d9f75844SAndroid Build Coastguard Worker uint8_t info[] = {1, 2, 3, 4, 5};
217*d9f75844SAndroid Build Coastguard Worker b.Add(HeartbeatRequestChunk(
218*d9f75844SAndroid Build Coastguard Worker Parameters::Builder().Add(HeartbeatInfoParameter(info)).Build()));
219*d9f75844SAndroid Build Coastguard Worker }
220*d9f75844SAndroid Build Coastguard Worker
MakeHeartbeatAckChunk(FuzzState & state,SctpPacket::Builder & b)221*d9f75844SAndroid Build Coastguard Worker void MakeHeartbeatAckChunk(FuzzState& state, SctpPacket::Builder& b) {
222*d9f75844SAndroid Build Coastguard Worker std::vector<uint8_t> info(8);
223*d9f75844SAndroid Build Coastguard Worker b.Add(HeartbeatRequestChunk(
224*d9f75844SAndroid Build Coastguard Worker Parameters::Builder().Add(HeartbeatInfoParameter(info)).Build()));
225*d9f75844SAndroid Build Coastguard Worker }
226*d9f75844SAndroid Build Coastguard Worker
MakeAbortChunk(FuzzState & state,SctpPacket::Builder & b)227*d9f75844SAndroid Build Coastguard Worker void MakeAbortChunk(FuzzState& state, SctpPacket::Builder& b) {
228*d9f75844SAndroid Build Coastguard Worker b.Add(AbortChunk(
229*d9f75844SAndroid Build Coastguard Worker /*filled_in_verification_tag=*/true,
230*d9f75844SAndroid Build Coastguard Worker Parameters::Builder().Add(UserInitiatedAbortCause("Fuzzing")).Build()));
231*d9f75844SAndroid Build Coastguard Worker }
232*d9f75844SAndroid Build Coastguard Worker
MakeErrorChunk(FuzzState & state,SctpPacket::Builder & b)233*d9f75844SAndroid Build Coastguard Worker void MakeErrorChunk(FuzzState& state, SctpPacket::Builder& b) {
234*d9f75844SAndroid Build Coastguard Worker b.Add(ErrorChunk(
235*d9f75844SAndroid Build Coastguard Worker Parameters::Builder().Add(ProtocolViolationCause("Fuzzing")).Build()));
236*d9f75844SAndroid Build Coastguard Worker }
237*d9f75844SAndroid Build Coastguard Worker
MakeCookieEchoChunk(FuzzState & state,SctpPacket::Builder & b)238*d9f75844SAndroid Build Coastguard Worker void MakeCookieEchoChunk(FuzzState& state, SctpPacket::Builder& b) {
239*d9f75844SAndroid Build Coastguard Worker std::vector<uint8_t> cookie(StateCookie::kCookieSize);
240*d9f75844SAndroid Build Coastguard Worker b.Add(CookieEchoChunk(cookie));
241*d9f75844SAndroid Build Coastguard Worker }
242*d9f75844SAndroid Build Coastguard Worker
MakeCookieAckChunk(FuzzState & state,SctpPacket::Builder & b)243*d9f75844SAndroid Build Coastguard Worker void MakeCookieAckChunk(FuzzState& state, SctpPacket::Builder& b) {
244*d9f75844SAndroid Build Coastguard Worker b.Add(CookieAckChunk());
245*d9f75844SAndroid Build Coastguard Worker }
246*d9f75844SAndroid Build Coastguard Worker
MakeShutdownChunk(FuzzState & state,SctpPacket::Builder & b)247*d9f75844SAndroid Build Coastguard Worker void MakeShutdownChunk(FuzzState& state, SctpPacket::Builder& b) {
248*d9f75844SAndroid Build Coastguard Worker b.Add(ShutdownChunk(state.GetNextTSN()));
249*d9f75844SAndroid Build Coastguard Worker }
250*d9f75844SAndroid Build Coastguard Worker
MakeShutdownAckChunk(FuzzState & state,SctpPacket::Builder & b)251*d9f75844SAndroid Build Coastguard Worker void MakeShutdownAckChunk(FuzzState& state, SctpPacket::Builder& b) {
252*d9f75844SAndroid Build Coastguard Worker b.Add(ShutdownAckChunk());
253*d9f75844SAndroid Build Coastguard Worker }
254*d9f75844SAndroid Build Coastguard Worker
MakeShutdownCompleteChunk(FuzzState & state,SctpPacket::Builder & b)255*d9f75844SAndroid Build Coastguard Worker void MakeShutdownCompleteChunk(FuzzState& state, SctpPacket::Builder& b) {
256*d9f75844SAndroid Build Coastguard Worker b.Add(ShutdownCompleteChunk(false));
257*d9f75844SAndroid Build Coastguard Worker }
258*d9f75844SAndroid Build Coastguard Worker
MakeReConfigChunk(FuzzState & state,SctpPacket::Builder & b)259*d9f75844SAndroid Build Coastguard Worker void MakeReConfigChunk(FuzzState& state, SctpPacket::Builder& b) {
260*d9f75844SAndroid Build Coastguard Worker std::vector<StreamID> streams = {StreamID(state.GetByte())};
261*d9f75844SAndroid Build Coastguard Worker Parameters::Builder params_builder =
262*d9f75844SAndroid Build Coastguard Worker Parameters::Builder().Add(OutgoingSSNResetRequestParameter(
263*d9f75844SAndroid Build Coastguard Worker ReconfigRequestSN(kRandomValue), ReconfigRequestSN(kRandomValue),
264*d9f75844SAndroid Build Coastguard Worker state.GetNextTSN(), streams));
265*d9f75844SAndroid Build Coastguard Worker b.Add(ReConfigChunk(params_builder.Build()));
266*d9f75844SAndroid Build Coastguard Worker }
267*d9f75844SAndroid Build Coastguard Worker
MakeForwardTsnChunk(FuzzState & state,SctpPacket::Builder & b)268*d9f75844SAndroid Build Coastguard Worker void MakeForwardTsnChunk(FuzzState& state, SctpPacket::Builder& b) {
269*d9f75844SAndroid Build Coastguard Worker std::vector<ForwardTsnChunk::SkippedStream> skipped_streams;
270*d9f75844SAndroid Build Coastguard Worker for (;;) {
271*d9f75844SAndroid Build Coastguard Worker uint8_t stream = state.GetByte();
272*d9f75844SAndroid Build Coastguard Worker if (skipped_streams.size() > 20 || stream < 0x80) {
273*d9f75844SAndroid Build Coastguard Worker break;
274*d9f75844SAndroid Build Coastguard Worker }
275*d9f75844SAndroid Build Coastguard Worker skipped_streams.emplace_back(StreamID(stream), SSN(state.GetByte()));
276*d9f75844SAndroid Build Coastguard Worker }
277*d9f75844SAndroid Build Coastguard Worker b.Add(ForwardTsnChunk(state.GetNextTSN(), std::move(skipped_streams)));
278*d9f75844SAndroid Build Coastguard Worker }
279*d9f75844SAndroid Build Coastguard Worker
MakeIDataChunk(FuzzState & state,SctpPacket::Builder & b)280*d9f75844SAndroid Build Coastguard Worker void MakeIDataChunk(FuzzState& state, SctpPacket::Builder& b) {
281*d9f75844SAndroid Build Coastguard Worker DataChunk::Options options;
282*d9f75844SAndroid Build Coastguard Worker options.is_unordered = IsUnordered(state.GetByte() != 0);
283*d9f75844SAndroid Build Coastguard Worker options.is_beginning = Data::IsBeginning(state.GetByte() != 0);
284*d9f75844SAndroid Build Coastguard Worker options.is_end = Data::IsEnd(state.GetByte() != 0);
285*d9f75844SAndroid Build Coastguard Worker b.Add(IDataChunk(state.GetNextTSN(), StreamID(state.GetByte()),
286*d9f75844SAndroid Build Coastguard Worker state.GetNextMID(), PPID(53), FSN(0),
287*d9f75844SAndroid Build Coastguard Worker std::vector<uint8_t>(10), options));
288*d9f75844SAndroid Build Coastguard Worker }
289*d9f75844SAndroid Build Coastguard Worker
MakeIForwardTsnChunk(FuzzState & state,SctpPacket::Builder & b)290*d9f75844SAndroid Build Coastguard Worker void MakeIForwardTsnChunk(FuzzState& state, SctpPacket::Builder& b) {
291*d9f75844SAndroid Build Coastguard Worker std::vector<ForwardTsnChunk::SkippedStream> skipped_streams;
292*d9f75844SAndroid Build Coastguard Worker for (;;) {
293*d9f75844SAndroid Build Coastguard Worker uint8_t stream = state.GetByte();
294*d9f75844SAndroid Build Coastguard Worker if (skipped_streams.size() > 20 || stream < 0x80) {
295*d9f75844SAndroid Build Coastguard Worker break;
296*d9f75844SAndroid Build Coastguard Worker }
297*d9f75844SAndroid Build Coastguard Worker skipped_streams.emplace_back(StreamID(stream), SSN(state.GetByte()));
298*d9f75844SAndroid Build Coastguard Worker }
299*d9f75844SAndroid Build Coastguard Worker b.Add(IForwardTsnChunk(state.GetNextTSN(), std::move(skipped_streams)));
300*d9f75844SAndroid Build Coastguard Worker }
301*d9f75844SAndroid Build Coastguard Worker
302*d9f75844SAndroid Build Coastguard Worker class RandomFuzzedChunk : public Chunk {
303*d9f75844SAndroid Build Coastguard Worker public:
RandomFuzzedChunk(FuzzState & state)304*d9f75844SAndroid Build Coastguard Worker explicit RandomFuzzedChunk(FuzzState& state) : state_(state) {}
305*d9f75844SAndroid Build Coastguard Worker
SerializeTo(std::vector<uint8_t> & out) const306*d9f75844SAndroid Build Coastguard Worker void SerializeTo(std::vector<uint8_t>& out) const override {
307*d9f75844SAndroid Build Coastguard Worker size_t bytes = state_.GetByte();
308*d9f75844SAndroid Build Coastguard Worker for (size_t i = 0; i < bytes; ++i) {
309*d9f75844SAndroid Build Coastguard Worker out.push_back(state_.GetByte());
310*d9f75844SAndroid Build Coastguard Worker }
311*d9f75844SAndroid Build Coastguard Worker }
312*d9f75844SAndroid Build Coastguard Worker
ToString() const313*d9f75844SAndroid Build Coastguard Worker std::string ToString() const override { return std::string("RANDOM_FUZZED"); }
314*d9f75844SAndroid Build Coastguard Worker
315*d9f75844SAndroid Build Coastguard Worker private:
316*d9f75844SAndroid Build Coastguard Worker FuzzState& state_;
317*d9f75844SAndroid Build Coastguard Worker };
318*d9f75844SAndroid Build Coastguard Worker
MakeChunkWithRandomContent(FuzzState & state,SctpPacket::Builder & b)319*d9f75844SAndroid Build Coastguard Worker void MakeChunkWithRandomContent(FuzzState& state, SctpPacket::Builder& b) {
320*d9f75844SAndroid Build Coastguard Worker b.Add(RandomFuzzedChunk(state));
321*d9f75844SAndroid Build Coastguard Worker }
322*d9f75844SAndroid Build Coastguard Worker
GeneratePacket(FuzzState & state)323*d9f75844SAndroid Build Coastguard Worker std::vector<uint8_t> GeneratePacket(FuzzState& state) {
324*d9f75844SAndroid Build Coastguard Worker DcSctpOptions options;
325*d9f75844SAndroid Build Coastguard Worker // Setting a fixed limit to not be dependent on the defaults, which may
326*d9f75844SAndroid Build Coastguard Worker // change.
327*d9f75844SAndroid Build Coastguard Worker options.mtu = 2048;
328*d9f75844SAndroid Build Coastguard Worker SctpPacket::Builder builder(VerificationTag(kRandomValue), options);
329*d9f75844SAndroid Build Coastguard Worker
330*d9f75844SAndroid Build Coastguard Worker // The largest expected serialized chunk, as created by fuzzers.
331*d9f75844SAndroid Build Coastguard Worker static constexpr size_t kMaxChunkSize = 256;
332*d9f75844SAndroid Build Coastguard Worker
333*d9f75844SAndroid Build Coastguard Worker for (int i = 0; i < 5 && builder.bytes_remaining() > kMaxChunkSize; ++i) {
334*d9f75844SAndroid Build Coastguard Worker switch (state.GetByte()) {
335*d9f75844SAndroid Build Coastguard Worker case 1:
336*d9f75844SAndroid Build Coastguard Worker MakeDataChunk(state, builder);
337*d9f75844SAndroid Build Coastguard Worker break;
338*d9f75844SAndroid Build Coastguard Worker case 2:
339*d9f75844SAndroid Build Coastguard Worker MakeInitChunk(state, builder);
340*d9f75844SAndroid Build Coastguard Worker break;
341*d9f75844SAndroid Build Coastguard Worker case 3:
342*d9f75844SAndroid Build Coastguard Worker MakeInitAckChunk(state, builder);
343*d9f75844SAndroid Build Coastguard Worker break;
344*d9f75844SAndroid Build Coastguard Worker case 4:
345*d9f75844SAndroid Build Coastguard Worker MakeSackChunk(state, builder);
346*d9f75844SAndroid Build Coastguard Worker break;
347*d9f75844SAndroid Build Coastguard Worker case 5:
348*d9f75844SAndroid Build Coastguard Worker MakeHeartbeatRequestChunk(state, builder);
349*d9f75844SAndroid Build Coastguard Worker break;
350*d9f75844SAndroid Build Coastguard Worker case 6:
351*d9f75844SAndroid Build Coastguard Worker MakeHeartbeatAckChunk(state, builder);
352*d9f75844SAndroid Build Coastguard Worker break;
353*d9f75844SAndroid Build Coastguard Worker case 7:
354*d9f75844SAndroid Build Coastguard Worker MakeAbortChunk(state, builder);
355*d9f75844SAndroid Build Coastguard Worker break;
356*d9f75844SAndroid Build Coastguard Worker case 8:
357*d9f75844SAndroid Build Coastguard Worker MakeErrorChunk(state, builder);
358*d9f75844SAndroid Build Coastguard Worker break;
359*d9f75844SAndroid Build Coastguard Worker case 9:
360*d9f75844SAndroid Build Coastguard Worker MakeCookieEchoChunk(state, builder);
361*d9f75844SAndroid Build Coastguard Worker break;
362*d9f75844SAndroid Build Coastguard Worker case 10:
363*d9f75844SAndroid Build Coastguard Worker MakeCookieAckChunk(state, builder);
364*d9f75844SAndroid Build Coastguard Worker break;
365*d9f75844SAndroid Build Coastguard Worker case 11:
366*d9f75844SAndroid Build Coastguard Worker MakeShutdownChunk(state, builder);
367*d9f75844SAndroid Build Coastguard Worker break;
368*d9f75844SAndroid Build Coastguard Worker case 12:
369*d9f75844SAndroid Build Coastguard Worker MakeShutdownAckChunk(state, builder);
370*d9f75844SAndroid Build Coastguard Worker break;
371*d9f75844SAndroid Build Coastguard Worker case 13:
372*d9f75844SAndroid Build Coastguard Worker MakeShutdownCompleteChunk(state, builder);
373*d9f75844SAndroid Build Coastguard Worker break;
374*d9f75844SAndroid Build Coastguard Worker case 14:
375*d9f75844SAndroid Build Coastguard Worker MakeReConfigChunk(state, builder);
376*d9f75844SAndroid Build Coastguard Worker break;
377*d9f75844SAndroid Build Coastguard Worker case 15:
378*d9f75844SAndroid Build Coastguard Worker MakeForwardTsnChunk(state, builder);
379*d9f75844SAndroid Build Coastguard Worker break;
380*d9f75844SAndroid Build Coastguard Worker case 16:
381*d9f75844SAndroid Build Coastguard Worker MakeIDataChunk(state, builder);
382*d9f75844SAndroid Build Coastguard Worker break;
383*d9f75844SAndroid Build Coastguard Worker case 17:
384*d9f75844SAndroid Build Coastguard Worker MakeIForwardTsnChunk(state, builder);
385*d9f75844SAndroid Build Coastguard Worker break;
386*d9f75844SAndroid Build Coastguard Worker case 18:
387*d9f75844SAndroid Build Coastguard Worker MakeChunkWithRandomContent(state, builder);
388*d9f75844SAndroid Build Coastguard Worker break;
389*d9f75844SAndroid Build Coastguard Worker default:
390*d9f75844SAndroid Build Coastguard Worker break;
391*d9f75844SAndroid Build Coastguard Worker }
392*d9f75844SAndroid Build Coastguard Worker }
393*d9f75844SAndroid Build Coastguard Worker std::vector<uint8_t> packet = builder.Build();
394*d9f75844SAndroid Build Coastguard Worker return packet;
395*d9f75844SAndroid Build Coastguard Worker }
396*d9f75844SAndroid Build Coastguard Worker } // namespace
397*d9f75844SAndroid Build Coastguard Worker
FuzzSocket(DcSctpSocketInterface & socket,FuzzerCallbacks & cb,rtc::ArrayView<const uint8_t> data)398*d9f75844SAndroid Build Coastguard Worker void FuzzSocket(DcSctpSocketInterface& socket,
399*d9f75844SAndroid Build Coastguard Worker FuzzerCallbacks& cb,
400*d9f75844SAndroid Build Coastguard Worker rtc::ArrayView<const uint8_t> data) {
401*d9f75844SAndroid Build Coastguard Worker if (data.size() < kMinInputLength || data.size() > kMaxInputLength) {
402*d9f75844SAndroid Build Coastguard Worker return;
403*d9f75844SAndroid Build Coastguard Worker }
404*d9f75844SAndroid Build Coastguard Worker if (data[0] >= static_cast<int>(StartingState::kNumberOfStates)) {
405*d9f75844SAndroid Build Coastguard Worker return;
406*d9f75844SAndroid Build Coastguard Worker }
407*d9f75844SAndroid Build Coastguard Worker
408*d9f75844SAndroid Build Coastguard Worker // Set the socket in a specified valid starting state
409*d9f75844SAndroid Build Coastguard Worker SetSocketState(socket, cb, static_cast<StartingState>(data[0]));
410*d9f75844SAndroid Build Coastguard Worker
411*d9f75844SAndroid Build Coastguard Worker FuzzState state(data.subview(1));
412*d9f75844SAndroid Build Coastguard Worker
413*d9f75844SAndroid Build Coastguard Worker while (!state.empty()) {
414*d9f75844SAndroid Build Coastguard Worker switch (state.GetByte()) {
415*d9f75844SAndroid Build Coastguard Worker case 1:
416*d9f75844SAndroid Build Coastguard Worker // Generate a valid SCTP packet (based on fuzz data) and "receive it".
417*d9f75844SAndroid Build Coastguard Worker socket.ReceivePacket(GeneratePacket(state));
418*d9f75844SAndroid Build Coastguard Worker break;
419*d9f75844SAndroid Build Coastguard Worker case 2:
420*d9f75844SAndroid Build Coastguard Worker socket.Connect();
421*d9f75844SAndroid Build Coastguard Worker break;
422*d9f75844SAndroid Build Coastguard Worker case 3:
423*d9f75844SAndroid Build Coastguard Worker socket.Shutdown();
424*d9f75844SAndroid Build Coastguard Worker break;
425*d9f75844SAndroid Build Coastguard Worker case 4:
426*d9f75844SAndroid Build Coastguard Worker socket.Close();
427*d9f75844SAndroid Build Coastguard Worker break;
428*d9f75844SAndroid Build Coastguard Worker case 5: {
429*d9f75844SAndroid Build Coastguard Worker StreamID streams[] = {StreamID(state.GetByte())};
430*d9f75844SAndroid Build Coastguard Worker socket.ResetStreams(streams);
431*d9f75844SAndroid Build Coastguard Worker } break;
432*d9f75844SAndroid Build Coastguard Worker case 6: {
433*d9f75844SAndroid Build Coastguard Worker uint8_t flags = state.GetByte();
434*d9f75844SAndroid Build Coastguard Worker SendOptions options;
435*d9f75844SAndroid Build Coastguard Worker options.unordered = IsUnordered(flags & 0x01);
436*d9f75844SAndroid Build Coastguard Worker options.max_retransmissions =
437*d9f75844SAndroid Build Coastguard Worker (flags & 0x02) != 0 ? absl::make_optional(0) : absl::nullopt;
438*d9f75844SAndroid Build Coastguard Worker options.lifecycle_id = LifecycleId(42);
439*d9f75844SAndroid Build Coastguard Worker size_t payload_exponent = (flags >> 2) % 16;
440*d9f75844SAndroid Build Coastguard Worker size_t payload_size = static_cast<size_t>(1) << payload_exponent;
441*d9f75844SAndroid Build Coastguard Worker socket.Send(DcSctpMessage(StreamID(state.GetByte()), PPID(53),
442*d9f75844SAndroid Build Coastguard Worker std::vector<uint8_t>(payload_size)),
443*d9f75844SAndroid Build Coastguard Worker options);
444*d9f75844SAndroid Build Coastguard Worker break;
445*d9f75844SAndroid Build Coastguard Worker }
446*d9f75844SAndroid Build Coastguard Worker case 7: {
447*d9f75844SAndroid Build Coastguard Worker // Expire an active timeout/timer.
448*d9f75844SAndroid Build Coastguard Worker uint8_t timeout_idx = state.GetByte();
449*d9f75844SAndroid Build Coastguard Worker absl::optional<TimeoutID> timeout_id = cb.ExpireTimeout(timeout_idx);
450*d9f75844SAndroid Build Coastguard Worker if (timeout_id.has_value()) {
451*d9f75844SAndroid Build Coastguard Worker socket.HandleTimeout(*timeout_id);
452*d9f75844SAndroid Build Coastguard Worker }
453*d9f75844SAndroid Build Coastguard Worker break;
454*d9f75844SAndroid Build Coastguard Worker }
455*d9f75844SAndroid Build Coastguard Worker default:
456*d9f75844SAndroid Build Coastguard Worker break;
457*d9f75844SAndroid Build Coastguard Worker }
458*d9f75844SAndroid Build Coastguard Worker }
459*d9f75844SAndroid Build Coastguard Worker }
460*d9f75844SAndroid Build Coastguard Worker } // namespace dcsctp_fuzzers
461*d9f75844SAndroid Build Coastguard Worker } // namespace dcsctp
462