1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include <fuzzer/FuzzedDataProvider.h>
17 #include <media/stagefright/foundation/AString.h>
18 #include <media/stagefright/foundation/base64.h>
19 #include <media/stagefright/rtsp/APacketSource.h>
20 #include <media/stagefright/rtsp/ASessionDescription.h>
21
22 using namespace android;
23
24 static constexpr int32_t kMinValue = 0;
25 static constexpr int32_t kMaxIPAddress = 255;
26 static constexpr int32_t kMaxFmt = 255;
27 static constexpr int32_t kMinAPICase = 0;
28 static constexpr int32_t kMaxPacketSourceAPI = 5;
29 static constexpr size_t kMinIndex = 1;
30 static constexpr size_t kMaxCodecConfigs = 4;
31
32 std::string kCodecs[] = {"opus", "ISAC", "VP8",
33 "google-data", "G722", "PCMU",
34 "PCMA", "CN", "telephone-event",
35 "VP9", "red", "ulpfec",
36 "rtx", "H264", "iLBC",
37 "H261", "MPV", "H263",
38 "AMR", "AC3", "G723",
39 "G729A", "H264", "MP4V-ES",
40 "H265", "H263-2000", "H263-1998",
41 "AMR", "AMR-WB", "MP4A-LATM",
42 "MP2T", "mpeg4-generic"};
43
44 std::string kFmtp[] = {"br=",
45 "bw=",
46 "ch-aw-recv=",
47 "mode-change-capability=",
48 "max-red =",
49 "octet-align=",
50 "mode-change-capability=",
51 "max-red=",
52 "profile-level-id=",
53 "packetization-mode=",
54 "profile=",
55 "level=",
56 "apt=",
57 "annexb=",
58 "protocol=",
59 "streamtype=",
60 "mode=",
61 "sizelength=",
62 "indexlength=",
63 "indexdeltalength=",
64 "minptime=",
65 "useinbandfec=",
66 "maxplaybackrate=",
67 "stereo=",
68 "level-asymmetry-allowed=",
69 "max-fs=",
70 "max-fr="};
71
72 std::string kCodecConfigString[kMaxCodecConfigs][2] = {{"H264", "profile-level-id="},
73 {"MP4A-LATM", "config="},
74 {"MP4V-ES", "config="},
75 {"mpeg4-generic", "mode="}};
76
77 class ASessionPacketFuzzer {
78 public:
ASessionPacketFuzzer(const uint8_t * data,size_t size)79 ASessionPacketFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
80 void process();
81
82 private:
83 FuzzedDataProvider mFdp;
84 };
85
checkFormatSupport(const std::string & codec,const std::string & format)86 bool checkFormatSupport(const std::string& codec, const std::string& format) {
87 for (int i = 0; i < kMaxCodecConfigs; ++i) {
88 if (codec == kCodecConfigString[i][0]) {
89 if (format == kCodecConfigString[i][1]) {
90 return true;
91 } else {
92 return false;
93 }
94 }
95 }
96 return true;
97 }
98
process()99 void ASessionPacketFuzzer::process() {
100 AString inputString;
101 const sp<ASessionDescription> sessionPacket = sp<ASessionDescription>::make();
102 std::string codec = mFdp.PickValueInArray(kCodecs);
103 std::string ipAddress =
104 std::to_string(mFdp.ConsumeIntegralInRange(kMinValue, kMaxIPAddress)) + "." +
105 std::to_string(mFdp.ConsumeIntegralInRange(kMinValue, kMaxIPAddress)) + "." +
106 std::to_string(mFdp.ConsumeIntegralInRange(kMinValue, kMaxIPAddress)) + "." + "0";
107 std::string format = mFdp.PickValueInArray(kFmtp);
108 std::string fmptStr = format + std::to_string(mFdp.ConsumeIntegralInRange(kMinValue, kMaxFmt)) +
109 ";" + mFdp.PickValueInArray(kFmtp) +
110 std::to_string(mFdp.ConsumeIntegralInRange(kMinValue, kMaxFmt));
111 sessionPacket->SDPStringFactory(
112 inputString, ipAddress.c_str() /* ip */, mFdp.ConsumeBool() /* isAudio */,
113 mFdp.ConsumeIntegral<unsigned int>() /* port */,
114 mFdp.ConsumeIntegral<unsigned int>() /* payloadType */,
115 mFdp.ConsumeIntegral<unsigned int>() /* as */, codec.c_str(), /* codec */
116 fmptStr.c_str() /* fmtp */, mFdp.ConsumeIntegral<int32_t>() /* width */,
117 mFdp.ConsumeIntegral<int32_t>() /* height */,
118 mFdp.ConsumeIntegral<int32_t>() /* cvoExtMap */);
119 sessionPacket->setTo(inputString.c_str(), inputString.size());
120 size_t trackSize = sessionPacket->countTracks();
121 AString desc = nullptr;
122 while (mFdp.remaining_bytes()) {
123 int32_t packetSourceAPI =
124 mFdp.ConsumeIntegralInRange<size_t>(kMinAPICase, kMaxPacketSourceAPI);
125 switch (packetSourceAPI) {
126 case 0: {
127 unsigned long payload = 0;
128 AString params = nullptr;
129 sessionPacket->getFormatType(mFdp.ConsumeIntegralInRange(kMinIndex, trackSize - 1),
130 &payload, &desc, ¶ms);
131 break;
132 }
133 case 1: {
134 int32_t width, height;
135 unsigned long payload = mFdp.ConsumeIntegral<unsigned long>();
136 sessionPacket->getDimensions(mFdp.ConsumeIntegralInRange(kMinIndex, trackSize - 1),
137 payload, &width, &height);
138 break;
139 }
140 case 2: {
141 int32_t cvoExtMap = mFdp.ConsumeIntegral<int32_t>();
142 sessionPacket->getCvoExtMap(mFdp.ConsumeIntegralInRange(kMinIndex, trackSize - 1),
143 &cvoExtMap);
144 break;
145 }
146 case 3: {
147 int64_t durationUs = mFdp.ConsumeIntegral<int64_t>();
148 sessionPacket->getDurationUs(&durationUs);
149 break;
150 }
151 case 4: {
152 int32_t timeScale, numChannels;
153 if (desc != nullptr) {
154 sessionPacket->ParseFormatDesc(desc.c_str(), &timeScale, &numChannels);
155 }
156 break;
157 }
158 case 5: {
159 if (checkFormatSupport(codec, format)) {
160 sp<APacketSource> packetSource = sp<APacketSource>::make(
161 sessionPacket, mFdp.ConsumeIntegralInRange(kMinIndex, trackSize - 1));
162 }
163 break;
164 }
165 }
166 }
167 }
168
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)169 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
170 ASessionPacketFuzzer packetSourceFuzzer(data, size);
171 packetSourceFuzzer.process();
172 return 0;
173 }
174