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 }