1 /*
2  * Copyright (C) 2022 Huawei Technologies Co., Ltd.
3  * Licensed under the Mulan PSL v2.
4  * You can use this software according to the terms and conditions of the Mulan PSL v2.
5  * You may obtain a copy of Mulan PSL v2 at:
6  *     http://license.coscl.org.cn/MulanPSL2
7  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
8  * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
9  * PURPOSE.
10  * See the Mulan PSL v2 for more details.
11  */
12 
13 #include "tee_client_socket.h"
14 #include <errno.h>     /* for errno */
15 #include <sys/types.h> /* for open close */
16 #include <sys/ioctl.h> /* for ioctl */
17 #include <sys/socket.h>
18 #include <sys/un.h>
19 #include <securec.h>
20 #include <time.h>
21 #include "tee_log.h"
22 #include "tc_ns_client.h"
23 #include "tee_client_inner.h"
24 
25 #ifdef LOG_TAG
26 #undef LOG_TAG
27 #endif
28 #define LOG_TAG "libteec_vendor"
29 
30 #define EACCES_ERR                (-3)
31 #define SEND_MESS_ERR             (-4)
32 #define IOV_LEN 1
33 
ConnectTeecdSocket(int * socketFd)34 static int ConnectTeecdSocket(int *socketFd)
35 {
36     int ret;
37     uint32_t len;
38     struct sockaddr_un remote;
39 
40     if (socketFd == NULL) {
41         tloge("bad parameter\n");
42         return -1;
43     }
44 
45     errno_t rc = memset_s(&remote, sizeof(remote), 0, sizeof(remote));
46     if (rc != EOK) {
47         return -1;
48     }
49 
50     int s = socket(AF_UNIX, SOCK_STREAM, 0);
51     if (s == -1) {
52         tloge("can't open stream socket, errno=%d", errno);
53         return -1;
54     }
55 
56     tlogd("Trying to connect...\n");
57     remote.sun_family = AF_UNIX;
58 
59     rc = strncpy_s(remote.sun_path, sizeof(remote.sun_path), TC_NS_SOCKET_NAME, sizeof(TC_NS_SOCKET_NAME));
60     if (rc != EOK) {
61         tloge("strncpy_s failed, errno=%d", rc);
62         close(s);
63         return -1;
64     }
65     len = (uint32_t)(strlen(remote.sun_path) + sizeof(remote.sun_family));
66     remote.sun_path[0] = 0;
67 
68     if (connect(s, (struct sockaddr *)&remote, len) == -1) {
69         tloge("connect() failed, errno=%d\n", errno);
70         ret = -1;
71         if (errno == EACCES) {
72             ret = EACCES_ERR;
73         }
74         close(s);
75         return ret;
76     }
77     tlogd("Connected.\n");
78 
79     *socketFd = s;
80     return 0;
81 }
82 
InitRecvMsg(struct msghdr * recvMsg,struct iovec * iov,size_t iovLen,char * ctrlBuf,size_t ctrlBufLen)83 static int InitRecvMsg(struct msghdr *recvMsg, struct iovec *iov, size_t iovLen,
84                        char *ctrlBuf, size_t ctrlBufLen)
85 {
86     if (recvMsg == NULL || iov == NULL || ctrlBuf == NULL) {
87         tloge("param error!\n");
88         return EINVAL;
89     }
90     recvMsg->msg_iov        = iov;
91     recvMsg->msg_iovlen     = iovLen;
92     recvMsg->msg_name       = NULL;
93     recvMsg->msg_namelen    = 0;
94     recvMsg->msg_control    = ctrlBuf;
95     recvMsg->msg_controllen = ctrlBufLen;
96     return EOK;
97 }
98 
99 /* Socket from which the file descriptor is read */
RecvFileDescriptor(int cmd,int socketFd)100 static int RecvFileDescriptor(int cmd, int socketFd)
101 {
102     struct msghdr hmsg;
103     struct iovec iov[IOV_LEN];
104     struct cmsghdr *controlMsg = NULL;
105     char ctrlBuf[CMSG_SPACE(sizeof(int))];
106     char data[IOV_LEN] = "0";
107     int version  = 0;
108     ssize_t res;
109     errno_t rc;
110     int *cmdata = NULL;
111 
112     rc = memset_s(&hmsg, sizeof(struct msghdr), 0, sizeof(struct msghdr));
113     if (rc != EOK) {
114         return -1;
115     }
116     rc = memset_s(ctrlBuf, sizeof(ctrlBuf), 0, CMSG_SPACE(sizeof(int)));
117     if (rc != EOK) {
118         return -1;
119     }
120     /* For the dummy data */
121     iov[0].iov_base = data;
122     iov[0].iov_len  = sizeof(data);
123 
124     rc = InitRecvMsg(&hmsg, iov, IOV_LEN, ctrlBuf, CMSG_SPACE(sizeof(int)));
125     if (rc != EOK) {
126         tloge("init msg failed!/n");
127         return -1;
128     }
129 
130     if (cmd == GET_TEEVERSION) {
131         iov[0].iov_base        = &version;
132         iov[0].iov_len         = sizeof(int);
133         hmsg.msg_control    = NULL;
134         hmsg.msg_controllen = 0;
135         res                    = recvmsg(socketFd, &hmsg, 0);
136         if (res <= 0) {
137             return -1;
138         }
139         return version;
140     }
141 
142     res = recvmsg(socketFd, &hmsg, 0);
143     if (res <= 0) {
144         return -1;
145     }
146 
147     /* Iterate through header to find if there is a file descriptor */
148     for (controlMsg = CMSG_FIRSTHDR(&hmsg); controlMsg != NULL; controlMsg = CMSG_NXTHDR(&hmsg, controlMsg)) {
149         if ((controlMsg->cmsg_level == SOL_SOCKET) && (controlMsg->cmsg_type == SCM_RIGHTS)) {
150             cmdata = (int *)(uintptr_t)CMSG_DATA(controlMsg);
151             return *cmdata;
152         }
153     }
154 
155     return -1;
156 }
157 
FillMsgBuffer(const CaAuthInfo * caInfo,CaRevMsg ** revMsg,int cmd)158 static int FillMsgBuffer(const CaAuthInfo *caInfo, CaRevMsg **revMsg, int cmd)
159 {
160     CaRevMsg *revBuffer = (CaRevMsg *)malloc(sizeof(*revBuffer));
161     if (revBuffer == NULL) {
162         tloge("alloc mem failed.\n");
163         return (int)TEEC_ERROR_OUT_OF_MEMORY;
164     }
165     errno_t ret = memset_s((void *)revBuffer, sizeof(*revBuffer), 0, sizeof(*revBuffer));
166     if (ret != EOK) {
167         tloge("memset failed\n");
168         free(revBuffer);
169         return -1;
170     }
171     int temp = memcpy_s(&(revBuffer->caAuthInfo), sizeof(CaAuthInfo), caInfo, sizeof(*caInfo));
172     if (temp != EOK) {
173         tloge("memcpy_s error!\n");
174         free(revBuffer);
175         return -1;
176     }
177     revBuffer->cmd = cmd;
178     *revMsg = revBuffer;
179     return EOK;
180 }
181 
InitSockMsg(struct msghdr * message,CaRevMsg * revMsg,struct iovec * iov)182 static void InitSockMsg(struct msghdr *message, CaRevMsg *revMsg, struct iovec *iov)
183 {
184     message->msg_name            = NULL;
185     message->msg_namelen         = 0;
186     message->msg_flags           = 0;
187     message->msg_iov             = iov;
188     message->msg_iovlen          = 1;
189     message->msg_control         = NULL;
190     message->msg_controllen      = 0;
191     (message->msg_iov[0]).iov_base = revMsg;
192     (message->msg_iov[0]).iov_len  = sizeof(*revMsg);
193 }
194 
SleepNs(long num)195 static void SleepNs(long num)
196 {
197     struct timespec ts;
198     ts.tv_sec  = 0;
199     ts.tv_nsec = num;
200 
201     if (nanosleep(&ts, NULL) != 0) {
202         tlogd("nanosleep ms error\n");
203     }
204 }
205 
206 
207 /* sleep 200 ms, and 50 times */
208 #define SLEEP_TIME (200 * 1000 * 1000)
209 #define SLEEP_COUNT 50
CaDaemonConnectWithCaInfo(const CaAuthInfo * caInfo,int cmd)210 int CaDaemonConnectWithCaInfo(const CaAuthInfo *caInfo, int cmd)
211 {
212     int s = -1;
213     struct msghdr message;
214     struct iovec iov[1];
215     CaRevMsg *revMsg = NULL;
216     int32_t failCount = 0; /* allow fail 50 times */
217     int32_t cRet;
218 
219     if (caInfo == NULL) {
220         tloge("ca daemon: ca auth info is NULL\n");
221         return -1;
222     }
223 
224     /* add retry to avoid app start before daemon */
225     while (failCount++ < SLEEP_COUNT) {
226         cRet = ConnectTeecdSocket(&s);
227         if (cRet != -1) {
228             break;
229         }
230 
231         tlogd("open device failed, retry!\n");
232         SleepNs(SLEEP_TIME);
233     }
234 
235     if (cRet < 0) {
236         tloge("try connect ca daemon failed, fail_counts = %d\n", failCount);
237         return -1;
238     }
239 
240     if (memset_s(&message, sizeof(message), 0, sizeof(message)) != EOK) {
241         tloge("ca daemon: memset failed\n");
242         close(s);
243         return -1;
244     }
245 
246     if (FillMsgBuffer(caInfo, &revMsg, cmd) != EOK) {
247         tloge("memcpy_s error!\n");
248         close(s);
249         return -1;
250     }
251 
252     /* For the dummy data */
253     InitSockMsg(&message, revMsg, iov);
254     if (sendmsg(s, &message, 0) < 0) {
255         tloge("send message error %d \n", errno);
256         close(s);
257         free(revMsg);
258         return SEND_MESS_ERR;
259     }
260 
261     int fd = RecvFileDescriptor(cmd, s);
262     if (fd >= 0) {
263         tlogd("FD received!");
264     }
265     close(s);
266     free(revMsg);
267     return fd;
268 }