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 }