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