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 "dfx_signalhandler_exception.h"
17 
18 #include <stdio.h>
19 #include <sys/syscall.h>
20 #include <sys/socket.h>
21 #include <sys/time.h>
22 #include <sys/un.h>
23 #include <unistd.h>
24 
25 #include "dfx_define.h"
26 #include "dfx_exception.h"
27 #include "dfx_socket_request.h"
28 #include "errno.h"
29 #include "string.h"
30 
31 #ifndef DFX_SIGNAL_LIBC
32 #include "dfx_log.h"
33 #else
34 #include "musl_log.h"
35 #endif
36 
37 #ifdef LOG_DOMAIN
38 #undef LOG_DOMAIN
39 #define LOG_DOMAIN 0xD002D11
40 #endif
41 
42 #ifdef LOG_TAG
43 #undef LOG_TAG
44 #define LOG_TAG "DfxSignalHandlerException"
45 #endif
46 
47 static const int TIME_OUT = 2;       /* seconds */
48 static const char FAULTLOGGERD_SOCKET_NAME[] = "/dev/unix/socket/faultloggerd.server";
49 
ConnectSocket(const char * path,const int timeout)50 static int ConnectSocket(const char* path, const int timeout)
51 {
52     int fd = -1;
53     if ((fd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) {
54         DFXLOG_ERROR("Failed to create a socket, errno(%d).", errno);
55         return -1;
56     }
57 
58     do {
59         if (timeout > 0) {
60             struct timeval timev = {
61                 timeout,
62                 0
63             };
64             void* pTimev = &timev;
65             if (OHOS_TEMP_FAILURE_RETRY(setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,
66                 (const void*)(pTimev), sizeof(timev))) != 0) {
67                 DFXLOG_ERROR("setsockopt SO_RCVTIMEO error, errno(%d).", errno);
68                 syscall(SYS_close, fd);
69                 fd = -1;
70                 break;
71             }
72         }
73         struct sockaddr_un server;
74         (void)memset(&server, 0, sizeof(server));
75         server.sun_family = AF_LOCAL;
76         (void)strncpy(server.sun_path, path, sizeof(server.sun_path) - 1);
77         int len = sizeof(server.sun_family) + strlen(server.sun_path);
78         int connected = OHOS_TEMP_FAILURE_RETRY(connect(fd, (struct sockaddr*)(&server), len));
79         if (connected < 0) {
80             DFXLOG_ERROR("Failed to connect to faultloggerd socket, errno = %d.", errno);
81             syscall(SYS_close, fd);
82             fd = -1;
83             break;
84         }
85     } while (false);
86     return fd;
87 }
88 
CheckReadResp(int fd)89 static bool CheckReadResp(int fd)
90 {
91     char controlBuffer[MAX_FUNC_NAME_LEN] = {0};
92     ssize_t nread = OHOS_TEMP_FAILURE_RETRY(read(fd, controlBuffer, sizeof(controlBuffer) - 1));
93     if (nread != (ssize_t)(strlen(FAULTLOGGER_DAEMON_RESP))) {
94         DFXLOG_ERROR("Failed to read expected length, nread: %zd, errno(%d).", nread, errno);
95         return false;
96     }
97     return true;
98 }
99 
ReportException(struct CrashDumpException exception)100 int ReportException(struct CrashDumpException exception)
101 {
102     struct FaultLoggerdRequest request;
103     (void)memset(&request, 0, sizeof(struct FaultLoggerdRequest));
104     request.clientType = (int32_t)REPORT_EXCEPTION_CLIENT;
105     request.pid = exception.pid;
106     request.uid = (uint32_t)(exception.uid);
107     int ret = -1;
108     int fd = ConnectSocket(FAULTLOGGERD_SOCKET_NAME, TIME_OUT); // connect timeout
109     if (fd == -1) {
110         DFXLOG_ERROR("Failed to connect socket.");
111         return ret;
112     }
113     do {
114         if (OHOS_TEMP_FAILURE_RETRY(write(fd, &request, sizeof(request))) != (long)sizeof(request)) {
115             DFXLOG_ERROR("Failed to write request message to socket, errno(%d).", errno);
116             break;
117         }
118 
119         if (!CheckReadResp(fd)) {
120             DFXLOG_ERROR("Failed to receive socket responces.");
121             break;
122         }
123 
124         if (OHOS_TEMP_FAILURE_RETRY(write(fd, &exception,
125             sizeof(exception))) != (long)sizeof(exception)) {
126             DFXLOG_ERROR("Failed to write exception message to socket, errno(%d).", errno);
127             break;
128         }
129 
130         ret = 0;
131     } while (false);
132     syscall(SYS_close, fd);
133     return ret;
134 }