1 /*
2 * Copyright (c) 2021-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_daemon.h"
17
18 #include <algorithm>
19 #include <cerrno>
20 #include <csignal>
21 #include <cstring>
22 #include <ctime>
23 #include <dirent.h>
24 #include <fcntl.h>
25 #include <fstream>
26 #include <securec.h>
27 #include <sstream>
28 #include <unistd.h>
29 #include <vector>
30
31 #include <sys/epoll.h>
32 #include <sys/socket.h>
33 #include <sys/stat.h>
34 #include <sys/syscall.h>
35 #include <sys/types.h>
36 #include <sys/un.h>
37 #include <sys/wait.h>
38
39 #include "dfx_define.h"
40 #include "dfx_exception.h"
41 #include "dfx_log.h"
42 #include "dfx_util.h"
43 #include "directory_ex.h"
44 #include "fault_logger_config.h"
45 #include "fault_logger_pipe.h"
46 #include "faultloggerd_socket.h"
47 #ifndef HISYSEVENT_DISABLE
48 #include "hisysevent.h"
49 #endif
50
51 namespace OHOS {
52 namespace HiviewDFX {
53 std::shared_ptr<FaultLoggerConfig> faultLoggerConfig_;
54 std::shared_ptr<FaultLoggerPipeMap> faultLoggerPipeMap_;
55
56 namespace {
57 constexpr int32_t MAX_CONNECTION = 30;
58 constexpr int32_t REQUEST_BUF_SIZE = 2048;
59 constexpr int32_t MAX_EPOLL_EVENT = 1024;
60 const int32_t FAULTLOG_FILE_PROP = 0640;
61
62 static constexpr uint32_t ROOT_UID = 0;
63 static constexpr uint32_t BMS_UID = 1000;
64 static constexpr uint32_t HIVIEW_UID = 1201;
65 static constexpr uint32_t HIDUMPER_SERVICE_UID = 1212;
66 static constexpr uint32_t FOUNDATION_UID = 5523;
67 static const std::string FAULTLOGGERD_TAG = "FaultLoggerd";
68 static const std::string DAEMON_RESP = "RESP:COMPLETE";
69 static const int DAEMON_REMOVE_FILE_TIME_S = 60;
70
GetRequestTypeName(int32_t type)71 static std::string GetRequestTypeName(int32_t type)
72 {
73 switch (type) {
74 case (int32_t)FaultLoggerType::CPP_CRASH:
75 return "cppcrash";
76 case (int32_t)FaultLoggerType::CPP_STACKTRACE: // change the name to nativestack ?
77 return "stacktrace";
78 case (int32_t)FaultLoggerType::JS_STACKTRACE:
79 return "jsstack";
80 case (int32_t)FaultLoggerType::JS_HEAP_SNAPSHOT:
81 return "jsheap";
82 case (int32_t)FaultLoggerType::LEAK_STACKTRACE:
83 return "leakstack";
84 case (int32_t)FaultLoggerType::FFRT_CRASH_LOG:
85 return "ffrtlog";
86 default:
87 return "unsupported";
88 }
89 }
90
CheckCallerUID(uint32_t callerUid)91 static bool CheckCallerUID(uint32_t callerUid)
92 {
93 // If caller's is BMS / root or caller's uid/pid is validate, just return true
94 if ((callerUid == BMS_UID) ||
95 (callerUid == ROOT_UID) ||
96 (callerUid == HIVIEW_UID) ||
97 (callerUid == HIDUMPER_SERVICE_UID) ||
98 (callerUid == FOUNDATION_UID)) {
99 return true;
100 }
101 DFXLOG_WARN("%s :: CheckCallerUID :: Caller Uid(%d) is unexpectly.\n", FAULTLOGGERD_TAG.c_str(), callerUid);
102 return false;
103 }
104 }
105
ReportExceptionToSysEvent(CrashDumpException & exception)106 static void ReportExceptionToSysEvent(CrashDumpException& exception)
107 {
108 #ifndef HISYSEVENT_DISABLE
109 std::string errMessage;
110 if (exception.error == CRASH_DUMP_LOCAL_REPORT) {
111 std::ifstream rfile;
112 if (strlen(exception.message) == 0) {
113 return;
114 }
115 rfile.open(exception.message, std::ios::binary | std::ios::ate);
116 if (!rfile.is_open()) {
117 return;
118 }
119 std::streamsize size = rfile.tellg();
120 rfile.seekg(0, std::ios::beg);
121 std::vector<char> buf(size);
122 rfile.read(buf.data(), size);
123 errMessage = std::string(buf.begin(), buf.end());
124 } else {
125 errMessage = exception.message;
126 }
127 HiSysEventWrite(
128 HiSysEvent::Domain::RELIABILITY,
129 "CPP_CRASH_EXCEPTION",
130 HiSysEvent::EventType::FAULT,
131 "PID", exception.pid,
132 "UID", exception.uid,
133 "HAPPEN_TIME", exception.time,
134 "ERROR_CODE", exception.error,
135 "ERROR_MSG", errMessage);
136 #endif
137 }
138
FaultLoggerDaemon()139 FaultLoggerDaemon::FaultLoggerDaemon()
140 {
141 }
142
StartServer()143 int32_t FaultLoggerDaemon::StartServer()
144 {
145 if (!CreateSockets()) {
146 DFXLOG_ERROR("%s :: Failed to create faultloggerd sockets.", FAULTLOGGERD_TAG.c_str());
147 CleanupSockets();
148 return -1;
149 }
150
151 if (!InitEnvironment()) {
152 DFXLOG_ERROR("%s :: Failed to init environment.", FAULTLOGGERD_TAG.c_str());
153 CleanupSockets();
154 return -1;
155 }
156
157 if (!CreateEventFd()) {
158 DFXLOG_ERROR("%s :: Failed to create eventFd.", FAULTLOGGERD_TAG.c_str());
159 CleanupSockets();
160 return -1;
161 }
162
163 // loop in WaitForRequest
164 WaitForRequest();
165
166 CleanupEventFd();
167 CleanupSockets();
168 return 0;
169 }
170
HandleAccept(int32_t epollFd,int32_t socketFd)171 void FaultLoggerDaemon::HandleAccept(int32_t epollFd, int32_t socketFd)
172 {
173 struct sockaddr_un clientAddr;
174 socklen_t clientAddrSize = static_cast<socklen_t>(sizeof(clientAddr));
175
176 int connectionFd = accept(socketFd, reinterpret_cast<struct sockaddr *>(&clientAddr), &clientAddrSize);
177 if (connectionFd < 0) {
178 DFXLOG_WARN("%s :: Failed to accept connection", FAULTLOGGERD_TAG.c_str());
179 return;
180 }
181
182 AddEvent(eventFd_, connectionFd, EPOLLIN);
183 connectionMap_[connectionFd] = socketFd;
184 }
185
186 #ifdef FAULTLOGGERD_FUZZER
HandleRequestForFuzzer(int32_t epollFd,int32_t connectionFd)187 void FaultLoggerDaemon::HandleRequestForFuzzer(int32_t epollFd, int32_t connectionFd)
188 {
189 HandleRequest(epollFd, connectionFd);
190 }
191 #endif
192
CheckReadRequest(ssize_t nread,ssize_t size)193 static bool CheckReadRequest(ssize_t nread, ssize_t size)
194 {
195 if (nread < 0) {
196 DFXLOG_ERROR("%s :: Failed to read message", FAULTLOGGERD_TAG.c_str());
197 return false;
198 } else if (nread == 0) {
199 DFXLOG_ERROR("%s :: Read null from request socket", FAULTLOGGERD_TAG.c_str());
200 return false;
201 } else if (nread != static_cast<long>(size)) {
202 return false;
203 }
204 return true;
205 }
206
HandleRequest(int32_t epollFd,int32_t connectionFd)207 void FaultLoggerDaemon::HandleRequest(int32_t epollFd, int32_t connectionFd)
208 {
209 if (epollFd < 0 || connectionFd < 3) { // 3: not allow fd = 0,1,2 because they are reserved by system
210 DFXLOG_ERROR("%s :: HandleRequest recieved invalid fd parmeters.", FAULTLOGGERD_TAG.c_str());
211 return;
212 }
213
214 std::vector<uint8_t> buf(REQUEST_BUF_SIZE, 0);
215 do {
216 ssize_t nread = read(connectionFd, buf.data(), REQUEST_BUF_SIZE);
217 if (CheckReadRequest(nread, sizeof(FaultLoggerdStatsRequest))) {
218 HandleDumpStats(connectionFd, reinterpret_cast<FaultLoggerdStatsRequest *>(buf.data()));
219 break;
220 }
221
222 if (!CheckReadRequest(nread, sizeof(FaultLoggerdRequest))) {
223 break;
224 }
225
226 auto request = reinterpret_cast<FaultLoggerdRequest *>(buf.data());
227 if (!CheckRequestCredential(connectionFd, request)) {
228 break;
229 }
230
231 DFXLOG_DEBUG("%s :: clientType(%d).\n", FAULTLOGGERD_TAG.c_str(), request->clientType);
232 switch (request->clientType) {
233 case static_cast<int32_t>(FaultLoggerClientType::DEFAULT_CLIENT):
234 HandleDefaultClientRequest(connectionFd, request);
235 break;
236 case static_cast<int32_t>(FaultLoggerClientType::LOG_FILE_DES_CLIENT):
237 HandleLogFileDesClientRequest(connectionFd, request);
238 break;
239 case static_cast<int32_t>(FaultLoggerClientType::PRINT_T_HILOG_CLIENT):
240 HandlePrintTHilogClientRequest(connectionFd, request);
241 break;
242 case static_cast<int32_t>(FaultLoggerClientType::PERMISSION_CLIENT):
243 HandlePermissionRequest(connectionFd, request);
244 break;
245 case static_cast<int32_t>(FaultLoggerClientType::SDK_DUMP_CLIENT):
246 HandleSdkDumpRequest(connectionFd, request);
247 break;
248 case static_cast<int32_t>(FaultLoggerClientType::PIPE_FD_CLIENT):
249 HandlePipeFdClientRequest(connectionFd, request);
250 break;
251 case static_cast<int32_t>(FaultLoggerClientType::REPORT_EXCEPTION_CLIENT):
252 HandleExceptionRequest(connectionFd, request);
253 break;
254 default:
255 DFXLOG_ERROR("%s :: unknown clientType(%d).\n", FAULTLOGGERD_TAG.c_str(), request->clientType);
256 break;
257 }
258 } while (false);
259 DelEvent(eventFd_, connectionFd, EPOLLIN);
260 connectionMap_.erase(connectionFd);
261 }
262
InitEnvironment()263 bool FaultLoggerDaemon::InitEnvironment()
264 {
265 faultLoggerConfig_ = std::make_shared<FaultLoggerConfig>(LOG_FILE_NUMBER, LOG_FILE_SIZE,
266 LOG_FILE_PATH, DEBUG_LOG_FILE_PATH);
267 faultLoggerPipeMap_ = std::make_shared<FaultLoggerPipeMap>();
268
269 if (!OHOS::ForceCreateDirectory(faultLoggerConfig_->GetLogFilePath())) {
270 DFXLOG_ERROR("%s :: Failed to ForceCreateDirectory GetLogFilePath", FAULTLOGGERD_TAG.c_str());
271 return false;
272 }
273
274 if (!OHOS::ForceCreateDirectory(faultLoggerConfig_->GetDebugLogFilePath())) {
275 DFXLOG_ERROR("%s :: Failed to ForceCreateDirectory GetDebugLogFilePath", FAULTLOGGERD_TAG.c_str());
276 return false;
277 }
278
279 signal(SIGCHLD, SIG_IGN);
280 signal(SIGPIPE, SIG_IGN);
281 return true;
282 }
283
HandleDefaultClientRequest(int32_t connectionFd,const FaultLoggerdRequest * request)284 void FaultLoggerDaemon::HandleDefaultClientRequest(int32_t connectionFd, const FaultLoggerdRequest * request)
285 {
286 RemoveTempFileIfNeed();
287
288 int fd = CreateFileForRequest(request->type, request->pid, request->tid, request->time, false);
289 if (fd < 0) {
290 DFXLOG_ERROR("%s :: Failed to create log file, errno(%d)", FAULTLOGGERD_TAG.c_str(), errno);
291 return;
292 }
293 RecordFileCreation(request->type, request->pid);
294 SendFileDescriptorToSocket(connectionFd, fd);
295
296 close(fd);
297 }
298
HandleLogFileDesClientRequest(int32_t connectionFd,const FaultLoggerdRequest * request)299 void FaultLoggerDaemon::HandleLogFileDesClientRequest(int32_t connectionFd, const FaultLoggerdRequest * request)
300 {
301 int fd = CreateFileForRequest(request->type, request->pid, request->tid, request->time, true);
302 if (fd < 0) {
303 DFXLOG_ERROR("%s :: Failed to create log file, errno(%d)", FAULTLOGGERD_TAG.c_str(), errno);
304 return;
305 }
306 SendFileDescriptorToSocket(connectionFd, fd);
307
308 close(fd);
309 }
310
HandleExceptionRequest(int32_t connectionFd,FaultLoggerdRequest * request)311 void FaultLoggerDaemon::HandleExceptionRequest(int32_t connectionFd, FaultLoggerdRequest * request)
312 {
313 if (write(connectionFd, DAEMON_RESP.c_str(), DAEMON_RESP.length()) != static_cast<ssize_t>(DAEMON_RESP.length())) {
314 DFXLOG_ERROR("%s :: Failed to write DAEMON_RESP.", FAULTLOGGERD_TAG.c_str());
315 }
316
317 CrashDumpException exception;
318 (void)memset_s(&exception, sizeof(CrashDumpException), 0, sizeof(CrashDumpException));
319 ssize_t nread = read(connectionFd, &exception, sizeof(CrashDumpException));
320 if (!CheckReadRequest(nread, sizeof(CrashDumpException))) {
321 return;
322 }
323
324 ReportExceptionToSysEvent(exception);
325 }
326
HandlePipeFdClientRequest(int32_t connectionFd,FaultLoggerdRequest * request)327 void FaultLoggerDaemon::HandlePipeFdClientRequest(int32_t connectionFd, FaultLoggerdRequest * request)
328 {
329 DFXLOG_DEBUG("%s :: pid(%d), pipeType(%d).\n", FAULTLOGGERD_TAG.c_str(), request->pid, request->pipeType);
330 int fd = -1;
331 FaultLoggerPipe2* faultLoggerPipe = faultLoggerPipeMap_->Get(request->pid);
332 if (faultLoggerPipe == nullptr) {
333 DFXLOG_ERROR("%s :: cannot find pipe fd for pid(%d).\n", FAULTLOGGERD_TAG.c_str(), request->pid);
334 return;
335 }
336 switch (request->pipeType) {
337 case (int32_t)FaultLoggerPipeType::PIPE_FD_READ_BUF: {
338 FaultLoggerCheckPermissionResp resSecurityCheck = SecurityCheck(connectionFd, request);
339 if (FaultLoggerCheckPermissionResp::CHECK_PERMISSION_PASS != resSecurityCheck) {
340 return;
341 }
342 if ((faultLoggerPipe->faultLoggerPipeBuf_) != nullptr) {
343 fd = faultLoggerPipe->faultLoggerPipeBuf_->GetReadFd();
344 }
345 break;
346 }
347 case (int32_t)FaultLoggerPipeType::PIPE_FD_WRITE_BUF: {
348 if ((faultLoggerPipe->faultLoggerPipeBuf_) != nullptr) {
349 fd = faultLoggerPipe->faultLoggerPipeBuf_->GetWriteFd();
350 }
351 break;
352 }
353 case (int32_t)FaultLoggerPipeType::PIPE_FD_READ_RES: {
354 FaultLoggerCheckPermissionResp resSecurityCheck = SecurityCheck(connectionFd, request);
355 if (FaultLoggerCheckPermissionResp::CHECK_PERMISSION_PASS != resSecurityCheck) {
356 return;
357 }
358 if ((faultLoggerPipe->faultLoggerPipeRes_) != nullptr) {
359 fd = faultLoggerPipe->faultLoggerPipeRes_->GetReadFd();
360 }
361 break;
362 }
363 case (int32_t)FaultLoggerPipeType::PIPE_FD_WRITE_RES: {
364 if ((faultLoggerPipe->faultLoggerPipeRes_) != nullptr) {
365 fd = faultLoggerPipe->faultLoggerPipeRes_->GetWriteFd();
366 }
367 break;
368 }
369 case (int32_t)FaultLoggerPipeType::PIPE_FD_DELETE: {
370 faultLoggerPipeMap_->Del(request->pid);
371 return;
372 }
373 case (int32_t)FaultLoggerPipeType::PIPE_FD_JSON_READ_BUF: {
374 FaultLoggerCheckPermissionResp resSecurityCheck = SecurityCheck(connectionFd, request);
375 if (FaultLoggerCheckPermissionResp::CHECK_PERMISSION_PASS != resSecurityCheck) {
376 return;
377 }
378 if ((faultLoggerPipe->faultLoggerJsonPipeBuf_) != nullptr) {
379 fd = faultLoggerPipe->faultLoggerJsonPipeBuf_->GetReadFd();
380 }
381 break;
382 }
383 case (int32_t)FaultLoggerPipeType::PIPE_FD_JSON_WRITE_BUF: {
384 if ((faultLoggerPipe->faultLoggerJsonPipeBuf_) != nullptr) {
385 fd = faultLoggerPipe->faultLoggerJsonPipeBuf_->GetWriteFd();
386 }
387 break;
388 }
389 case (int32_t)FaultLoggerPipeType::PIPE_FD_JSON_READ_RES: {
390 FaultLoggerCheckPermissionResp resSecurityCheck = SecurityCheck(connectionFd, request);
391 if (FaultLoggerCheckPermissionResp::CHECK_PERMISSION_PASS != resSecurityCheck) {
392 return;
393 }
394 if ((faultLoggerPipe->faultLoggerJsonPipeRes_) != nullptr) {
395 fd = faultLoggerPipe->faultLoggerJsonPipeRes_->GetReadFd();
396 }
397 break;
398 }
399 case (int32_t)FaultLoggerPipeType::PIPE_FD_JSON_WRITE_RES: {
400 if ((faultLoggerPipe->faultLoggerJsonPipeRes_) != nullptr) {
401 fd = faultLoggerPipe->faultLoggerJsonPipeRes_->GetWriteFd();
402 }
403 break;
404 }
405 default:
406 DFXLOG_ERROR("%s :: unknown pipeType(%d).", FAULTLOGGERD_TAG.c_str(), request->pipeType);
407 return;
408 }
409 if (fd < 0) {
410 DFXLOG_ERROR("%s :: Failed to get pipe fd, pipeType(%d)", FAULTLOGGERD_TAG.c_str(), request->pipeType);
411 return;
412 }
413 SendFileDescriptorToSocket(connectionFd, fd);
414 }
415
HandlePrintTHilogClientRequest(int32_t const connectionFd,FaultLoggerdRequest * request)416 void FaultLoggerDaemon::HandlePrintTHilogClientRequest(int32_t const connectionFd, FaultLoggerdRequest * request)
417 {
418 char buf[LINE_BUF_SIZE] = {0};
419
420 if (write(connectionFd, DAEMON_RESP.c_str(), DAEMON_RESP.length()) != static_cast<ssize_t>(DAEMON_RESP.length())) {
421 DFXLOG_ERROR("%s :: Failed to write DAEMON_RESP.", FAULTLOGGERD_TAG.c_str());
422 }
423
424 int nread = read(connectionFd, buf, sizeof(buf) - 1);
425 if (nread < 0) {
426 DFXLOG_ERROR("%s :: Failed to read message, errno(%d)", FAULTLOGGERD_TAG.c_str(), errno);
427 } else if (nread == 0) {
428 DFXLOG_ERROR("%s :: HandlePrintTHilogClientRequest :: Read null from request socket", FAULTLOGGERD_TAG.c_str());
429 } else {
430 DFXLOG_ERROR("%s", buf);
431 }
432 }
433
SecurityCheck(int32_t connectionFd,FaultLoggerdRequest * request)434 FaultLoggerCheckPermissionResp FaultLoggerDaemon::SecurityCheck(int32_t connectionFd, FaultLoggerdRequest * request)
435 {
436 FaultLoggerCheckPermissionResp resCheckPermission = FaultLoggerCheckPermissionResp::CHECK_PERMISSION_REJECT;
437
438 struct ucred rcred;
439 do {
440 int optval = 1;
441 if (setsockopt(connectionFd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) == -1) {
442 DFXLOG_ERROR("%s :: setsockopt SO_PASSCRED error, errno(%d)", FAULTLOGGERD_TAG.c_str(), errno);
443 break;
444 }
445
446 if (write(connectionFd, DAEMON_RESP.c_str(), DAEMON_RESP.length()) !=
447 static_cast<ssize_t>(DAEMON_RESP.length())) {
448 DFXLOG_ERROR("%s :: Failed to write DAEMON_RESP, errno(%d)", FAULTLOGGERD_TAG.c_str(), errno);
449 }
450
451 if (!RecvMsgCredFromSocket(connectionFd, &rcred)) {
452 DFXLOG_ERROR("%s :: Recv msg ucred error.", FAULTLOGGERD_TAG.c_str());
453 break;
454 }
455
456 request->uid = rcred.uid;
457 request->callerPid = static_cast<int32_t>(rcred.pid);
458
459 auto it = connectionMap_.find(connectionFd);
460 if (it == connectionMap_.end()) {
461 break;
462 }
463
464 if (it->second == sdkdumpSocketFd_) {
465 resCheckPermission = FaultLoggerCheckPermissionResp::CHECK_PERMISSION_PASS;
466 break;
467 }
468
469 bool res = CheckCallerUID(request->uid);
470 if (res) {
471 resCheckPermission = FaultLoggerCheckPermissionResp::CHECK_PERMISSION_PASS;
472 }
473 } while (false);
474
475 return resCheckPermission;
476 }
477
HandlePermissionRequest(int32_t connectionFd,FaultLoggerdRequest * request)478 void FaultLoggerDaemon::HandlePermissionRequest(int32_t connectionFd, FaultLoggerdRequest * request)
479 {
480 FaultLoggerCheckPermissionResp resSecurityCheck = SecurityCheck(connectionFd, request);
481 if (FaultLoggerCheckPermissionResp::CHECK_PERMISSION_PASS == resSecurityCheck) {
482 send(connectionFd, "1", strlen("1"), 0);
483 }
484 if (FaultLoggerCheckPermissionResp::CHECK_PERMISSION_REJECT == resSecurityCheck) {
485 send(connectionFd, "2", strlen("2"), 0);
486 }
487 }
488
HandleSdkDumpRequest(int32_t connectionFd,FaultLoggerdRequest * request)489 void FaultLoggerDaemon::HandleSdkDumpRequest(int32_t connectionFd, FaultLoggerdRequest * request)
490 {
491 DFXLOG_INFO("Receive dump request for pid:%d tid:%d.", request->pid, request->tid);
492 FaultLoggerSdkDumpResp resSdkDump = FaultLoggerSdkDumpResp::SDK_DUMP_PASS;
493 FaultLoggerCheckPermissionResp resSecurityCheck = SecurityCheck(connectionFd, request);
494
495 /*
496 * all threads my user, local pid my user, remote pid other user's process
497 * 3rd Y Y(in signal_handler local) Y(in signal_handler loacl) N
498 * system Y Y(in signal_handler local) Y(in signal_handler loacl) Y(in signal_handler remote)
499 * root Y Y(in signal_handler local) Y(in signal_handler loacl) Y(in signal_handler remote)
500 */
501
502 /*
503 * 1. pid != 0 && tid != 0: means we want dump a thread, so we send signal to a thread.
504 Main thread stack is tid's stack, we need ignore other thread info.
505 * 2. pid != 0 && tid == 0: means we want dump a process, so we send signal to process.
506 Main thead stack is pid's stack, we need other tread info.
507 */
508
509 /*
510 * in signal_handler we need to check caller pid and tid(which is send to signal handler by SYS_rt_sig.).
511 * 1. caller pid == signal pid, means we do back trace in ourself process, means local backtrace.
512 * |- we do all tid back trace in signal handler's local unwind.
513 * 2. pid != signal pid, means we do remote back trace.
514 */
515
516 /*
517 * in local back trace, all unwind stack will save to signal_handler global var.(mutex lock in signal handler.)
518 * in remote back trace, all unwind stack will save to file, and read in dump_catcher, then return.
519 */
520
521 do {
522 if ((request->pid <= 0) || (FaultLoggerCheckPermissionResp::CHECK_PERMISSION_REJECT == resSecurityCheck)) {
523 DFXLOG_ERROR("%s :: HandleSdkDumpRequest :: pid(%d) or resSecurityCheck(%d) fail.\n", \
524 FAULTLOGGERD_TAG.c_str(), request->pid, (int)resSecurityCheck);
525 resSdkDump = FaultLoggerSdkDumpResp::SDK_DUMP_REJECT;
526 break;
527 }
528 if (IsCrashed(request->pid)) {
529 resSdkDump = FaultLoggerSdkDumpResp::SDK_PROCESS_CRASHED;
530 DFXLOG_WARN("%s :: pid(%d) has been crashed, break.\n", FAULTLOGGERD_TAG.c_str(), request->pid);
531 break;
532 }
533 if (faultLoggerPipeMap_->Check(request->pid, request->time)) {
534 resSdkDump = FaultLoggerSdkDumpResp::SDK_DUMP_REPEAT;
535 DFXLOG_ERROR("%s :: pid(%d) is dumping, break.\n", FAULTLOGGERD_TAG.c_str(), request->pid);
536 break;
537 }
538 faultLoggerPipeMap_->Set(request->pid, request->time, request->isJson);
539
540 #pragma clang diagnostic push
541 #pragma clang diagnostic ignored "-Winitializer-overrides"
542 // defined in out/hi3516dv300/obj/third_party/musl/intermidiates/linux/musl_src_ported/include/signal.h
543 siginfo_t si {0};
544 si.si_signo = SIGDUMP;
545 si.si_errno = 0;
546 si.si_value.sival_int = request->tid;
547 si.si_code = request->sigCode;
548 si.si_pid = request->callerPid;
549 si.si_uid = static_cast<uid_t>(request->callerTid);
550 #pragma clang diagnostic pop
551 int32_t reqTid = 0;
552 if (request->tid == 0) {
553 /*
554 * means we need dump all the threads in a process
555 * --------
556 * Accroding to the linux manual, A process-directed signal may be delivered to any one of the
557 * threads that does not currently have the signal blocked. So we should specify the main thread
558 * as the target thread of signal.
559 */
560 reqTid = request->pid;
561 } else {
562 // means we need dump a specified thread
563 reqTid = request->tid;
564 }
565 if (syscall(SYS_rt_tgsigqueueinfo, request->pid, reqTid, si.si_signo, &si) != 0) {
566 DFXLOG_ERROR("Failed to SYS_rt_tgsigqueueinfo signal(%d), errno(%d).", si.si_signo, errno);
567 resSdkDump = FaultLoggerSdkDumpResp::SDK_DUMP_NOPROC;
568 break;
569 }
570 } while (false);
571 auto retMsg = std::to_string(resSdkDump);
572 send(connectionFd, retMsg.data(), retMsg.length(), 0);
573 }
574
RecordFileCreation(int32_t type,int32_t pid)575 void FaultLoggerDaemon::RecordFileCreation(int32_t type, int32_t pid)
576 {
577 if (type == static_cast<int32_t>(FaultLoggerType::CPP_CRASH)) {
578 ClearTimeOutRecords();
579 crashTimeMap_[pid] = time(nullptr);
580 }
581 }
582
ClearTimeOutRecords()583 void FaultLoggerDaemon::ClearTimeOutRecords()
584 {
585 constexpr int validTime = 8;
586 auto currentTime = time(nullptr);
587 for (auto it = crashTimeMap_.begin(); it != crashTimeMap_.end();) {
588 if ((it->second + validTime) <= currentTime) {
589 crashTimeMap_.erase(it++);
590 } else {
591 it++;
592 }
593 }
594 }
595
IsCrashed(int32_t pid)596 bool FaultLoggerDaemon::IsCrashed(int32_t pid)
597 {
598 ClearTimeOutRecords();
599 return crashTimeMap_.find(pid) != crashTimeMap_.end();
600 }
601
CreateFileForRequest(int32_t type,int32_t pid,int32_t tid,uint64_t time,bool debugFlag) const602 int32_t FaultLoggerDaemon::CreateFileForRequest(int32_t type, int32_t pid, int32_t tid,
603 uint64_t time, bool debugFlag) const
604 {
605 std::string typeStr = GetRequestTypeName(type);
606 if (typeStr == "unsupported") {
607 DFXLOG_ERROR("Unsupported request type(%d)", type);
608 return -1;
609 }
610
611 std::string folderPath = "";
612 if (debugFlag == false) {
613 folderPath = faultLoggerConfig_->GetLogFilePath();
614 } else {
615 folderPath = faultLoggerConfig_->GetDebugLogFilePath();
616 }
617
618 if (time == 0) {
619 time = static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::milliseconds>\
620 (std::chrono::system_clock::now().time_since_epoch()).count());
621 }
622
623 std::stringstream ss;
624 ss << folderPath << "/" << typeStr << "-" << pid;
625 if (type == FaultLoggerType::JS_HEAP_SNAPSHOT) {
626 ss << "-" << tid;
627 }
628 ss << "-" << time;
629 const std::string path = ss.str();
630 DFXLOG_INFO("%s :: file path(%s).\n", FAULTLOGGERD_TAG.c_str(), path.c_str());
631 if (!VerifyFilePath(path, VALID_FILE_PATH)) {
632 DFXLOG_ERROR("%s :: Open %s fail, please check it under valid path.\n", FAULTLOGGERD_TAG.c_str(), path.c_str());
633 return -1;
634 }
635 int32_t fd = OHOS_TEMP_FAILURE_RETRY(open(path.c_str(), O_RDWR | O_CREAT, FAULTLOG_FILE_PROP));
636 if (fd != -1) {
637 if (!ChangeModeFile(path, FAULTLOG_FILE_PROP)) {
638 DFXLOG_ERROR("%s :: Failed to ChangeMode CreateFileForRequest", FAULTLOGGERD_TAG.c_str());
639 }
640 }
641 return fd;
642 }
643
RemoveTempFileIfNeed()644 void FaultLoggerDaemon::RemoveTempFileIfNeed()
645 {
646 int maxFileCount = 50;
647 int currentLogCounts = 0;
648
649 std::vector<std::string> files;
650 OHOS::GetDirFiles(faultLoggerConfig_->GetLogFilePath(), files);
651 currentLogCounts = (int)files.size();
652
653 maxFileCount = faultLoggerConfig_->GetLogFileMaxNumber();
654 if (currentLogCounts < maxFileCount) {
655 return;
656 }
657
658 std::sort(files.begin(), files.end(),
659 [](const std::string& lhs, const std::string& rhs) -> int {
660 auto lhsSplitPos = lhs.find_last_of("-");
661 auto rhsSplitPos = rhs.find_last_of("-");
662 if (lhsSplitPos == std::string::npos || rhsSplitPos == std::string::npos) {
663 return lhs.compare(rhs) > 0;
664 }
665
666 return lhs.substr(lhsSplitPos).compare(rhs.substr(rhsSplitPos)) > 0;
667 });
668
669 time_t currentTime = static_cast<time_t>(time(nullptr));
670 if (currentTime <= 0) {
671 DFXLOG_ERROR("%s :: currentTime is less than zero CreateFileForRequest", FAULTLOGGERD_TAG.c_str());
672 }
673
674 constexpr int deleteNum = 1;
675 int startIndex = maxFileCount > deleteNum ? maxFileCount - deleteNum : maxFileCount;
676 for (unsigned int index = (unsigned int)startIndex; index < files.size(); index++) {
677 struct stat st;
678 int err = stat(files[index].c_str(), &st);
679 if (err != 0) {
680 DFXLOG_ERROR("%s :: Get log stat failed, errno(%d).", FAULTLOGGERD_TAG.c_str(), errno);
681 } else {
682 if ((currentTime - st.st_mtime) <= DAEMON_REMOVE_FILE_TIME_S) {
683 continue;
684 }
685 }
686
687 OHOS::RemoveFile(files[index]);
688 DFXLOG_DEBUG("%s :: Now we rm file(%s) as max log number exceeded.", \
689 FAULTLOGGERD_TAG.c_str(), files[index].c_str());
690 }
691 }
692
AddEvent(int32_t epollFd,int32_t addFd,uint32_t event)693 void FaultLoggerDaemon::AddEvent(int32_t epollFd, int32_t addFd, uint32_t event)
694 {
695 epoll_event ev;
696 ev.events = event;
697 ev.data.fd = addFd;
698 int ret = epoll_ctl(epollFd, EPOLL_CTL_ADD, addFd, &ev);
699 if (ret < 0) {
700 DFXLOG_WARN("%s :: Failed to epoll ctl add Fd(%d), errno(%d)", FAULTLOGGERD_TAG.c_str(), addFd, errno);
701 }
702 }
703
DelEvent(int32_t epollFd,int32_t delFd,uint32_t event)704 void FaultLoggerDaemon::DelEvent(int32_t epollFd, int32_t delFd, uint32_t event)
705 {
706 epoll_event ev;
707 ev.events = event;
708 ev.data.fd = delFd;
709 int ret = epoll_ctl(epollFd, EPOLL_CTL_DEL, delFd, &ev);
710 if (ret < 0) {
711 DFXLOG_WARN("%s :: Failed to epoll ctl del Fd(%d), errno(%d)", FAULTLOGGERD_TAG.c_str(), delFd, errno);
712 }
713 close(delFd);
714 }
715
CheckRequestCredential(int32_t connectionFd,FaultLoggerdRequest * request)716 bool FaultLoggerDaemon::CheckRequestCredential(int32_t connectionFd, FaultLoggerdRequest* request)
717 {
718 if (request == nullptr) {
719 return false;
720 }
721
722 auto it = connectionMap_.find(connectionFd);
723 if (it == connectionMap_.end()) {
724 DFXLOG_ERROR("%s : Failed to find fd:%d, map size:%zu", FAULTLOGGERD_TAG.c_str(),
725 connectionFd, connectionMap_.size());
726 return false;
727 }
728
729 if (it->second == crashSocketFd_ || it->second == sdkdumpSocketFd_) {
730 // only processdump use this socket
731 return true;
732 }
733
734 struct ucred creds = {};
735 socklen_t credSize = sizeof(creds);
736 int err = getsockopt(connectionFd, SOL_SOCKET, SO_PEERCRED, &creds, &credSize);
737 if (err != 0) {
738 DFXLOG_ERROR("%s :: Failed to CheckRequestCredential, errno(%d)", FAULTLOGGERD_TAG.c_str(), errno);
739 return false;
740 }
741
742 if (CheckCallerUID(creds.uid)) {
743 return true;
744 }
745
746 bool isCredentialMatched = (creds.pid == request->pid);
747 if (request->clientType == (int32_t)REPORT_EXCEPTION_CLIENT) {
748 isCredentialMatched = (creds.uid == request->uid); /* check uid when report exception */
749 }
750 if (!isCredentialMatched) {
751 DFXLOG_WARN("Failed to check request credential request:%d:%d cred:%d:%d fd:%d:%d",
752 request->pid, request->uid, creds.pid, creds.uid, it->second, crashSocketFd_);
753 }
754 return isCredentialMatched;
755 }
756
CreateSockets()757 bool FaultLoggerDaemon::CreateSockets()
758 {
759 if (!StartListen(defaultSocketFd_, SERVER_SOCKET_NAME, MAX_CONNECTION)) {
760 return false;
761 }
762
763 if (!StartListen(crashSocketFd_, SERVER_CRASH_SOCKET_NAME, MAX_CONNECTION)) {
764 close(defaultSocketFd_);
765 defaultSocketFd_ = -1;
766 return false;
767 }
768
769 if (!StartListen(sdkdumpSocketFd_, SERVER_SDKDUMP_SOCKET_NAME, MAX_CONNECTION)) {
770 close(defaultSocketFd_);
771 defaultSocketFd_ = -1;
772 close(crashSocketFd_);
773 crashSocketFd_ = -1;
774 return false;
775 }
776
777 return true;
778 }
779
CleanupSockets()780 void FaultLoggerDaemon::CleanupSockets()
781 {
782 if (defaultSocketFd_ >= 0) {
783 close(defaultSocketFd_);
784 defaultSocketFd_ = -1;
785 }
786
787 if (crashSocketFd_ >= 0) {
788 close(crashSocketFd_);
789 crashSocketFd_ = -1;
790 }
791
792 if (sdkdumpSocketFd_ >= 0) {
793 close(sdkdumpSocketFd_);
794 sdkdumpSocketFd_ = -1;
795 }
796 }
797
CreateEventFd()798 bool FaultLoggerDaemon::CreateEventFd()
799 {
800 eventFd_ = epoll_create(MAX_EPOLL_EVENT);
801 if (eventFd_ < 0) {
802 return false;
803 }
804 return true;
805 }
806
WaitForRequest()807 void FaultLoggerDaemon::WaitForRequest()
808 {
809 AddEvent(eventFd_, defaultSocketFd_, EPOLLIN);
810 AddEvent(eventFd_, crashSocketFd_, EPOLLIN);
811 AddEvent(eventFd_, sdkdumpSocketFd_, EPOLLIN);
812 epoll_event events[MAX_CONNECTION];
813 DFXLOG_DEBUG("%s :: %s: start epoll wait.", FAULTLOGGERD_TAG.c_str(), __func__);
814 do {
815 int epollNum = epoll_wait(eventFd_, events, MAX_CONNECTION, -1);
816 if (epollNum < 0) {
817 if (errno != EINTR) {
818 DFXLOG_ERROR("%s :: %s: epoll wait error, errno(%d).", FAULTLOGGERD_TAG.c_str(), __func__, errno);
819 }
820 continue;
821 }
822 for (int i = 0; i < epollNum; i++) {
823 if (!(events[i].events & EPOLLIN)) {
824 DFXLOG_WARN("%s :: %s: epoll event(%d) error.", FAULTLOGGERD_TAG.c_str(), __func__, events[i].events);
825 continue;
826 }
827
828 int fd = events[i].data.fd;
829 if (fd == defaultSocketFd_ || fd == crashSocketFd_ || fd == sdkdumpSocketFd_) {
830 HandleAccept(eventFd_, fd);
831 } else {
832 HandleRequest(eventFd_, fd);
833 }
834 }
835 } while (true);
836 }
837
CleanupEventFd()838 void FaultLoggerDaemon::CleanupEventFd()
839 {
840 DelEvent(eventFd_, defaultSocketFd_, EPOLLIN);
841 DelEvent(eventFd_, crashSocketFd_, EPOLLIN);
842 DelEvent(eventFd_, sdkdumpSocketFd_, EPOLLIN);
843
844 if (eventFd_ > 0) {
845 close(eventFd_);
846 eventFd_ = -1;
847 }
848 }
849
GetElfName(FaultLoggerdStatsRequest * request)850 std::string GetElfName(FaultLoggerdStatsRequest* request)
851 {
852 if (request == nullptr || strlen(request->callerElf) > NAME_BUF_LEN) {
853 return "";
854 }
855
856 std::stringstream stream;
857 stream << std::string(request->callerElf, strlen(request->callerElf));
858 stream << "(";
859 stream << std::hex << request->offset;
860 stream << ")";
861 return stream.str();
862 }
863
HandleDumpStats(int32_t connectionFd,FaultLoggerdStatsRequest * request)864 void FaultLoggerDaemon::HandleDumpStats(int32_t connectionFd, FaultLoggerdStatsRequest* request)
865 {
866 DFXLOG_INFO("%s :: %s: HandleDumpStats", FAULTLOGGERD_TAG.c_str(), __func__);
867 size_t index = 0;
868 bool hasRecord = false;
869 for (index = 0; index < stats_.size(); index++) {
870 if (stats_[index].pid == request->pid) {
871 hasRecord = true;
872 break;
873 }
874 }
875
876 DumpStats stats;
877 if (request->type == PROCESS_DUMP && !hasRecord) {
878 stats.pid = request->pid;
879 stats.signalTime = request->signalTime;
880 stats.processdumpStartTime = request->processdumpStartTime;
881 stats.processdumpFinishTime = request->processdumpFinishTime;
882 stats.targetProcessName = request->targetProcess;
883 stats_.emplace_back(stats);
884 } else if (request->type == DUMP_CATCHER && hasRecord) {
885 stats_[index].requestTime = request->requestTime;
886 stats_[index].dumpCatcherFinishTime = request->dumpCatcherFinishTime;
887 stats_[index].callerElfName = GetElfName(request);
888 stats_[index].callerProcessName = request->callerProcess;
889 stats_[index].result = request->result;
890 stats_[index].summary = request->summary;
891 ReportDumpStats(stats_[index]);
892 stats_.erase(stats_.begin() + index);
893 } else if (request->type == DUMP_CATCHER) {
894 stats.pid = request->pid;
895 stats.requestTime = request->requestTime;
896 stats.dumpCatcherFinishTime = request->dumpCatcherFinishTime;
897 stats.callerElfName = GetElfName(request);
898 stats.result = request->result;
899 stats.callerProcessName = request->callerProcess;
900 stats.summary = request->summary;
901 ReportDumpStats(stats);
902 }
903 RemoveTimeoutDumpStats();
904 }
905
RemoveTimeoutDumpStats()906 void FaultLoggerDaemon::RemoveTimeoutDumpStats()
907 {
908 const uint64_t timeout = 10000;
909 uint64_t now = GetTimeMilliSeconds();
910 for (auto it = stats_.begin(); it != stats_.end();) {
911 if (((now > it->signalTime) && (now - it->signalTime > timeout)) ||
912 (now <= it->signalTime)) {
913 it = stats_.erase(it);
914 } else {
915 ++it;
916 }
917 }
918 }
919
ReportDumpStats(const DumpStats & stat)920 void FaultLoggerDaemon::ReportDumpStats(const DumpStats& stat)
921 {
922 #ifndef HISYSEVENT_DISABLE
923 HiSysEventWrite(
924 HiSysEvent::Domain::HIVIEWDFX,
925 "DUMP_CATCHER_STATS",
926 HiSysEvent::EventType::STATISTIC,
927 "CALLER_PROCESS_NAME", stat.callerProcessName,
928 "CALLER_FUNC_NAME", stat.callerElfName,
929 "TARGET_PROCESS_NAME", stat.targetProcessName,
930 "RESULT", stat.result,
931 "SUMMARY", stat.summary, // we need to parse summary when interface return false
932 "PID", stat.pid,
933 "REQUEST_TIME", stat.requestTime,
934 "OVERALL_TIME", stat.dumpCatcherFinishTime - stat.requestTime,
935 "SIGNAL_TIME", stat.signalTime - stat.requestTime,
936 "DUMPER_START_TIME", stat.processdumpStartTime - stat.signalTime,
937 "UNWIND_TIME", stat.processdumpFinishTime - stat.processdumpStartTime);
938 #endif
939 }
940 } // namespace HiviewDFX
941 } // namespace OHOS
942