1/*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "faultloggerdserver_fuzzer.h"
17
18#include <cstddef>
19#include <cstdint>
20#include <unistd.h>
21#include <sys/socket.h>
22
23#include "dfx_exception.h"
24#include "dfx_util.h"
25#include "faultloggerd_client.h"
26#include "faultloggerd_fuzzertest_common.h"
27#include "fault_logger_config.h"
28#define private public
29#include "fault_logger_daemon.h"
30#undef private
31
32namespace OHOS {
33namespace HiviewDFX {
34constexpr int32_t FAULTLOGGERD_FUZZ_READ_BUFF = 1024;
35
36void *ReadThread1(void *param)
37{
38    int fd = static_cast<int>(reinterpret_cast<long>(param));
39    char buff[FAULTLOGGERD_FUZZ_READ_BUFF];
40    OHOS_TEMP_FAILURE_RETRY(read(fd, buff, sizeof(buff)));
41    char msg[] = "any test str";
42    OHOS_TEMP_FAILURE_RETRY(write(fd, reinterpret_cast<char*>(msg), sizeof(msg)));
43    return nullptr;
44}
45
46void *ReadThread2(void *param)
47{
48    int fd = static_cast<int>(reinterpret_cast<long>(param));
49    char buff[FAULTLOGGERD_FUZZ_READ_BUFF];
50    OHOS_TEMP_FAILURE_RETRY(read(fd, buff, sizeof(buff)));
51    CrashDumpException test;
52    test.error = CRASH_DUMP_LOCAL_REPORT;
53    OHOS_TEMP_FAILURE_RETRY(write(fd, reinterpret_cast<char*>(&test), sizeof(CrashDumpException)));
54    return nullptr;
55}
56
57void *ReadThread3(void *param)
58{
59    int fd = static_cast<int>(reinterpret_cast<long>(param));
60    char buff[FAULTLOGGERD_FUZZ_READ_BUFF];
61    OHOS_TEMP_FAILURE_RETRY(read(fd, buff, sizeof(buff)));
62    CrashDumpException test{};
63    OHOS_TEMP_FAILURE_RETRY(write(fd, reinterpret_cast<char*>(&test), sizeof(CrashDumpException)));
64    return nullptr;
65}
66
67void HandleRequestTestCommon(std::shared_ptr<FaultLoggerDaemon> daemon, char* buff, size_t len,
68    void *(*startRoutine)(void *))
69{
70    int socketFd[2]; // 2 : the length of the array
71    if (socketpair(AF_UNIX, SOCK_STREAM, 0, socketFd) == 0) {
72        OHOS_TEMP_FAILURE_RETRY(write(socketFd[1], buff, len));
73        daemon->connectionMap_[socketFd[0]] = socketFd[0];
74
75        if (!startRoutine) {
76            daemon->HandleRequest(0, socketFd[0]);
77        } else {
78            pthread_t threadId;
79            if (pthread_create(&threadId, nullptr, startRoutine, reinterpret_cast<void*>(socketFd[1])) != 0) {
80                perror("Failed to create thread");
81                close(socketFd[0]);
82                close(socketFd[1]);
83                return;
84            }
85
86            daemon->HandleRequest(0, socketFd[0]);
87
88            pthread_join(threadId, nullptr);
89        }
90        close(socketFd[1]);
91    }
92}
93
94std::vector<FaultLoggerdStatsRequest> InitStatsRequests(const uint8_t* data, size_t size)
95{
96    std::vector<FaultLoggerdStatsRequest> statsRequest;
97    {
98        FaultLoggerdStatsRequest requst{};
99        requst.type = PROCESS_DUMP;
100        requst.signalTime = GetTimeMilliSeconds();
101        requst.pid = 1;
102        requst.processdumpStartTime = time(nullptr);
103        requst.processdumpFinishTime = time(nullptr) + 10; // 10 : Get the last 10 seconds of the current time
104        statsRequest.emplace_back(requst);
105    }
106    {
107        FaultLoggerdStatsRequest requst{};
108        auto lastRequst = statsRequest.back();
109        requst.type = DUMP_CATCHER;
110        requst.pid = lastRequst.pid;
111        requst.requestTime = time(nullptr);
112        requst.dumpCatcherFinishTime = time(nullptr) + 10; // 10 : Get the last 10 seconds of the current time
113        requst.result = 1;
114        statsRequest.emplace_back(requst);
115    }
116    {
117        FaultLoggerdStatsRequest requst{};
118        requst.type = DUMP_CATCHER;
119        requst.pid = 1;
120        requst.requestTime = time(nullptr);
121        requst.dumpCatcherFinishTime = time(nullptr) + 10; // 10 : Get the last 10 seconds of the current time
122        requst.result = 1;
123        statsRequest.emplace_back(requst);
124    }
125    return statsRequest;
126}
127
128void HandleRequestByClientTypeForDefaultClientTest(std::shared_ptr<FaultLoggerDaemon> daemon)
129{
130    FaultLoggerdRequest requst;
131    requst.clientType = FaultLoggerClientType::DEFAULT_CLIENT;
132    HandleRequestTestCommon(daemon, reinterpret_cast<char*>(&requst), sizeof(FaultLoggerdRequest), nullptr);
133    requst.type = FaultLoggerType::CPP_CRASH;
134    HandleRequestTestCommon(daemon, reinterpret_cast<char*>(&requst), sizeof(FaultLoggerdRequest), nullptr);
135    requst.type = FaultLoggerType::JS_HEAP_SNAPSHOT;
136    HandleRequestTestCommon(daemon, reinterpret_cast<char*>(&requst), sizeof(FaultLoggerdRequest), nullptr);
137    daemon->crashTimeMap_[1] = time(nullptr) - 10; // 10 : Get the first 10 seconds of the current time
138    HandleRequestTestCommon(daemon, reinterpret_cast<char*>(&requst), sizeof(FaultLoggerdRequest), nullptr);
139    daemon->crashTimeMap_[1] = time(nullptr);
140    HandleRequestTestCommon(daemon, reinterpret_cast<char*>(&requst), sizeof(FaultLoggerdRequest), nullptr);
141}
142
143void HandleRequestByClientTypeTest(std::shared_ptr<FaultLoggerDaemon> daemon)
144{
145    HandleRequestByClientTypeForDefaultClientTest(daemon);
146    {
147        FaultLoggerdRequest requst;
148        requst.clientType = FaultLoggerClientType::LOG_FILE_DES_CLIENT;
149        HandleRequestTestCommon(daemon, reinterpret_cast<char*>(&requst), sizeof(FaultLoggerdRequest), nullptr);
150    }
151    {
152        FaultLoggerdRequest requst;
153        requst.clientType = FaultLoggerClientType::PRINT_T_HILOG_CLIENT;
154        HandleRequestTestCommon(daemon, reinterpret_cast<char*>(&requst), sizeof(FaultLoggerdRequest), ReadThread2);
155    }
156    {
157        FaultLoggerdRequest requst;
158        requst.clientType = FaultLoggerClientType::PERMISSION_CLIENT;
159        HandleRequestTestCommon(daemon, reinterpret_cast<char*>(&requst), sizeof(FaultLoggerdRequest), ReadThread2);
160    }
161    {
162        FaultLoggerdRequest requst;
163        requst.clientType = FaultLoggerClientType::SDK_DUMP_CLIENT;
164        requst.pid = 1;
165        HandleRequestTestCommon(daemon, reinterpret_cast<char*>(&requst), sizeof(FaultLoggerdRequest), ReadThread2);
166    }
167    {
168        FaultLoggerdRequest requst;
169        requst.clientType = FaultLoggerClientType::PIPE_FD_CLIENT;
170        HandleRequestTestCommon(daemon, reinterpret_cast<char*>(&requst), sizeof(FaultLoggerdRequest), nullptr);
171    }
172    {
173        FaultLoggerdRequest requst;
174        requst.clientType = FaultLoggerClientType::REPORT_EXCEPTION_CLIENT;
175        HandleRequestTestCommon(daemon, reinterpret_cast<char*>(&requst), sizeof(FaultLoggerdRequest), ReadThread1);
176        HandleRequestTestCommon(daemon, reinterpret_cast<char*>(&requst), sizeof(FaultLoggerdRequest), ReadThread2);
177        HandleRequestTestCommon(daemon, reinterpret_cast<char*>(&requst), sizeof(FaultLoggerdRequest), ReadThread3);
178    }
179    {
180        FaultLoggerdRequest requst;
181        requst.clientType = -1;
182        HandleRequestTestCommon(daemon, reinterpret_cast<char*>(&requst), sizeof(FaultLoggerdRequest), nullptr);
183    }
184}
185
186void HandStaticTest(std::shared_ptr<FaultLoggerDaemon> daemon)
187{
188    daemon->HandleStaticForFuzzer(FaultLoggerType::CPP_STACKTRACE, 0);
189    daemon->HandleStaticForFuzzer(FaultLoggerType::JS_STACKTRACE, 0);
190    daemon->HandleStaticForFuzzer(FaultLoggerType::LEAK_STACKTRACE, 1);
191    daemon->HandleStaticForFuzzer(FaultLoggerType::FFRT_CRASH_LOG, 1);
192    daemon->HandleStaticForFuzzer(FaultLoggerType::JIT_CODE_LOG, 1);
193}
194
195bool CheckReadResp(int sockfd)
196{
197    char controlBuffer[SOCKET_BUFFER_SIZE] = {0};
198    ssize_t nread = OHOS_TEMP_FAILURE_RETRY(read(sockfd, controlBuffer, sizeof(controlBuffer) - 1));
199    if (nread != static_cast<ssize_t>(strlen(FAULTLOGGER_DAEMON_RESP))) {
200        return false;
201    }
202    return true;
203}
204
205void HandleRequestByPipeTypeCommon(std::shared_ptr<FaultLoggerDaemon> daemon, int32_t pipeType,
206    bool isPassCheck = false, bool isJson = false)
207{
208    int fd = -1;
209    FaultLoggerdRequest request;
210    request.pipeType = pipeType;
211    std::unique_ptr<FaultLoggerPipe2> ptr = std::make_unique<FaultLoggerPipe2>(GetTimeMilliSeconds(), isJson);
212
213    if (!isPassCheck) {
214        daemon->HandleRequestByPipeType(fd, 1, &request, ptr.get());
215        close(fd);
216        return;
217    }
218
219    int socketFd[2]; // 2 : the length of the array
220    if (socketpair(AF_UNIX, SOCK_STREAM, 0, socketFd) == 0) {
221        pid_t pid = fork();
222        if (pid == 0) {
223            sleep(1);
224            if (CheckReadResp(socketFd[1])) {
225                std::string test = "test";
226                OHOS_TEMP_FAILURE_RETRY(write(socketFd[1], test.c_str(), sizeof(test)));
227            }
228        } else if (pid > 0) {
229            daemon->connectionMap_[socketFd[0]] = socketFd[0];
230            daemon->HandleRequestByPipeType(fd, socketFd[0], &request, ptr.get());
231            close(fd);
232            close(socketFd[1]);
233        }
234    }
235}
236
237void HandleRequestByPipeTypeTest(std::shared_ptr<FaultLoggerDaemon> daemon)
238{
239    HandleRequestByPipeTypeCommon(daemon, FaultLoggerPipeType::PIPE_FD_READ_BUF, true, false);
240    HandleRequestByPipeTypeCommon(daemon, FaultLoggerPipeType::PIPE_FD_READ_RES, true, false);
241    HandleRequestByPipeTypeCommon(daemon, FaultLoggerPipeType::PIPE_FD_DELETE, true, false);
242    HandleRequestByPipeTypeCommon(daemon, FaultLoggerPipeType::PIPE_FD_JSON_READ_BUF, true, true);
243    HandleRequestByPipeTypeCommon(daemon, FaultLoggerPipeType::PIPE_FD_JSON_READ_RES, true, true);
244
245    HandleRequestByPipeTypeCommon(daemon, FaultLoggerPipeType::PIPE_FD_READ_BUF);
246    HandleRequestByPipeTypeCommon(daemon, FaultLoggerPipeType::PIPE_FD_WRITE_BUF);
247    HandleRequestByPipeTypeCommon(daemon, FaultLoggerPipeType::PIPE_FD_READ_RES);
248    HandleRequestByPipeTypeCommon(daemon, FaultLoggerPipeType::PIPE_FD_WRITE_RES);
249    HandleRequestByPipeTypeCommon(daemon, FaultLoggerPipeType::PIPE_FD_JSON_READ_BUF, false, true);
250    HandleRequestByPipeTypeCommon(daemon, FaultLoggerPipeType::PIPE_FD_JSON_WRITE_BUF, false, true);
251    HandleRequestByPipeTypeCommon(daemon, FaultLoggerPipeType::PIPE_FD_JSON_READ_RES, false, true);
252    HandleRequestByPipeTypeCommon(daemon, FaultLoggerPipeType::PIPE_FD_JSON_WRITE_RES, false, true);
253    HandleRequestByPipeTypeCommon(daemon, -1);
254}
255
256void FaultloggerdServerTestCallOnce(const uint8_t* data, size_t size)
257{
258    static bool callCnt = false;
259    if (callCnt) {
260        return;
261    }
262    callCnt = true;
263
264    std::shared_ptr<FaultLoggerDaemon> daemon = std::make_shared<FaultLoggerDaemon>();
265    // HandleRequest
266    daemon->HandleRequest(-1, 0);
267
268    // HandleRequestTest
269    std::vector<FaultLoggerdStatsRequest> statsRequest = InitStatsRequests(data, size);
270    for (auto requst : statsRequest) {
271        HandleRequestTestCommon(daemon, reinterpret_cast<char*>(&requst), sizeof(FaultLoggerdStatsRequest), nullptr);
272    }
273
274    // CheckReadRequest
275    {
276        int socketFd[2]; // 2 : the length of the array
277        if (socketpair(AF_UNIX, SOCK_STREAM, 0, socketFd) == 0) {
278            close(socketFd[1]);
279            daemon->HandleRequest(0, socketFd[0]);
280        }
281    }
282    char buff[] = "any test str";
283    HandleRequestTestCommon(daemon, reinterpret_cast<char*>(buff), sizeof(buff), nullptr);
284
285    // CheckRequestCredential
286    {
287        FaultLoggerdRequest requst;
288        int socketFd[2]; // 2 : the length of the array
289        if (socketpair(AF_UNIX, SOCK_STREAM, 0, socketFd) == 0) {
290            OHOS_TEMP_FAILURE_RETRY(write(socketFd[1], reinterpret_cast<char*>(&requst), sizeof(FaultLoggerdRequest)));
291            daemon->HandleRequest(0, socketFd[0]);
292            close(socketFd[1]);
293        }
294    }
295
296    // init
297    if (!daemon->InitEnvironment()) {
298        daemon->CleanupSockets();
299        return;
300    }
301
302    HandleRequestByClientTypeTest(daemon);
303    HandleRequestByPipeTypeTest(daemon);
304    HandStaticTest(daemon);
305}
306
307void FaultloggerdServerTest(const uint8_t* data, size_t size)
308{
309    std::shared_ptr<FaultLoggerDaemon> daemon = std::make_shared<FaultLoggerDaemon>();
310
311    int32_t epollFd;
312    int32_t connectionFd;
313    int32_t type;
314    int32_t pid;
315    int32_t tid;
316    int32_t uid;
317
318    int offsetTotalLength = sizeof(epollFd) + sizeof(connectionFd) + sizeof(type) + sizeof(pid) +
319                            sizeof(tid) + sizeof(uid);
320    if (offsetTotalLength > size) {
321        return;
322    }
323
324    STREAM_TO_VALUEINFO(data, epollFd);
325    STREAM_TO_VALUEINFO(data, connectionFd);
326    STREAM_TO_VALUEINFO(data, type);
327    STREAM_TO_VALUEINFO(data, pid);
328    STREAM_TO_VALUEINFO(data, tid);
329    STREAM_TO_VALUEINFO(data, uid);
330
331    if (epollFd < 0 || connectionFd < 3) { // 3: not allow fd = 0,1,2 because they are reserved by system
332        return;
333    }
334
335    struct FaultLoggerdRequest request;
336    (void)memset_s(&request, sizeof(request), 0, sizeof(request));
337    request.type = type;
338    request.pid = pid;
339    request.tid = tid;
340    request.uid = uid;
341    request.time = OHOS::HiviewDFX::GetTimeMilliSeconds();
342
343    daemon->HandleRequestForFuzzer(epollFd, connectionFd, &request, &request);
344    sleep(1);
345}
346} // namespace HiviewDFX
347} // namespace OHOS
348
349/* Fuzzer entry point */
350extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
351{
352    if (data == nullptr || size == 0) {
353        return 0;
354    }
355
356    /* Run your code on data */
357    OHOS::HiviewDFX::FaultloggerdServerTestCallOnce(data, size);
358    OHOS::HiviewDFX::FaultloggerdServerTest(data, size);
359    return 0;
360}
361