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 }