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