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 
17 #include <arpa/inet.h>
18 #include <fuzzer/FuzzedDataProvider.h>
19 #include <media/stagefright/foundation/AMessage.h>
20 #include <media/stagefright/rtsp/ARTSPConnection.h>
21 #include <thread>
22 
23 using namespace android;
24 
25 const std::string kAuthType[] = {"Basic", "Digest"};
26 const std::string kTab = "\t";
27 const std::string kCSeq = "CSeq: ";
28 const std::string kSpace = " ";
29 const std::string kNewLine = "\n";
30 const std::string kBinaryHeader = "$";
31 const std::string kNonce = " nonce=\"\"";
32 const std::string kRealm = " realm=\"\"";
33 const std::string kHeaderBoundary = "\r\n\r\n";
34 const std::string kContentLength = "content-length: ";
35 const std::string kDefaultRequestValue = "INVALID_FORMAT";
36 const std::string kUrlPrefix = "rtsp://root:pass@127.0.0.1:";
37 const std::string kRequestMarker = "REQUEST_SENT";
38 const std::string kQuitResponse = "\n\n\n\n";
39 const std::string kRTSPVersion = "RTSP/1.0";
40 const std::string kValidResponse = kRTSPVersion + " 200 \n";
41 const std::string kAuthString = kRTSPVersion + " 401 \nwww-authenticate: ";
42 constexpr char kNullValue = '\0';
43 constexpr char kDefaultValue = '0';
44 constexpr int32_t kWhat = 'resp';
45 constexpr int32_t kMinPort = 100;
46 constexpr int32_t kMaxPort = 999;
47 constexpr int32_t kMinASCIIValue = 32;
48 constexpr int32_t kMaxASCIIValue = 126;
49 constexpr int32_t kMinContentLength = 0;
50 constexpr int32_t kMaxContentLength = 1000;
51 constexpr int32_t kBinaryVectorSize = 3;
52 constexpr int32_t kDefaultCseqValue = 1;
53 constexpr int32_t kBufferSize = 1024;
54 constexpr int32_t kMaxLoopRuns = 5;
55 constexpr int32_t kPort = 554;
56 constexpr int32_t kMaxBytes = 128;
57 constexpr int32_t kMaxThreads = 1024;
58 
59 struct FuzzAHandler : public AHandler {
60   public:
FuzzAHandlerFuzzAHandler61     FuzzAHandler(std::function<void()> signalEosFunction)
62         : mSignalEosFunction(std::move(signalEosFunction)) {}
63     ~FuzzAHandler() = default;
64 
65   protected:
onMessageReceivedFuzzAHandler66     void onMessageReceived(const sp<AMessage>& msg) override {
67         switch (msg->what()) {
68             case kWhat: {
69                 mSignalEosFunction();
70                 break;
71             }
72         }
73     }
74 
75   private:
76     std::function<void()> mSignalEosFunction;
77 };
78 
79 class RTSPConnectionFuzzer {
80   public:
RTSPConnectionFuzzer(const uint8_t * data,size_t size)81     RTSPConnectionFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
~RTSPConnectionFuzzer()82     ~RTSPConnectionFuzzer() {
83         // wait for all the threads to join the main thread
84         for (auto& thread : mThreadPool) {
85             if (thread.joinable()) {
86                 thread.join();
87             }
88         }
89         close(mServerFd);
90     }
91     void process();
92 
93   private:
94     void signalEos();
95     void startServer();
96     void createFuzzData();
97     void acceptConnection();
98     void handleConnection(int32_t);
99     void handleClientResponse(int32_t);
100     void sendValidResponse(int32_t, int32_t);
101     int32_t checkSocket(int32_t);
102     size_t generateBinaryDataSize(std::string);
103     bool checkValidRequestData(const AString&);
104     bool mEosReached = false;
105     bool mServerFailure = false;
106     bool mNotifyResponseListener = false;
107     int32_t mServerFd;
108     std::string mFuzzData = "";
109     std::string mFuzzRequestData = "";
110     std::string mRequestData = kDefaultRequestValue;
111     std::mutex mFuzzDataMutex;
112     std::mutex mMsgPostCompleteMutex;
113     std::condition_variable mConditionalVariable;
114     std::vector<std::thread> mThreadPool;
115     FuzzedDataProvider mFdp;
116 };
117 
generateBinaryDataSize(std::string values)118 size_t RTSPConnectionFuzzer::generateBinaryDataSize(std::string values) {
119     // computed the binary data size as done in ARTSPConnection.cpp
120     uint8_t x = values[0];
121     uint8_t y = values[1];
122     return x << 8 | y;
123 }
124 
checkValidRequestData(const AString & request)125 bool RTSPConnectionFuzzer::checkValidRequestData(const AString& request) {
126     if (request.find(kHeaderBoundary.c_str()) <= 0) {
127         return false;
128     }
129     ssize_t space = request.find(kSpace.c_str());
130     if (space <= 0) {
131         return false;
132     }
133     if (request.find(kSpace.c_str(), space + 1) <= 0) {
134         return false;
135     }
136     return true;
137 }
138 
createFuzzData()139 void RTSPConnectionFuzzer::createFuzzData() {
140     std::unique_lock fuzzLock(mFuzzDataMutex);
141     mFuzzData = "";
142     mFuzzRequestData = "";
143     int32_t contentLength = 0;
144     if (mFdp.ConsumeBool()) {
145         if (mFdp.ConsumeBool()) {
146             // if we want to handle server request
147             mFuzzData.append(kSpace + kSpace + kRTSPVersion);
148         } else {
149             // if we want to notify response listener
150             mFuzzData.append(
151                     kRTSPVersion + kSpace +
152                     std::to_string(mFdp.ConsumeIntegralInRange<uint16_t>(kMinPort, kMaxPort)) +
153                     kSpace);
154         }
155         mFuzzData.append(kNewLine);
156         if (mFdp.ConsumeBool()) {
157             contentLength =
158                     mFdp.ConsumeIntegralInRange<int32_t>(kMinContentLength, kMaxContentLength);
159             mFuzzData.append(kContentLength + std::to_string(contentLength) + kNewLine);
160             if (mFdp.ConsumeBool()) {
161                 mFdp.ConsumeBool() ? mFuzzData.append(kSpace + kNewLine)
162                                    : mFuzzData.append(kTab + kNewLine);
163             }
164         }
165         // new line to break out of infinite for loop
166         mFuzzData.append(kNewLine);
167         if (contentLength) {
168             std::string contentData = mFdp.ConsumeBytesAsString(contentLength);
169             contentData.resize(contentLength, kDefaultValue);
170             mFuzzData.append(contentData);
171         }
172     } else {
173         // for binary data
174         std::string randomValues(kBinaryVectorSize, kNullValue);
175         for (size_t idx = 0; idx < kBinaryVectorSize; ++idx) {
176             randomValues[idx] =
177                     (char)mFdp.ConsumeIntegralInRange<uint8_t>(kMinASCIIValue, kMaxASCIIValue);
178         }
179         size_t binaryDataSize = generateBinaryDataSize(randomValues);
180         std::string data = mFdp.ConsumeBytesAsString(binaryDataSize);
181         data.resize(binaryDataSize, kDefaultValue);
182         mFuzzData.append(kBinaryHeader + randomValues + data);
183     }
184     if (mFdp.ConsumeBool()) {
185         mRequestData = mFdp.ConsumeRandomLengthString(kMaxBytes) + kSpace + kSpace +
186                        kHeaderBoundary + mFdp.ConsumeRandomLengthString(kMaxBytes);
187         // Check if Request data is valid
188         if (checkValidRequestData(mRequestData.c_str())) {
189             if (mFdp.ConsumeBool()) {
190                 if (mFdp.ConsumeBool()) {
191                     // if we want to handle server request
192                     mFuzzRequestData.append(kSpace + kSpace + kRTSPVersion + kNewLine);
193                 } else {
194                     // if we want to add authentication headers
195                     mNotifyResponseListener = true;
196                     mFuzzRequestData.append(kAuthString);
197                     if (mFdp.ConsumeBool()) {
198                         // for Authentication type: Basic
199                         mFuzzRequestData.append(kAuthType[0]);
200                     } else {
201                         // for Authentication type: Digest
202                         mFuzzRequestData.append(kAuthType[1]);
203                         mFuzzRequestData.append(kNonce);
204                         mFuzzRequestData.append(kRealm);
205                     }
206                     mFuzzRequestData.append(kNewLine);
207                 }
208             } else {
209                 mNotifyResponseListener = false;
210                 mFuzzRequestData.append(kValidResponse);
211             }
212         } else {
213             mRequestData = kDefaultRequestValue;
214         }
215     } else {
216         mRequestData = kDefaultRequestValue;
217         mFuzzData.append(kNewLine);
218     }
219 }
220 
signalEos()221 void RTSPConnectionFuzzer::signalEos() {
222     mEosReached = true;
223     mConditionalVariable.notify_all();
224     return;
225 }
226 
checkSocket(int32_t newSocket)227 int32_t RTSPConnectionFuzzer::checkSocket(int32_t newSocket) {
228     struct timeval tv;
229     tv.tv_sec = 1;
230     tv.tv_usec = 0;
231 
232     fd_set rs;
233     FD_ZERO(&rs);
234     FD_SET(newSocket, &rs);
235 
236     return select(newSocket + 1, &rs, nullptr, nullptr, &tv);
237 }
238 
sendValidResponse(int32_t newSocket,int32_t cseq=-1)239 void RTSPConnectionFuzzer::sendValidResponse(int32_t newSocket, int32_t cseq = -1) {
240     std::string validResponse = kValidResponse;
241     if (cseq != -1) {
242         validResponse.append(kCSeq + std::to_string(cseq));
243         validResponse.append(kNewLine + kNewLine);
244     } else {
245         validResponse.append(kNewLine);
246     }
247     send(newSocket, validResponse.c_str(), validResponse.size(), 0);
248 }
249 
handleClientResponse(int32_t newSocket)250 void RTSPConnectionFuzzer::handleClientResponse(int32_t newSocket) {
251     char buffer[kBufferSize] = {0};
252     if (checkSocket(newSocket) == 1) {
253         read(newSocket, buffer, kBufferSize);
254     }
255 }
256 
handleConnection(int32_t newSocket)257 void RTSPConnectionFuzzer::handleConnection(int32_t newSocket) {
258     std::unique_lock fuzzLock(mFuzzDataMutex);
259     send(newSocket, mFuzzData.c_str(), mFuzzData.size(), 0);
260     if (mFuzzData[0] == kSpace[0]) {
261         handleClientResponse(newSocket);
262     }
263 
264     if (mFuzzRequestData != "") {
265         char buffer[kBufferSize] = {0};
266         if (checkSocket(newSocket) == 1 && recv(newSocket, buffer, kBufferSize, MSG_DONTWAIT) > 0) {
267             // Extract the 'CSeq' value present at the end of header
268             std::string clientResponse(buffer);
269             std::string header = clientResponse.substr(0, clientResponse.find(kHeaderBoundary));
270             char cseq = header[header.rfind(kCSeq) + kCSeq.length()];
271             int32_t cseqValue = cseq ? cseq - '0' : kDefaultCseqValue;
272             std::string response = mFuzzRequestData;
273             response.append(kCSeq + std::to_string(cseqValue));
274             response.append(kNewLine + kNewLine);
275             send(newSocket, response.data(), response.length(), 0);
276 
277             if (!mNotifyResponseListener) {
278                 char buffer[kBufferSize] = {0};
279                 if (checkSocket(newSocket) == 1) {
280                     if (recv(newSocket, buffer, kBufferSize, MSG_DONTWAIT) > 0) {
281                         // Extract the 'CSeq' value present at the end of header
282                         std::string clientResponse(buffer);
283                         std::string header =
284                                 clientResponse.substr(0, clientResponse.find(kHeaderBoundary));
285                         char cseq = header[header.rfind(kCSeq) + kCSeq.length()];
286                         int32_t cseqValue = cseq ? cseq - '0' : kDefaultCseqValue;
287                         sendValidResponse(newSocket, cseqValue);
288                     } else {
289                         sendValidResponse(newSocket);
290                     }
291                 }
292             }
293         } else {
294             // If no data to read, then send a valid response
295             // to release the mutex lock in fuzzer
296             sendValidResponse(newSocket);
297         }
298     }
299     send(newSocket, kQuitResponse.c_str(), kQuitResponse.size(), 0);
300 }
301 
startServer()302 void RTSPConnectionFuzzer::startServer() {
303     signal(SIGPIPE, SIG_IGN);
304     mServerFd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
305     struct sockaddr_in serverAddress;
306     serverAddress.sin_family = AF_INET;
307     serverAddress.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
308     serverAddress.sin_port = htons(kPort);
309 
310     // Get rid of "Address in use" error
311     int32_t opt = 1;
312     if (setsockopt(mServerFd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
313         mServerFailure = true;
314     }
315 
316     // Bind the socket and set for listening.
317     if (bind(mServerFd, (struct sockaddr*)(&serverAddress), sizeof(serverAddress)) < 0) {
318         mServerFailure = true;
319     }
320 
321     if (listen(mServerFd, 5) < 0) {
322         mServerFailure = true;
323     }
324 }
325 
acceptConnection()326 void RTSPConnectionFuzzer::acceptConnection() {
327     int32_t clientFd = accept4(mServerFd, nullptr, nullptr, SOCK_CLOEXEC);
328     handleConnection(clientFd);
329     close(clientFd);
330 }
331 
process()332 void RTSPConnectionFuzzer::process() {
333     startServer();
334     if (mServerFailure) {
335         return;
336     }
337     sp<ALooper> looper = sp<ALooper>::make();
338     sp<FuzzAHandler> handler =
339             sp<FuzzAHandler>::make(std::bind(&RTSPConnectionFuzzer::signalEos, this));
340     sp<ARTSPConnection> rtspConnection =
341             sp<ARTSPConnection>::make(mFdp.ConsumeBool(), mFdp.ConsumeIntegral<uint64_t>());
342     looper->start();
343     looper->registerHandler(rtspConnection);
344     looper->registerHandler(handler);
345     sp<AMessage> replymsg = sp<AMessage>::make(kWhat, handler);
346     std::string url = kUrlPrefix + std::to_string(kPort) + "/";
347 
348     while (mFdp.remaining_bytes() && mThreadPool.size() < kMaxThreads) {
349         createFuzzData();
350         mThreadPool.push_back(std::thread(&RTSPConnectionFuzzer::acceptConnection, this));
351         if (mFdp.ConsumeBool()) {
352             rtspConnection->observeBinaryData(replymsg);
353         }
354 
355         {
356             rtspConnection->connect(url.c_str(), replymsg);
357             std::unique_lock waitForMsgPostComplete(mMsgPostCompleteMutex);
358             mConditionalVariable.wait(waitForMsgPostComplete, [this] {
359                 if (mEosReached == true) {
360                     mEosReached = false;
361                     return true;
362                 }
363                 return mEosReached;
364             });
365         }
366 
367         if (mRequestData != kDefaultRequestValue) {
368             rtspConnection->sendRequest(mRequestData.c_str(), replymsg);
369             std::unique_lock waitForMsgPostComplete(mMsgPostCompleteMutex);
370             mConditionalVariable.wait(waitForMsgPostComplete, [this] {
371                 if (mEosReached == true) {
372                     mEosReached = false;
373                     return true;
374                 }
375                 return mEosReached;
376             });
377         }
378 
379         if (mFdp.ConsumeBool()) {
380             rtspConnection->disconnect(replymsg);
381             std::unique_lock waitForMsgPostComplete(mMsgPostCompleteMutex);
382             mConditionalVariable.wait(waitForMsgPostComplete, [this] {
383                 if (mEosReached == true) {
384                     mEosReached = false;
385                     return true;
386                 }
387                 return mEosReached;
388             });
389         }
390     }
391 }
392 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)393 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
394     RTSPConnectionFuzzer rtspFuzz(data, size);
395     rtspFuzz.process();
396     return 0;
397 }
398