• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "fault_logger_service.h"
17 
18 #include <algorithm>
19 #include <fstream>
20 #include <sys/wait.h>
21 #include <sys/socket.h>
22 #include <sys/syscall.h>
23 
24 #include "dfx_define.h"
25 #include "dfx_log.h"
26 #include "dfx_trace.h"
27 #include "dfx_util.h"
28 #include "fault_logger_daemon.h"
29 #include "faultloggerd_socket.h"
30 
31 #ifndef is_ohos_lite
32 #include "fault_logger_pipe.h"
33 #endif
34 
35 #ifndef HISYSEVENT_DISABLE
36 #include "hisysevent.h"
37 #endif
38 
39 #include "string_printf.h"
40 #include "temp_file_manager.h"
41 #include "smart_fd.h"
42 
43 namespace OHOS {
44 namespace HiviewDFX {
45 
46 namespace {
47 
48 constexpr const char* const FAULTLOGGERD_SERVICE_TAG = "FAULT_LOGGER_SERVICE";
GetUcredByPeerCred(struct ucred & rcred,int32_t connectionFd)49 bool GetUcredByPeerCred(struct ucred& rcred, int32_t connectionFd)
50 {
51     socklen_t credSize = sizeof(rcred);
52     if (getsockopt(connectionFd, SOL_SOCKET, SO_PEERCRED, &rcred, &credSize) != 0) {
53         DFXLOGE("%{public}s :: Failed to GetCredential, errno: %{public}d", FAULTLOGGERD_SERVICE_TAG, errno);
54         return false;
55     }
56     return true;
57 }
58 
CheckCallerUID(uint32_t callerUid)59 bool CheckCallerUID(uint32_t callerUid)
60 {
61     const uint32_t whitelist[] = {
62         0, // rootUid
63         1000, // bmsUid
64         1201, // hiviewUid
65         1212, // hidumperServiceUid
66         5523 // foundationUid
67     };
68     if (std::find(std::begin(whitelist), std::end(whitelist), callerUid) == std::end(whitelist)) {
69         DFXLOGW("%{public}s :: CheckCallerUID :: Caller Uid(%{public}d) is unexpectly.",
70                 FAULTLOGGERD_SERVICE_TAG, callerUid);
71         return false;
72     }
73     return true;
74 }
75 
CheckRequestCredential(int32_t connectionFd,int32_t requestPid)76 bool CheckRequestCredential(int32_t connectionFd, int32_t requestPid)
77 {
78     struct ucred creds{};
79     if (!GetUcredByPeerCred(creds, connectionFd)) {
80         return false;
81     }
82     if (CheckCallerUID(creds.uid)) {
83         return true;
84     }
85     if (creds.pid != requestPid) {
86         DFXLOGW("Failed to check request credential request:%{public}d: cred:%{public}d fd:%{public}d",
87                 requestPid, creds.pid, connectionFd);
88         return false;
89     }
90     return true;
91 }
92 }
93 
94 #ifndef HISYSEVENT_DISABLE
Filter(int32_t connectionFd,const CrashDumpException & requestData)95 bool ExceptionReportService::Filter(int32_t connectionFd, const CrashDumpException& requestData)
96 {
97     if (strlen(requestData.message) == 0) {
98         return false;
99     }
100     struct ucred creds{};
101     if (!GetUcredByPeerCred(creds, connectionFd) || creds.uid != static_cast<uint32_t>(requestData.uid)) {
102         DFXLOGW("Failed to check request credential request uid:%{public}d: cred uid:%{public}d fd:%{public}d",
103                 requestData.uid, creds.uid, connectionFd);
104         return false;
105     }
106     return true;
107 }
108 
OnRequest(const std::string & socketName,int32_t connectionFd,const CrashDumpException & requestData)109 int32_t ExceptionReportService::OnRequest(const std::string& socketName, int32_t connectionFd,
110     const CrashDumpException& requestData)
111 {
112     if (!Filter(connectionFd, requestData)) {
113         return ResponseCode::REQUEST_REJECT;
114     }
115     HiSysEventWrite(
116         HiSysEvent::Domain::RELIABILITY,
117         "CPP_CRASH_EXCEPTION",
118         HiSysEvent::EventType::FAULT,
119         "PID", requestData.pid,
120         "UID", requestData.uid,
121         "HAPPEN_TIME", requestData.time,
122         "ERROR_CODE", requestData.error,
123         "ERROR_MSG", requestData.message);
124     return ResponseCode::REQUEST_SUCCESS;
125 }
126 
RemoveTimeoutDumpStats()127 void StatsService::RemoveTimeoutDumpStats()
128 {
129     constexpr uint64_t timeout = 10000; // 10s
130     uint64_t now = GetTimeMilliSeconds();
131     stats_.remove_if([&now, &timeout](const auto& stats) {
132         return (now > stats.signalTime && now - stats.signalTime > timeout) ||
133             now <= stats.signalTime;
134     });
135 }
136 
ReportDumpStats(const DumpStats & stat)137 void StatsService::ReportDumpStats(const DumpStats& stat)
138 {
139     HiSysEventWrite(
140         HiSysEvent::Domain::HIVIEWDFX,
141         "DUMP_CATCHER_STATS",
142         HiSysEvent::EventType::STATISTIC,
143         "CALLER_PROCESS_NAME", stat.callerProcessName,
144         "CALLER_FUNC_NAME", stat.callerElfName,
145         "TARGET_PROCESS_NAME", stat.targetProcessName,
146         "RESULT", stat.result,
147         "SUMMARY", stat.summary, // we need to parse summary when interface return false
148         "PID", stat.pid,
149         "REQUEST_TIME", stat.requestTime,
150         "OVERALL_TIME", stat.dumpCatcherFinishTime - stat.requestTime,
151         "SIGNAL_TIME", stat.signalTime - stat.requestTime,
152         "DUMPER_START_TIME", stat.processdumpStartTime - stat.signalTime,
153         "UNWIND_TIME", stat.processdumpFinishTime - stat.processdumpStartTime);
154 }
155 
GetElfName(const FaultLoggerdStatsRequest & request)156 std::string StatsService::GetElfName(const FaultLoggerdStatsRequest& request)
157 {
158     if (strlen(request.callerElf) > NAME_BUF_LEN) {
159         return "";
160     }
161     return StringPrintf("%s(%p)", request.callerElf, reinterpret_cast<void*>(request.offset));
162 }
163 
OnRequest(const std::string & socketName,int32_t connectionFd,const FaultLoggerdStatsRequest & requestData)164 int32_t StatsService::OnRequest(const std::string& socketName, int32_t connectionFd,
165     const FaultLoggerdStatsRequest& requestData)
166 {
167     constexpr int32_t delayTime = 7; // allow 10s for processdump report, 3s for dumpcatch timeout and 7s for delay
168     DFXLOGI("%{public}s :: %{public}s: HandleDumpStats", FAULTLOGGERD_SERVICE_TAG, __func__);
169     auto iter = std::find_if(stats_.begin(), stats_.end(), [&requestData](const DumpStats& dumpStats) {
170         return dumpStats.pid == requestData.pid;
171     });
172     if (requestData.type == PROCESS_DUMP && iter == stats_.end()) {
173         auto& stats = stats_.emplace_back();
174         stats.pid = requestData.pid;
175         stats.signalTime = requestData.signalTime;
176         stats.processdumpStartTime = requestData.processdumpStartTime;
177         stats.processdumpFinishTime = requestData.processdumpFinishTime;
178         stats.targetProcessName = requestData.targetProcess;
179     } else {
180         auto task = [requestData, this] {
181             auto iter = std::find_if(stats_.begin(), stats_.end(), [&requestData](const DumpStats& dumpStats) {
182                 return dumpStats.pid == requestData.pid;
183             });
184             if (requestData.type == DUMP_CATCHER && iter != stats_.end()) {
185                 iter->requestTime = requestData.requestTime;
186                 iter->dumpCatcherFinishTime = requestData.dumpCatcherFinishTime;
187                 iter->callerElfName = GetElfName(requestData);
188                 iter->callerProcessName = requestData.callerProcess;
189                 iter->result = requestData.result;
190                 iter->summary = requestData.summary;
191                 ReportDumpStats(*iter);
192                 stats_.erase(iter);
193             } else if (requestData.type == DUMP_CATCHER) {
194                 DumpStats stats;
195                 stats.pid = requestData.pid;
196                 stats.requestTime = requestData.requestTime;
197                 stats.dumpCatcherFinishTime = requestData.dumpCatcherFinishTime;
198                 stats.callerElfName = GetElfName(requestData);
199                 stats.result = requestData.result;
200                 stats.callerProcessName = requestData.callerProcess;
201                 stats.summary = requestData.summary;
202                 stats.targetProcessName = requestData.targetProcess;
203                 ReportDumpStats(stats);
204             }
205             RemoveTimeoutDumpStats();
206         };
207         StartDelayTask(task, delayTime);
208     }
209     RemoveTimeoutDumpStats();
210 #ifdef FAULTLOGGERD_TEST
211     int32_t responseData = ResponseCode::REQUEST_SUCCESS;
212     SendMsgToSocket(connectionFd, &responseData, sizeof(responseData));
213 #endif
214     return ResponseCode::REQUEST_SUCCESS;
215 }
216 
StartDelayTask(std::function<void ()> workFunc,int32_t delayTime)217 void StatsService::StartDelayTask(std::function<void()> workFunc, int32_t delayTime)
218 {
219     EpollManager* epollManager = FaultLoggerDaemon::GetInstance().GetEpollManager(EpollManagerType::MAIN_SERVER);
220     if (epollManager == nullptr) {
221         return;
222     }
223     auto delayTask = DelayTask::CreateInstance(workFunc, delayTime, *epollManager);
224     epollManager->AddListener(std::move(delayTask));
225 }
226 #endif
227 
OnRequest(const std::string & socketName,int32_t connectionFd,const FaultLoggerdRequest & requestData)228 int32_t FileDesService::OnRequest(const std::string& socketName, int32_t connectionFd,
229     const FaultLoggerdRequest& requestData)
230 {
231     DFX_TRACE_SCOPED("FileDesServiceOnRequest");
232     if (!Filter(socketName, connectionFd, requestData)) {
233         return ResponseCode::REQUEST_REJECT;
234     }
235 
236     int32_t fd = TempFileManager::CreateFileDescriptor(requestData.type,
237         requestData.pid, requestData.tid, requestData.time);
238     if (fd < 0) {
239         return ResponseCode::ABNORMAL_SERVICE;
240     }
241 #ifndef is_ohos_lite
242     TempFileManager::RecordFileCreation(requestData.type, requestData.pid);
243 #endif
244     int32_t responseData = ResponseCode::REQUEST_SUCCESS;
245     SendMsgToSocket(connectionFd, &responseData, sizeof(responseData));
246     SendFileDescriptorToSocket(connectionFd, &fd, 1);
247     close(fd);
248     return responseData;
249 }
250 
Filter(const std::string & socketName,int32_t connectionFd,const FaultLoggerdRequest & requestData)251 bool FileDesService::Filter(const std::string& socketName, int32_t connectionFd,
252     const FaultLoggerdRequest& requestData)
253 {
254     switch (requestData.type) {
255         case FaultLoggerType::CPP_CRASH:
256         case FaultLoggerType::CPP_STACKTRACE:
257         case FaultLoggerType::LEAK_STACKTRACE:
258         case FaultLoggerType::JIT_CODE_LOG:
259             return socketName == SERVER_CRASH_SOCKET_NAME;
260         default:
261             return CheckRequestCredential(connectionFd, requestData.pid);
262     }
263 }
264 
265 #ifndef is_ohos_lite
Filter(const std::string & socketName,const SdkDumpRequestData & requestData,uint32_t uid)266 int32_t SdkDumpService::Filter(const std::string& socketName, const SdkDumpRequestData& requestData, uint32_t uid)
267 {
268     if (requestData.pid <= 0 || socketName != SERVER_SDKDUMP_SOCKET_NAME || !CheckCallerUID(uid)) {
269         DFXLOGE("%{public}s :: HandleSdkDumpRequest :: pid(%{public}d) or socketName(%{public}s) fail.",
270             FAULTLOGGERD_SERVICE_TAG, requestData.pid, socketName.c_str());
271         return ResponseCode::REQUEST_REJECT;
272     }
273     if (TempFileManager::CheckCrashFileRecord(requestData.pid)) {
274         DFXLOGW("%{public}s :: pid(%{public}d) has been crashed, break.",
275                 FAULTLOGGERD_SERVICE_TAG, requestData.pid);
276         return ResponseCode::SDK_PROCESS_CRASHED;
277     }
278     if (FaultLoggerPipePair::CheckSdkDumpRecord(requestData.pid, requestData.time)) {
279         DFXLOGE("%{public}s :: pid(%{public}d) is dumping, break.", FAULTLOGGERD_SERVICE_TAG, requestData.pid);
280         return ResponseCode::SDK_DUMP_REPEAT;
281     }
282     return ResponseCode::REQUEST_SUCCESS;
283 }
284 
OnRequest(const std::string & socketName,int32_t connectionFd,const SdkDumpRequestData & requestData)285 int32_t SdkDumpService::OnRequest(const std::string& socketName, int32_t connectionFd,
286     const SdkDumpRequestData& requestData)
287 {
288     DFX_TRACE_SCOPED("SdkDumpServiceOnRequest");
289     DFXLOGI("Receive dump request for pid:%{public}d tid:%{public}d.", requestData.pid, requestData.tid);
290     struct ucred creds;
291     if (!GetUcredByPeerCred(creds, connectionFd)) {
292         DFXLOGE("Sdk dump pid(%{public}d) request failed to get cred.", requestData.pid);
293         return ResponseCode::REQUEST_REJECT;
294     }
295     int32_t responseCode = Filter(socketName, requestData, creds.uid);
296     if (responseCode != ResponseCode::REQUEST_SUCCESS) {
297         return responseCode;
298     }
299 
300     /*
301     *           all     threads my user, local pid             my user, remote pid     other user's process
302     * 3rd       Y       Y(in signal_handler local)     Y(in signal_handler loacl)      N
303     * system    Y       Y(in signal_handler local)     Y(in signal_handler loacl)      Y(in signal_handler remote)
304     * root      Y       Y(in signal_handler local)     Y(in signal_handler loacl)      Y(in signal_handler remote)
305     */
306 
307     /*
308     * 1. pid != 0 && tid != 0:    means we want dump a thread, so we send signal to a thread.
309         Main thread stack is tid's stack, we need ignore other thread info.
310     * 2. pid != 0 && tid == 0:    means we want dump a process, so we send signal to process.
311         Main thead stack is pid's stack, we need other tread info.
312     */
313 
314     /*
315      * in signal_handler we need to check caller pid and tid(which is send to signal handler by SYS_rt_sig.).
316      * 1. caller pid == signal pid, means we do back trace in ourself process, means local backtrace.
317      *      |- we do all tid back trace in signal handler's local unwind.
318      * 2. pid != signal pid, means we do remote back trace.
319      */
320 
321     /*
322      * in local back trace, all unwind stack will save to signal_handler global var.(mutex lock in signal handler.)
323      * in remote back trace, all unwind stack will save to file, and read in dump_catcher, then return.
324      */
325 
326 #pragma clang diagnostic push
327 #pragma clang diagnostic ignored "-Winitializer-overrides"
328     // defined in out/hi3516dv300/obj/third_party/musl/intermidiates/linux/musl_src_ported/include/signal.h
329     siginfo_t si{0};
330     si.si_signo = SIGDUMP;
331     si.si_errno = 0;
332     si.si_value.sival_int = requestData.tid;
333     if (requestData.tid == 0 && sizeof(void*) == 8) { // 8 : platform 64
334         si.si_value.sival_ptr = reinterpret_cast<void*>(requestData.endTime | (1ULL << 63)); // 63 : platform 64
335     }
336     si.si_code = requestData.sigCode;
337     si.si_pid = static_cast<int32_t>(creds.pid);
338     si.si_uid = static_cast<uid_t>(requestData.callerTid);
339 #pragma clang diagnostic pop
340     /*
341      * means we need dump all the threads in a process
342      * --------
343      * Accroding to the linux manual, A process-directed signal may be delivered to any one of the
344      * threads that does not currently have the signal blocked.
345      */
346     auto& faultLoggerPipe = FaultLoggerPipePair::CreateSdkDumpPipePair(requestData.pid, requestData.time);
347 #ifndef FAULTLOGGERD_TEST
348     if (syscall(SYS_rt_sigqueueinfo, requestData.pid, si.si_signo, &si) != 0) {
349         DFXLOGE("%{public}s :: Failed to SYS_rt_sigqueueinfo signal(%{public}d), errno(%{public}d).",
350             FAULTLOGGERD_SERVICE_TAG, si.si_signo, errno);
351         FaultLoggerPipePair::DelSdkDumpPipePair(requestData.pid);
352         return ResponseCode::SDK_DUMP_NOPROC;
353     }
354 #endif
355 
356     int32_t fds[PIPE_NUM_SZ] = {
357         faultLoggerPipe.GetPipeFd(PipeFdUsage::BUFFER_FD, FaultLoggerPipeType::PIPE_FD_READ),
358         faultLoggerPipe.GetPipeFd(PipeFdUsage::RESULT_FD, FaultLoggerPipeType::PIPE_FD_READ)
359     };
360     if (fds[PIPE_BUF_INDEX] < 0 || fds[PIPE_RES_INDEX] < 0) {
361         return ResponseCode::ABNORMAL_SERVICE;
362     }
363     int32_t res = ResponseCode::REQUEST_SUCCESS;
364     SendMsgToSocket(connectionFd, &res, sizeof(res));
365     SendFileDescriptorToSocket(connectionFd, fds, PIPE_NUM_SZ);
366     return res;
367 }
368 
Filter(const std::string & socketName,int32_t connectionFd,const PipFdRequestData & requestData)369 bool PipeService::Filter(const std::string &socketName, int32_t connectionFd, const PipFdRequestData &requestData)
370 {
371     if (requestData.pipeType > FaultLoggerPipeType::PIPE_FD_DELETE ||
372         requestData.pipeType < FaultLoggerPipeType::PIPE_FD_READ) {
373         return false;
374     }
375     if (socketName == SERVER_CRASH_SOCKET_NAME) {
376         return true;
377     }
378     return CheckRequestCredential(connectionFd, requestData.pid);
379 }
380 
OnRequest(const std::string & socketName,int32_t connectionFd,const PipFdRequestData & requestData)381 int32_t PipeService::OnRequest(const std::string& socketName, int32_t connectionFd, const PipFdRequestData& requestData)
382 {
383     DFX_TRACE_SCOPED("PipeServiceOnRequest");
384     if (!Filter(socketName, connectionFd, requestData)) {
385         return ResponseCode::REQUEST_REJECT;
386     }
387     int32_t responseData = ResponseCode::REQUEST_SUCCESS;
388     if (requestData.pipeType == FaultLoggerPipeType::PIPE_FD_DELETE) {
389         FaultLoggerPipePair::DelSdkDumpPipePair(requestData.pid);
390         SendMsgToSocket(connectionFd, &responseData, sizeof(responseData));
391         return responseData;
392     }
393     FaultLoggerPipePair* faultLoggerPipe = FaultLoggerPipePair::GetSdkDumpPipePair(requestData.pid);
394     if (faultLoggerPipe == nullptr) {
395         DFXLOGE("%{public}s :: cannot find pipe fd for pid(%{public}d).", FAULTLOGGERD_SERVICE_TAG, requestData.pid);
396         return ResponseCode::ABNORMAL_SERVICE;
397     }
398     int32_t fds[PIPE_NUM_SZ] = {
399         faultLoggerPipe->GetPipeFd(PipeFdUsage::BUFFER_FD, FaultLoggerPipeType::PIPE_FD_WRITE),
400         faultLoggerPipe->GetPipeFd(PipeFdUsage::RESULT_FD, FaultLoggerPipeType::PIPE_FD_WRITE)
401     };
402     if (fds[PIPE_BUF_INDEX] < 0 || fds[PIPE_RES_INDEX] < 0) {
403         DFXLOGE("%{public}s :: failed to get fds for pipeType(%{public}d).", FAULTLOGGERD_SERVICE_TAG,
404             requestData.pipeType);
405         return ResponseCode::ABNORMAL_SERVICE;
406     }
407     SendMsgToSocket(connectionFd, &responseData, sizeof(responseData));
408     SendFileDescriptorToSocket(connectionFd, fds, PIPE_NUM_SZ);
409     return responseData;
410 }
411 #endif
412 }
413 }