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 "appspawn_client.h"
17
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <pthread.h>
21 #include <string.h>
22 #include <unistd.h>
23
24 #include <linux/in.h>
25 #include <linux/socket.h>
26 #include <linux/tcp.h>
27 #include <sys/socket.h>
28 #include <sys/time.h>
29 #include <sys/types.h>
30 #include <sys/un.h>
31
32 #include "appspawn_mount_permission.h"
33 #include "appspawn_hook.h"
34 #include "appspawn_utils.h"
35 #include "parameter.h"
36 #include "securec.h"
37
38 static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
39 static AppSpawnReqMsgMgr *g_clientInstance[CLIENT_MAX] = {NULL};
40
GetDefaultTimeout(uint32_t def)41 static uint32_t GetDefaultTimeout(uint32_t def)
42 {
43 uint32_t value = def;
44 char data[32] = {}; // 32 length
45 int ret = GetParameter("persist.appspawn.reqMgr.timeout", "0", data, sizeof(data));
46 if (ret > 0 && strcmp(data, "0") != 0) {
47 errno = 0;
48 value = (uint32_t)atoi(data);
49 return (errno != 0) ? def : value;
50 }
51 return value;
52 }
53
InitClientInstance(AppSpawnClientType type)54 static int InitClientInstance(AppSpawnClientType type)
55 {
56 pthread_mutex_lock(&g_mutex);
57 if (g_clientInstance[type] != NULL) {
58 pthread_mutex_unlock(&g_mutex);
59 return 0;
60 }
61 AppSpawnReqMsgMgr *clientInstance = malloc(sizeof(AppSpawnReqMsgMgr) + RECV_BLOCK_LEN);
62 if (clientInstance == NULL) {
63 pthread_mutex_unlock(&g_mutex);
64 return APPSPAWN_SYSTEM_ERROR;
65 }
66 // init
67 clientInstance->type = type;
68 clientInstance->msgNextId = 1;
69 clientInstance->timeout = GetDefaultTimeout(TIMEOUT_DEF);
70 clientInstance->maxRetryCount = MAX_RETRY_SEND_COUNT;
71 clientInstance->socketId = -1;
72 pthread_mutex_init(&clientInstance->mutex, NULL);
73 // init recvBlock
74 OH_ListInit(&clientInstance->recvBlock.node);
75 clientInstance->recvBlock.blockSize = RECV_BLOCK_LEN;
76 clientInstance->recvBlock.currentIndex = 0;
77 g_clientInstance[type] = clientInstance;
78 pthread_mutex_unlock(&g_mutex);
79 return 0;
80 }
81
CloseClientSocket(int socketId)82 APPSPAWN_STATIC void CloseClientSocket(int socketId)
83 {
84 APPSPAWN_LOGV("Closed socket with fd %{public}d", socketId);
85 if (socketId >= 0) {
86 int flag = 0;
87 setsockopt(socketId, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int));
88 close(socketId);
89 }
90 }
91
CreateClientSocket(uint32_t type,uint32_t timeout)92 APPSPAWN_STATIC int CreateClientSocket(uint32_t type, uint32_t timeout)
93 {
94 const char *socketName;
95
96 switch (type) {
97 case CLIENT_FOR_APPSPAWN:
98 socketName = APPSPAWN_SOCKET_NAME;
99 break;
100 case CLIENT_FOR_CJAPPSPAWN:
101 socketName = CJAPPSPAWN_SOCKET_NAME;
102 break;
103 case CLIENT_FOR_NATIVESPAWN:
104 socketName = NATIVESPAWN_SOCKET_NAME;
105 break;
106 default:
107 socketName = NWEBSPAWN_SOCKET_NAME;
108 break;
109 }
110
111 int socketFd = socket(AF_UNIX, SOCK_STREAM, 0); // SOCK_SEQPACKET
112 APPSPAWN_CHECK(socketFd >= 0, return -1,
113 "Socket socket fd: %{public}s error: %{public}d", socketName, errno);
114 int ret = 0;
115 do {
116 int flag = 1;
117 ret = setsockopt(socketFd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int));
118 flag = 1;
119 ret = setsockopt(socketFd, SOL_SOCKET, SO_PASSCRED, &flag, sizeof(flag));
120 APPSPAWN_CHECK(ret == 0, break, "Set opt SO_PASSCRED name: %{public}s error: %{public}d", socketName, errno);
121
122 struct timeval timeoutVal = {timeout, 0};
123 ret = setsockopt(socketFd, SOL_SOCKET, SO_SNDTIMEO, &timeoutVal, sizeof(timeoutVal));
124 APPSPAWN_CHECK(ret == 0, break, "Set opt SO_SNDTIMEO name: %{public}s error: %{public}d", socketName, errno);
125 ret = setsockopt(socketFd, SOL_SOCKET, SO_RCVTIMEO, &timeoutVal, sizeof(timeoutVal));
126 APPSPAWN_CHECK(ret == 0, break, "Set opt SO_RCVTIMEO name: %{public}s error: %{public}d", socketName, errno);
127
128 ret = APPSPAWN_SYSTEM_ERROR;
129 struct sockaddr_un addr;
130 socklen_t pathSize = sizeof(addr.sun_path);
131 int pathLen = snprintf_s(addr.sun_path, pathSize, (pathSize - 1), "%s%s", APPSPAWN_SOCKET_DIR, socketName);
132 APPSPAWN_CHECK(pathLen > 0, break, "Format path %{public}s error: %{public}d", socketName, errno);
133 addr.sun_family = AF_LOCAL;
134 socklen_t socketAddrLen = (socklen_t)(offsetof(struct sockaddr_un, sun_path) + (socklen_t)pathLen + 1);
135 ret = connect(socketFd, (struct sockaddr *)(&addr), socketAddrLen);
136 APPSPAWN_CHECK(ret == 0, break,
137 "Failed to connect %{public}s error: %{public}d", addr.sun_path, errno);
138 APPSPAWN_LOGI("Create socket success %{public}s socketFd: %{public}d", addr.sun_path, socketFd);
139 return socketFd;
140 } while (0);
141 CloseClientSocket(socketFd);
142 return -1;
143 }
144
UpdateSocketTimeout(uint32_t timeout,int socketFd)145 APPSPAWN_STATIC int UpdateSocketTimeout(uint32_t timeout, int socketFd)
146 {
147 struct timeval timeoutVal = {timeout, 0};
148 int ret = setsockopt(socketFd, SOL_SOCKET, SO_SNDTIMEO, &timeoutVal, sizeof(timeoutVal));
149 APPSPAWN_CHECK(ret == 0, return ret, "Set opt SO_SNDTIMEO error: %{public}d", errno);
150 ret = setsockopt(socketFd, SOL_SOCKET, SO_RCVTIMEO, &timeoutVal, sizeof(timeoutVal));
151 APPSPAWN_CHECK(ret == 0, return ret, "Set opt SO_RCVTIMEO error: %{public}d", errno);
152 return ret;
153 }
154
ReadMessage(int socketFd,uint32_t sendMsgId,uint8_t * buf,int len,AppSpawnResult * result)155 static int ReadMessage(int socketFd, uint32_t sendMsgId, uint8_t *buf, int len, AppSpawnResult *result)
156 {
157 ssize_t rLen = TEMP_FAILURE_RETRY(read(socketFd, buf, len));
158 APPSPAWN_CHECK(rLen >= 0, return APPSPAWN_TIMEOUT,
159 "Read message from fd %{public}d rLen %{public}zd errno: %{public}d", socketFd, rLen, errno);
160 if ((size_t)rLen >= sizeof(AppSpawnResponseMsg)) {
161 AppSpawnResponseMsg *msg = (AppSpawnResponseMsg *)(buf);
162 APPSPAWN_CHECK_ONLY_LOG(sendMsgId == msg->msgHdr.msgId,
163 "Invalid msg recvd %{public}u %{public}u", sendMsgId, msg->msgHdr.msgId);
164 return memcpy_s(result, sizeof(AppSpawnResult), &msg->result, sizeof(msg->result));
165 }
166 return APPSPAWN_TIMEOUT;
167 }
168
WriteMessage(int socketFd,const uint8_t * buf,ssize_t len,int * fds,int * fdCount)169 static int WriteMessage(int socketFd, const uint8_t *buf, ssize_t len, int *fds, int *fdCount)
170 {
171 ssize_t written = 0;
172 ssize_t remain = len;
173 const uint8_t *offset = buf;
174 struct iovec iov = {
175 .iov_base = (void *) offset,
176 .iov_len = len,
177 };
178 struct msghdr msg = {
179 .msg_iov = &iov,
180 .msg_iovlen = 1,
181 };
182 char *ctrlBuffer = NULL;
183 if (fdCount != NULL && fds != NULL && *fdCount > 0) {
184 msg.msg_controllen = CMSG_SPACE(*fdCount * sizeof(int));
185 ctrlBuffer = (char *) malloc(msg.msg_controllen);
186 APPSPAWN_CHECK(ctrlBuffer != NULL, return -1,
187 "WriteMessage fail to alloc memory for msg_control %{public}d %{public}d", msg.msg_controllen, errno);
188 msg.msg_control = ctrlBuffer;
189 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
190 APPSPAWN_CHECK(cmsg != NULL, free(ctrlBuffer);
191 return -1, "WriteMessage fail to get CMSG_FIRSTHDR %{public}d", errno);
192 cmsg->cmsg_len = CMSG_LEN(*fdCount * sizeof(int));
193 cmsg->cmsg_type = SCM_RIGHTS;
194 cmsg->cmsg_level = SOL_SOCKET;
195 int ret = memcpy_s(CMSG_DATA(cmsg), cmsg->cmsg_len, fds, *fdCount * sizeof(int));
196 APPSPAWN_CHECK(ret == 0, free(ctrlBuffer);
197 return -1, "WriteMessage fail to memcpy_s fd %{public}d", errno);
198 APPSPAWN_LOGV("build fd info count %{public}d", *fdCount);
199 }
200 for (ssize_t wLen = 0; remain > 0; offset += wLen, remain -= wLen, written += wLen) {
201 errno = 0;
202 wLen = sendmsg(socketFd, &msg, MSG_NOSIGNAL);
203 APPSPAWN_LOGV("Write msg errno: %{public}d %{public}zd", errno, wLen);
204 APPSPAWN_CHECK((wLen > 0) || (errno == EINTR), free(ctrlBuffer);
205 return -errno,
206 "Failed to write message to fd %{public}d, wLen %{public}zd errno: %{public}d", socketFd, wLen, errno);
207 }
208 free(ctrlBuffer);
209 return written == len ? 0 : -EFAULT;
210 }
211
HandleMsgSend(AppSpawnReqMsgMgr * reqMgr,int socketId,AppSpawnReqMsgNode * reqNode)212 static int HandleMsgSend(AppSpawnReqMsgMgr *reqMgr, int socketId, AppSpawnReqMsgNode *reqNode)
213 {
214 APPSPAWN_LOGV("HandleMsgSend reqId: %{public}u msgId: %{public}d", reqNode->reqId, reqNode->msg->msgId);
215 ListNode *sendNode = reqNode->msgBlocks.next;
216 uint32_t currentIndex = 0;
217 bool sendFd = true;
218 while (sendNode != NULL && sendNode != &reqNode->msgBlocks) {
219 AppSpawnMsgBlock *sendBlock = (AppSpawnMsgBlock *)ListEntry(sendNode, AppSpawnMsgBlock, node);
220 int ret = WriteMessage(socketId, sendBlock->buffer, sendBlock->currentIndex,
221 sendFd ? reqNode->fds : NULL,
222 sendFd ? &reqNode->fdCount : NULL);
223 currentIndex += sendBlock->currentIndex;
224 APPSPAWN_LOGV("Write msg ret: %{public}d msgId: %{public}u %{public}u %{public}u",
225 ret, reqNode->msg->msgId, reqNode->msg->msgLen, currentIndex);
226 if (ret == 0) {
227 sendFd = false;
228 sendNode = sendNode->next;
229 continue;
230 }
231 APPSPAWN_LOGE("Send msg fail reqId: %{public}u msgId: %{public}d ret: %{public}d",
232 reqNode->reqId, reqNode->msg->msgId, ret);
233 return ret;
234 }
235 return 0;
236 }
237
TryCreateSocket(AppSpawnReqMsgMgr * reqMgr)238 static void TryCreateSocket(AppSpawnReqMsgMgr *reqMgr)
239 {
240 uint32_t retryCount = 1;
241 while (retryCount <= reqMgr->maxRetryCount) {
242 if (reqMgr->socketId < 0) {
243 reqMgr->socketId = CreateClientSocket(reqMgr->type, reqMgr->timeout);
244 }
245 if (reqMgr->socketId < 0) {
246 APPSPAWN_LOGV("Failed to create socket, try again");
247 usleep(RETRY_TIME);
248 retryCount++;
249 continue;
250 }
251 break;
252 }
253 }
254
ClientSendMsg(AppSpawnReqMsgMgr * reqMgr,AppSpawnReqMsgNode * reqNode,AppSpawnResult * result)255 static int ClientSendMsg(AppSpawnReqMsgMgr *reqMgr, AppSpawnReqMsgNode *reqNode, AppSpawnResult *result)
256 {
257 uint32_t retryCount = 1;
258 int isColdRun = reqNode->isAsan;
259 while (retryCount <= reqMgr->maxRetryCount) {
260 if (reqMgr->socketId < 0) { // try create socket
261 TryCreateSocket(reqMgr);
262 if (reqMgr->socketId < 0) {
263 usleep(RETRY_TIME);
264 retryCount++;
265 continue;
266 }
267 }
268 if (isColdRun && reqMgr->timeout < ASAN_TIMEOUT) {
269 UpdateSocketTimeout(ASAN_TIMEOUT, reqMgr->socketId);
270 }
271
272 if (reqNode->msg->msgId == 0) {
273 reqNode->msg->msgId = reqMgr->msgNextId++;
274 }
275 int ret = HandleMsgSend(reqMgr, reqMgr->socketId, reqNode);
276 if (ret == 0) {
277 ret = ReadMessage(reqMgr->socketId, reqNode->msg->msgId,
278 reqMgr->recvBlock.buffer, reqMgr->recvBlock.blockSize, result);
279 }
280 if (ret == 0) {
281 if (isColdRun && reqMgr->timeout < ASAN_TIMEOUT) {
282 UpdateSocketTimeout(reqMgr->timeout, reqMgr->socketId);
283 }
284 return 0;
285 }
286 // retry
287 CloseClientSocket(reqMgr->socketId);
288 reqMgr->socketId = -1;
289 reqMgr->msgNextId = 1;
290 reqNode->msg->msgId = 0;
291 usleep(RETRY_TIME);
292 retryCount++;
293 }
294 return APPSPAWN_TIMEOUT;
295 }
296
AppSpawnClientInit(const char * serviceName,AppSpawnClientHandle * handle)297 int AppSpawnClientInit(const char *serviceName, AppSpawnClientHandle *handle)
298 {
299 APPSPAWN_CHECK(serviceName != NULL, return APPSPAWN_ARG_INVALID, "Invalid service name");
300 APPSPAWN_CHECK(handle != NULL, return APPSPAWN_ARG_INVALID, "Invalid handle for %{public}s", serviceName);
301 APPSPAWN_LOGV("AppSpawnClientInit serviceName %{public}s", serviceName);
302 AppSpawnClientType type = CLIENT_FOR_APPSPAWN;
303 if (strcmp(serviceName, CJAPPSPAWN_SERVER_NAME) == 0) {
304 type = CLIENT_FOR_CJAPPSPAWN;
305 } else if (strcmp(serviceName, NWEBSPAWN_SERVER_NAME) == 0 || strstr(serviceName, NWEBSPAWN_SOCKET_NAME) != NULL) {
306 type = CLIENT_FOR_NWEBSPAWN;
307 } else if (strcmp(serviceName, NATIVESPAWN_SERVER_NAME) == 0 ||
308 strstr(serviceName, NATIVESPAWN_SOCKET_NAME) != NULL) {
309 type = CLIENT_FOR_NATIVESPAWN;
310 }
311 int ret = InitClientInstance(type);
312 APPSPAWN_CHECK(ret == 0, return APPSPAWN_SYSTEM_ERROR, "Failed to create reqMgr");
313 *handle = (AppSpawnClientHandle)g_clientInstance[type];
314 return 0;
315 }
316
AppSpawnClientDestroy(AppSpawnClientHandle handle)317 int AppSpawnClientDestroy(AppSpawnClientHandle handle)
318 {
319 AppSpawnReqMsgMgr *reqMgr = (AppSpawnReqMsgMgr *)handle;
320 APPSPAWN_CHECK(reqMgr != NULL, return APPSPAWN_SYSTEM_ERROR, "Invalid reqMgr");
321 pthread_mutex_lock(&g_mutex);
322 if (reqMgr->type < sizeof(g_clientInstance) / sizeof(g_clientInstance[0])) {
323 g_clientInstance[reqMgr->type] = NULL;
324 }
325 pthread_mutex_unlock(&g_mutex);
326 pthread_mutex_destroy(&reqMgr->mutex);
327 if (reqMgr->socketId >= 0) {
328 CloseClientSocket(reqMgr->socketId);
329 reqMgr->socketId = -1;
330 }
331 free(reqMgr);
332 return 0;
333 }
334
AppSpawnClientSendMsg(AppSpawnClientHandle handle,AppSpawnReqMsgHandle reqHandle,AppSpawnResult * result)335 int AppSpawnClientSendMsg(AppSpawnClientHandle handle, AppSpawnReqMsgHandle reqHandle, AppSpawnResult *result)
336 {
337 APPSPAWN_CHECK(result != NULL, AppSpawnReqMsgFree(reqHandle);
338 return APPSPAWN_ARG_INVALID, "Invalid result");
339 result->result = APPSPAWN_ARG_INVALID;
340 result->pid = 0;
341 AppSpawnReqMsgMgr *reqMgr = (AppSpawnReqMsgMgr *)handle;
342 APPSPAWN_CHECK(reqMgr != NULL, AppSpawnReqMsgFree(reqHandle);
343 return APPSPAWN_ARG_INVALID, "Invalid reqMgr");
344 AppSpawnReqMsgNode *reqNode = (AppSpawnReqMsgNode *)reqHandle;
345 APPSPAWN_CHECK(reqNode != NULL && reqNode->msg != NULL, AppSpawnReqMsgFree(reqHandle);
346 return APPSPAWN_ARG_INVALID, "Invalid msgReq");
347
348 APPSPAWN_LOGI("AppSpawnClientSendMsg reqId: %{public}u msgLen: %{public}u %{public}s",
349 reqNode->reqId, reqNode->msg->msgLen, reqNode->msg->processName);
350 pthread_mutex_lock(&reqMgr->mutex);
351 int ret = ClientSendMsg(reqMgr, reqNode, result);
352 if (ret != 0) {
353 result->result = ret;
354 }
355 pthread_mutex_unlock(&reqMgr->mutex);
356 APPSPAWN_LOGI("AppSpawnClientSendMsg reqId: %{public}u end result: 0x%{public}x pid: %{public}d",
357 reqNode->reqId, result->result, result->pid);
358 AppSpawnReqMsgFree(reqHandle);
359 return ret;
360 }
361