1 /*
2  * Copyright (c) 2021-2023 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 "faultloggerd_socket.h"
17 
18 #include <cstddef>
19 #include <cstdio>
20 #include <securec.h>
21 #include <string>
22 #include <unistd.h>
23 
24 #include <sys/socket.h>
25 #include <sys/stat.h>
26 #include <sys/time.h>
27 #include <sys/un.h>
28 
29 #include "dfx_define.h"
30 #include "dfx_log.h"
31 #include "init_socket.h"
32 
StartConnect(int & sockfd,const char * path,const int timeout)33 bool StartConnect(int& sockfd, const char* path, const int timeout)
34 {
35     bool ret = false;
36     if ((sockfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) {
37         DFXLOG_ERROR("%s :: Failed to socket, errno(%d)", __func__, errno);
38         return ret;
39     }
40 
41     do {
42         if (timeout > 0) {
43             struct timeval timev = {
44                 timeout,
45                 0
46             };
47             void* pTimev = &timev;
48             if (OHOS_TEMP_FAILURE_RETRY(setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, \
49                 static_cast<const char*>(pTimev), sizeof(timev))) != 0) {
50                     DFXLOG_ERROR("setsockopt(%d) SO_RCVTIMEO error, errno(%d).", sockfd, errno);
51             }
52             if (OHOS_TEMP_FAILURE_RETRY(setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, \
53                 static_cast<const char*>(pTimev), sizeof(timev))) != 0) {
54                     DFXLOG_ERROR("setsockopt(%d) SO_SNDTIMEO error, errno(%d).", sockfd, errno);
55             }
56         }
57 
58         std::string fullPath = std::string(FAULTLOGGERD_SOCK_BASE_PATH) + std::string(path);
59         struct sockaddr_un server;
60         (void)memset_s(&server, sizeof(server), 0, sizeof(server));
61         server.sun_family = AF_LOCAL;
62         errno_t err = strncpy_s(server.sun_path, sizeof(server.sun_path), fullPath.c_str(),
63             sizeof(server.sun_path) - 1);
64         if (err != EOK) {
65             DFXLOG_ERROR("%s :: strncpy failed, err = %d.", __func__, (int)err);
66             break;
67         }
68 
69         int len = static_cast<int>(offsetof(struct sockaddr_un, sun_path) + strlen(server.sun_path) + 1);
70         int connected = OHOS_TEMP_FAILURE_RETRY(connect(sockfd, reinterpret_cast<struct sockaddr *>(&server), len));
71         if (connected < 0) {
72             DFXLOG_ERROR("%s :: connect failed, errno = %d.", __func__, errno);
73             break;
74         }
75 
76         ret = true;
77     } while (false);
78 
79     if (!ret) {
80         close(sockfd);
81     }
82     return ret;
83 }
84 
GetServerSocket(int & sockfd,const char * name)85 static bool GetServerSocket(int& sockfd, const char* name)
86 {
87     sockfd = OHOS_TEMP_FAILURE_RETRY(socket(AF_LOCAL, SOCK_STREAM, 0));
88     if (sockfd < 0) {
89         DFXLOG_ERROR("%s :: Failed to create socket, errno(%d)", __func__, errno);
90         return false;
91     }
92 
93     std::string path = std::string(FAULTLOGGERD_SOCK_BASE_PATH) + std::string(name);
94     struct sockaddr_un server;
95     (void)memset_s(&server, sizeof(server), 0, sizeof(server));
96     server.sun_family = AF_LOCAL;
97     if (strncpy_s(server.sun_path, sizeof(server.sun_path), path.c_str(), sizeof(server.sun_path) - 1) != 0) {
98         DFXLOG_ERROR("%s :: strncpy failed.", __func__);
99         return false;
100     }
101 
102     chmod(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IWOTH);
103     unlink(path.c_str());
104 
105     int optval = 1;
106     int ret = OHOS_TEMP_FAILURE_RETRY(setsockopt(sockfd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)));
107     if (ret < 0) {
108         DFXLOG_ERROR("%s :: Failed to set socket option, errno(%d)", __func__, errno);
109         return false;
110     }
111 
112     if (bind(sockfd, reinterpret_cast<struct sockaddr *>(&server),
113         offsetof(struct sockaddr_un, sun_path) + strlen(server.sun_path)) < 0) {
114         DFXLOG_ERROR("%s :: Failed to bind socket, errno(%d)", __func__, errno);
115         return false;
116     }
117 
118     return true;
119 }
120 
StartListen(int & sockfd,const char * name,const int listenCnt)121 bool StartListen(int& sockfd, const char* name, const int listenCnt)
122 {
123     if (name == nullptr) {
124         return false;
125     }
126     sockfd = GetControlSocket(name);
127     if (sockfd < 0) {
128         DFXLOG_WARN("%s :: Failed to get socket fd by cfg", __func__);
129         if (GetServerSocket(sockfd, name) == false) {
130             DFXLOG_ERROR("%s :: Failed to get socket fd by path", __func__);
131             return false;
132         }
133     }
134 
135     if (listen(sockfd, listenCnt) < 0) {
136         DFXLOG_ERROR("%s :: Failed to listen socket, errno(%d)", __func__, errno);
137         close(sockfd);
138         sockfd = -1;
139         return false;
140     }
141 
142     DFXLOG_INFO("%s :: success to listen socket", __func__);
143     return true;
144 }
145 
RecvMsgFromSocket(int sockfd,unsigned char * data,size_t & len)146 static bool RecvMsgFromSocket(int sockfd, unsigned char* data, size_t& len)
147 {
148     bool ret = false;
149     if ((sockfd < 0) || (data == nullptr)) {
150         return ret;
151     }
152 
153     do {
154         struct msghdr msgh;
155         (void)memset_s(&msgh, sizeof(msgh), 0, sizeof(msgh));
156         char msgBuffer[SOCKET_BUFFER_SIZE] = { 0 };
157         struct iovec iov = {
158             .iov_base = msgBuffer,
159             .iov_len = sizeof(msgBuffer)
160         };
161         msgh.msg_iov = &iov;
162         msgh.msg_iovlen = 1;
163 
164         char ctlBuffer[SOCKET_BUFFER_SIZE] = { 0 };
165         msgh.msg_control = ctlBuffer;
166         msgh.msg_controllen = sizeof(ctlBuffer);
167 
168         if (OHOS_TEMP_FAILURE_RETRY(recvmsg(sockfd, &msgh, 0)) < 0) {
169             DFXLOG_ERROR("%s :: Failed to recv message, errno(%d)\n", __func__, errno);
170             break;
171         }
172 
173         struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msgh);
174         if (cmsg == nullptr) {
175             DFXLOG_ERROR("%s :: Invalid message\n", __func__);
176             break;
177         }
178 
179         len = cmsg->cmsg_len - sizeof(struct cmsghdr);
180         if (memcpy_s(data, len, CMSG_DATA(cmsg), len) != 0) {
181             DFXLOG_ERROR("%s :: memcpy error\n", __func__);
182             break;
183         }
184 
185         ret = true;
186     } while (false);
187     return ret;
188 }
189 
RecvMsgCredFromSocket(int sockfd,struct ucred * pucred)190 bool RecvMsgCredFromSocket(int sockfd, struct ucred* pucred)
191 {
192     bool ret = false;
193     if ((sockfd < 0) || (pucred == nullptr)) {
194         return ret;
195     }
196 
197     do {
198         struct msghdr msgh;
199         (void)memset_s(&msgh, sizeof(msgh), 0, sizeof(msgh));
200         union {
201             char buf[CMSG_SPACE(sizeof(struct ucred))];
202 
203             /* Space large enough to hold a 'ucred' structure */
204             struct cmsghdr align;
205         } controlMsg;
206 
207         msgh.msg_name = nullptr;
208         msgh.msg_namelen = 0;
209 
210         int data;
211         struct iovec iov = {
212             .iov_base = &data,
213             .iov_len = sizeof(data)
214         };
215         msgh.msg_iov = &iov;
216         msgh.msg_iovlen = 1;
217 
218         msgh.msg_control = controlMsg.buf;
219         msgh.msg_controllen = sizeof(controlMsg.buf);
220 
221         if (OHOS_TEMP_FAILURE_RETRY(recvmsg(sockfd, &msgh, 0)) < 0) {
222             DFXLOG_ERROR("%s :: Failed to recv message, errno(%d)\n", __func__, errno);
223             break;
224         }
225 
226         struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msgh);
227         if (cmsg == nullptr) {
228             DFXLOG_ERROR("%s :: Invalid message\n", __func__);
229             break;
230         }
231 
232         if (memcpy_s(pucred, sizeof(struct ucred), CMSG_DATA(cmsg), sizeof(struct ucred)) != 0) {
233             DFXLOG_ERROR("%s :: memcpy error\n", __func__);
234             break;
235         }
236 
237         ret = true;
238     } while (false);
239     return ret;
240 }
241 
SendMsgIovToSocket(int sockfd,void * iovBase,const int iovLen)242 bool SendMsgIovToSocket(int sockfd, void *iovBase, const int iovLen)
243 {
244     if ((sockfd < 0) || (iovBase == nullptr) || (iovLen == 0)) {
245         return false;
246     }
247 
248     struct msghdr msgh;
249     (void)memset_s(&msgh, sizeof(msgh), 0, sizeof(msgh));
250     msgh.msg_name = nullptr;
251     msgh.msg_namelen = 0;
252 
253     struct iovec iov;
254     iov.iov_base = iovBase;
255     iov.iov_len = iovLen;
256     msgh.msg_iov = &iov;
257     msgh.msg_iovlen = 1;
258 
259     msgh.msg_control = nullptr;
260     msgh.msg_controllen = 0;
261 
262     if (OHOS_TEMP_FAILURE_RETRY(sendmsg(sockfd, &msgh, 0)) < 0) {
263         DFXLOG_ERROR("%s :: Failed to send message, errno(%d).", __func__, errno);
264         return false;
265     }
266     return true;
267 }
268 
SendMsgCtlToSocket(int sockfd,const void * cmsg,const int cmsgLen)269 static bool SendMsgCtlToSocket(int sockfd, const void *cmsg, const int cmsgLen)
270 {
271     if ((sockfd < 0) || (cmsg == nullptr) || (cmsgLen == 0)) {
272         return false;
273     }
274 
275     struct msghdr msgh;
276     (void)memset_s(&msgh, sizeof(msgh), 0, sizeof(msgh));
277     char iovBase[] = "";
278     struct iovec iov = {
279         .iov_base = reinterpret_cast<void *>(iovBase),
280         .iov_len = 1
281     };
282     msgh.msg_iov = &iov;
283     msgh.msg_iovlen = 1;
284 
285     int controlBufLen = CMSG_SPACE(static_cast<unsigned int>(cmsgLen));
286     char controlBuf[controlBufLen];
287     msgh.msg_control = controlBuf;
288     msgh.msg_controllen = sizeof(controlBuf);
289 
290     struct cmsghdr *cmsgh = CMSG_FIRSTHDR(&msgh);
291     if (cmsgh != nullptr) {
292         cmsgh->cmsg_level = SOL_SOCKET;
293         cmsgh->cmsg_type = SCM_RIGHTS;
294         cmsgh->cmsg_len = CMSG_LEN(cmsgLen);
295     }
296     if (memcpy_s(CMSG_DATA(cmsgh), cmsgLen, cmsg, cmsgLen) != 0) {
297         DFXLOG_ERROR("%s :: memcpy error\n", __func__);
298     }
299 
300     if (OHOS_TEMP_FAILURE_RETRY(sendmsg(sockfd, &msgh, 0)) < 0) {
301         DFXLOG_ERROR("%s :: Failed to send message, errno(%d)", __func__, errno);
302         return false;
303     }
304     return true;
305 }
306 
SendFileDescriptorToSocket(int sockfd,int fd)307 bool SendFileDescriptorToSocket(int sockfd, int fd)
308 {
309     return SendMsgCtlToSocket(sockfd, reinterpret_cast<void *>(&fd), sizeof(fd));
310 }
311 
ReadFileDescriptorFromSocket(int sockfd)312 int ReadFileDescriptorFromSocket(int sockfd)
313 {
314     size_t len = sizeof(int);
315     unsigned char data[len + 1];
316     if (!RecvMsgFromSocket(sockfd, data, len)) {
317         DFXLOG_ERROR("%s :: Failed to recv message", __func__);
318         return -1;
319     }
320 
321     if (len != sizeof(int)) {
322         DFXLOG_ERROR("%s :: data is null or len is %zu", __func__, len);
323         return -1;
324     }
325     int fd = *(reinterpret_cast<int *>(data));
326     DFXLOG_DEBUG("%s :: fd: %d", __func__, fd);
327     return fd;
328 }