• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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_coredump_service.h"
17 
18 #include <fstream>
19 #include <sys/wait.h>
20 #include <sys/socket.h>
21 #include <sys/syscall.h>
22 #include "dfx_define.h"
23 #include "dfx_log.h"
24 #include "dfx_trace.h"
25 #include "dfx_util.h"
26 #include "fault_logger_daemon.h"
27 #include "faultloggerd_socket.h"
28 #include "fault_common_util.h"
29 #include "procinfo.h"
30 #include "proc_util.h"
31 #include "string_printf.h"
32 
33 namespace OHOS {
34 namespace HiviewDFX {
35 
36 namespace {
37 constexpr const char* const FAULTLOGGERD_SERVICE_TAG = "FAULT_COREDUMP_SERVICE";
CheckCoredumpUID(uint32_t callerUid)38 bool CheckCoredumpUID(uint32_t callerUid)
39 {
40     const uint32_t whitelist[] = {
41         0, // rootUid
42         1202, // dumpcatcherUid
43         7005, // taskManagerUid
44     };
45     if (std::find(std::begin(whitelist), std::end(whitelist), callerUid) == std::end(whitelist)) {
46         DFXLOGW("%{public}s :: CheckCoredumpUID :: Coredump Uid(%{public}d) is unexpectly.",
47                 FAULTLOGGERD_SERVICE_TAG, callerUid);
48         return false;
49     }
50     return true;
51 }
52 
SendCancelSignal(int32_t processDumpPid)53 int32_t SendCancelSignal(int32_t processDumpPid)
54 {
55     siginfo_t si{0};
56     si.si_signo = SIGTERM;
57     si.si_errno = 0;
58     si.si_code = SIGLEAK_STACK_COREDUMP;
59 #ifndef FAULTLOGGERD_TEST
60     if (syscall(SYS_rt_sigqueueinfo, processDumpPid, si.si_signo, &si) != 0) {
61         DFXLOGE("%{public}s :: Failed to SYS_rt_sigqueueinfo signal(%{public}d), errno(%{public}d).",
62             FAULTLOGGERD_SERVICE_TAG, si.si_signo, errno);
63         return ResponseCode::CORE_DUMP_NOPROC;
64     }
65 #endif
66     return ResponseCode::REQUEST_SUCCESS;
67 }
68 
SendMsgToCoredumpClient(int32_t targetPid,int32_t responseCode,const std::string & fileName,RecorderProcessMap & coredumpRecorder)69 bool SendMsgToCoredumpClient(int32_t targetPid, int32_t responseCode, const std::string& fileName,
70     RecorderProcessMap& coredumpRecorder)
71 {
72     int32_t savedConnectionFd = -1;
73 
74     coredumpRecorder.GetCoredumpSocketId(targetPid, savedConnectionFd);
75     if (savedConnectionFd < 0) {
76         DFXLOGE("%{public}s :: Client sockFd has been crashed.", __func__);
77         return false;
78     }
79 
80     CoreDumpResult coredumpResult;
81     if (strncpy_s(coredumpResult.fileName, sizeof(coredumpResult.fileName),
82         fileName.c_str(), fileName.size()) != 0) {
83         DFXLOGE("%{public}s :: strncpy failed.", __func__);
84         return false;
85     }
86     coredumpResult.retCode = responseCode;
87 
88     if (SendMsgToSocket(savedConnectionFd, &coredumpResult, sizeof(coredumpResult))) {
89         return true;
90     }
91     return false;
92 }
93 
HandleCoredumpAndCleanup(int32_t targetPid,int32_t retCode,const std::string & fileName,RecorderProcessMap & coredumpRecorder)94 bool HandleCoredumpAndCleanup(int32_t targetPid, int32_t retCode, const std::string& fileName,
95     RecorderProcessMap& coredumpRecorder)
96 {
97     if (!SendMsgToCoredumpClient(targetPid, retCode, fileName, coredumpRecorder)) {
98         DFXLOGE("Send message to client failed, %{public}s %{public}d", __func__, __LINE__);
99     }
100 
101     if (!coredumpRecorder.ClearTargetPid(targetPid)) {
102         DFXLOGE("Remove targetpid %{public}d failed, %{public}s %{public}d", targetPid, __func__, __LINE__);
103         return false;
104     }
105     return true;
106 }
107 }
108 
GetInstance()109 RecorderProcessMap& RecorderProcessMap::GetInstance()
110 {
111     static RecorderProcessMap instance;
112     return instance;
113 }
114 
IsEmpty()115 bool RecorderProcessMap::IsEmpty()
116 {
117     return coredumpProcessMap.empty();
118 }
119 
HasTargetPid(int32_t targetPid)120 bool RecorderProcessMap::HasTargetPid(int32_t targetPid)
121 {
122     return coredumpProcessMap.find(targetPid) != coredumpProcessMap.end();
123 }
124 
AddProcessMap(int32_t targetPid,const CoredumpProcessInfo & processInfo)125 void RecorderProcessMap::AddProcessMap(int32_t targetPid, const CoredumpProcessInfo& processInfo)
126 {
127     coredumpProcessMap.emplace(
128         targetPid,
129         CoredumpProcessInfo(processInfo.processDumpPid, processInfo.coredumpSocketId,
130                             processInfo.endTime, processInfo.cancelFlag)
131     );
132 }
133 
ClearTargetPid(int32_t targetPid)134 bool RecorderProcessMap::ClearTargetPid(int32_t targetPid)
135 {
136     auto it = coredumpProcessMap.find(targetPid);
137     if (it != coredumpProcessMap.end()) {
138         close(it->second.coredumpSocketId);
139         coredumpProcessMap.erase(it);
140         return true;
141     }
142     return false;
143 }
144 
SetCancelFlag(int32_t targetPid,bool flag)145 bool RecorderProcessMap::SetCancelFlag(int32_t targetPid, bool flag)
146 {
147     auto it = coredumpProcessMap.find(targetPid);
148     if (it != coredumpProcessMap.end()) {
149         it->second.cancelFlag = flag;
150         return true;
151     }
152     return false;
153 }
154 
SetProcessDumpPid(int32_t targetPid,int32_t processDumpPid)155 bool RecorderProcessMap::SetProcessDumpPid(int32_t targetPid, int32_t processDumpPid)
156 {
157     auto it = coredumpProcessMap.find(targetPid);
158     if (it != coredumpProcessMap.end()) {
159         it->second.processDumpPid = processDumpPid;
160         return true;
161     }
162     return false;
163 }
164 
GetCoredumpSocketId(int32_t targetPid,int32_t & coredumpSocketId)165 bool RecorderProcessMap::GetCoredumpSocketId(int32_t targetPid, int32_t& coredumpSocketId)
166 {
167     auto it = coredumpProcessMap.find(targetPid);
168     if (it != coredumpProcessMap.end()) {
169         coredumpSocketId = it->second.coredumpSocketId;
170         return true;
171     }
172     return false;
173 }
174 
GetProcessDumpPid(int32_t targetPid,int32_t & processDumpPid)175 bool RecorderProcessMap::GetProcessDumpPid(int32_t targetPid, int32_t& processDumpPid)
176 {
177     auto it = coredumpProcessMap.find(targetPid);
178     if (it != coredumpProcessMap.end()) {
179         processDumpPid = it->second.processDumpPid;
180         return true;
181     }
182     return false;
183 }
184 
GetCancelFlag(int32_t targetPid,bool & flag)185 bool RecorderProcessMap::GetCancelFlag(int32_t targetPid, bool& flag)
186 {
187     auto it = coredumpProcessMap.find(targetPid);
188     if (it != coredumpProcessMap.end()) {
189         flag = it->second.cancelFlag;
190         return true;
191     }
192     return false;
193 }
194 
195 #ifndef is_ohos_lite
HandleProcessDumpPid(int32_t targetPid,int32_t processDumpPid)196 bool CoredumpStatusService::HandleProcessDumpPid(int32_t targetPid, int32_t processDumpPid)
197 {
198     if (processDumpPid <= 0 || targetPid <= 0) {
199         return false;
200     }
201 
202     if (!coredumpRecorder.HasTargetPid(targetPid)) {
203         return false;
204     }
205 
206     bool cancelFlag = false;
207     if (coredumpRecorder.GetCancelFlag(targetPid, cancelFlag)) {
208         if (!cancelFlag) {
209             coredumpRecorder.SetProcessDumpPid(targetPid, processDumpPid);
210             return true;
211         }
212     }
213 
214     if (SendCancelSignal(processDumpPid) != ResponseCode::REQUEST_SUCCESS) {
215         return false;
216     }
217 
218     int32_t retCode = ResponseCode::CORE_DUMP_CANCEL;
219     std::string fileName = "";
220     HandleCoredumpAndCleanup(targetPid, retCode, fileName, coredumpRecorder);
221     return true;
222 }
223 
OnRequest(const std::string & socketName,int32_t connectionFd,const CoreDumpStatusData & requestData)224 int32_t CoredumpStatusService::OnRequest(const std::string& socketName, int32_t connectionFd,
225     const CoreDumpStatusData& requestData)
226 {
227     DFX_TRACE_SCOPED("CoredumpStatusServiceOnRequest");
228     DFXLOGI("Receive coredump status request for pid:%{public}d, status:%{public}d", requestData.pid,
229             requestData.coredumpStatus);
230 
231     int32_t res = ResponseCode::REQUEST_SUCCESS;
232     if (requestData.coredumpStatus == CoreDumpStatus::CORE_DUMP_START) {
233         DFXLOGI("Processdump start %{public}s %{public}d", __func__, __LINE__);
234         int32_t processDumpPid = requestData.processDumpPid;
235 
236         if (!HandleProcessDumpPid(requestData.pid, processDumpPid)) {
237             DFXLOGE("Handle processDumpPid %{public}d failed", processDumpPid);
238             res = ResponseCode::ABNORMAL_SERVICE;
239             return res;
240         }
241     } else if (requestData.coredumpStatus == CoreDumpStatus::CORE_DUMP_END) {
242         DFXLOGI("Processdump finish %{public}s %{public}d", __func__, __LINE__);
243 
244         int32_t targetPid = requestData.pid;
245         char cfileName[256];
246         if (strncpy_s(cfileName, sizeof(cfileName), requestData.fileName, sizeof(requestData.fileName)) != 0) {
247             DFXLOGE("%{public}s :: strncpy failed.", __func__);
248             return ResponseCode::DEFAULT_ERROR_CODE;
249         }
250         int32_t retCode = requestData.retCode;
251         HandleCoredumpAndCleanup(targetPid, retCode, cfileName, coredumpRecorder);
252     }
253 
254     SendMsgToSocket(connectionFd, &res, sizeof(res));
255     return res;
256 }
257 
Filter(const std::string & socketName,const CoreDumpRequestData & requestData,uint32_t uid)258 int32_t CoredumpService::Filter(const std::string& socketName, const CoreDumpRequestData& requestData, uint32_t uid)
259 {
260     if (requestData.pid <= 0 || socketName != SERVER_SOCKET_NAME || !CheckCoredumpUID(uid)) {
261         DFXLOGE("%{public}s :: HandleCoreDumpRequest :: pid(%{public}d) or socketName(%{public}s) fail.",
262             FAULTLOGGERD_SERVICE_TAG, requestData.pid, socketName.c_str());
263         return ResponseCode::REQUEST_REJECT;
264     }
265     if (TempFileManager::CheckCrashFileRecord(requestData.pid)) {
266         DFXLOGW("%{public}s :: pid(%{public}d) has been crashed, break.",
267                 FAULTLOGGERD_SERVICE_TAG, requestData.pid);
268         return ResponseCode::CORE_PROCESS_CRASHED;
269     }
270     return ResponseCode::REQUEST_SUCCESS;
271 }
272 
DoCoredumpRequest(const std::string & socketName,int32_t connectionFd,const CoreDumpRequestData & requestData)273 int32_t CoredumpService::DoCoredumpRequest(const std::string& socketName, int32_t connectionFd,
274     const CoreDumpRequestData& requestData)
275 {
276     struct ucred creds;
277     if (!FaultCommonUtil::GetUcredByPeerCred(creds, connectionFd)) {
278         DFXLOGE("Core dump pid(%{public}d) request failed to get cred.", requestData.pid);
279         return ResponseCode::REQUEST_REJECT;
280     }
281     int32_t responseCode = Filter(socketName, requestData, creds.uid);
282     if (responseCode != ResponseCode::REQUEST_SUCCESS) {
283         return responseCode;
284     }
285 
286     int32_t res = ResponseCode::REQUEST_SUCCESS;
287     int32_t coredumpSocketId = dup(connectionFd);
288     int32_t targetPid = requestData.pid;
289     if (coredumpRecorder.HasTargetPid(targetPid)) {
290         DFXLOGE("%{public}d is generating coredump, please do not repeat dump!", targetPid);
291         res = ResponseCode::CORE_DUMP_REPEAT;
292         SendMsgToSocket(coredumpSocketId, &res, sizeof(res));
293         close(coredumpSocketId);
294         return res;
295     }
296 
297     siginfo_t si{0};
298     si.si_signo = SIGLEAK_STACK;
299     si.si_errno = 0;
300     si.si_code = SIGLEAK_STACK_COREDUMP;
301     si.si_pid = static_cast<int32_t>(creds.pid);
302     if (auto ret = FaultCommonUtil::SendSignalToProcess(targetPid, si); ret != ResponseCode::REQUEST_SUCCESS) {
303         SendMsgToSocket(coredumpSocketId, &ret, sizeof(ret));
304         close(coredumpSocketId);
305         return ret;
306     }
307 
308     int32_t processDumpPid = -1;
309     uint64_t endTime = requestData.endTime;
310     coredumpRecorder.AddProcessMap(targetPid, {processDumpPid, coredumpSocketId, endTime, false});
311     SendMsgToSocket(coredumpSocketId, &res, sizeof(res));
312 
313     auto removeTask = [targetPid, coredumpRecorderPtr = &coredumpRecorder]() {
314         coredumpRecorderPtr->ClearTargetPid(targetPid);
315     };
316 
317     constexpr int32_t minDelays = 60; // 60 : 60s
318     int32_t delays = static_cast<int32_t>((endTime - GetAbsTimeMilliSeconds()) / 1000);
319     delays = std::min(delays, minDelays);
320     StartDelayTask(removeTask, delays);
321     return res;
322 }
323 
CancelCoredumpRequest(int32_t connectionFd,const CoreDumpRequestData & requestData)324 int32_t CoredumpService::CancelCoredumpRequest(int32_t connectionFd, const CoreDumpRequestData& requestData)
325 {
326     int32_t targetPid = requestData.pid;
327     int32_t res = ResponseCode::REQUEST_SUCCESS;
328     if (!coredumpRecorder.HasTargetPid(targetPid)) {
329         DFXLOGE("No need to cancel!");
330         res = ResponseCode::DEFAULT_ERROR_CODE;
331         SendMsgToSocket(connectionFd, &res, sizeof(res));
332         return res;
333     }
334 
335     int32_t processDumpPid = -1;
336     if (coredumpRecorder.GetProcessDumpPid(targetPid, processDumpPid)) {
337         if (processDumpPid == -1) {
338             DFXLOGE("Can not get processdump pid!");
339             coredumpRecorder.SetCancelFlag(targetPid, true);
340         } else {
341             DFXLOGI("processDumpPid get %{public}d %{public}d", processDumpPid, __LINE__);
342 
343             res = SendCancelSignal(processDumpPid);
344             if (res != ResponseCode::REQUEST_SUCCESS) {
345                 return res;
346             }
347             int32_t retCode = ResponseCode::CORE_DUMP_CANCEL;
348             std::string fileName = "";
349             HandleCoredumpAndCleanup(targetPid, retCode, fileName, coredumpRecorder);
350         }
351     }
352 
353     SendMsgToSocket(connectionFd, &res, sizeof(res));
354     return res;
355 }
356 
OnRequest(const std::string & socketName,int32_t connectionFd,const CoreDumpRequestData & requestData)357 int32_t CoredumpService::OnRequest(const std::string& socketName, int32_t connectionFd,
358     const CoreDumpRequestData& requestData)
359 {
360     DFX_TRACE_SCOPED("CoredumpServiceOnRequest");
361     DFXLOGI("Receive coredump request for pid:%{public}d, action:%{public}d.", requestData.pid,
362             requestData.coredumpAction);
363 
364     int32_t res = ResponseCode::REQUEST_SUCCESS;
365     if (requestData.coredumpAction == CoreDumpAction::DO_CORE_DUMP) {
366         DFXLOGI("Do coredump %{public}s %{public}d", __func__, __LINE__);
367         res = DoCoredumpRequest(socketName, connectionFd, requestData);
368     } else if (requestData.coredumpAction == CoreDumpAction::CANCEL_CORE_DUMP) {
369         DFXLOGI("Cancel coredump %{public}s %{public}d", __func__, __LINE__);
370         res = CancelCoredumpRequest(connectionFd, requestData);
371     }
372     return res;
373 }
374 
StartDelayTask(std::function<void ()> workFunc,int32_t delayTime)375 void CoredumpService::StartDelayTask(std::function<void()> workFunc, int32_t delayTime)
376 {
377     auto delayTask = DelayTask::CreateInstance(workFunc, delayTime);
378     FaultLoggerDaemon::GetEpollManager(EpollManagerType::MAIN_SERVER).AddListener(std::move(delayTask));
379 }
380 #endif
381 }
382 }