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_ca_daemon.h"
14 #include <unistd.h>
15 #include <errno.h> /* for errno */
16 #include <fcntl.h>
17 #include <sys/ioctl.h> /* for ioctl */
18 #include <sys/mman.h>  /* for mmap */
19 #include <sys/socket.h>
20 #include <sys/un.h>
21 #include <pthread.h>
22 #include "securec.h"
23 #include "tc_ns_client.h"
24 #include "tee_client_type.h"
25 #include "tee_client_socket.h"
26 #include "tee_agent.h"
27 #include "tee_log.h"
28 #include "tee_auth_common.h"
29 #include "tee_ca_auth.h"
30 #include "fs_work_agent.h"
31 
32 /* debug switch */
33 #ifdef LOG_NDEBUG
34 #undef LOG_NDEBUG
35 #endif
36 #ifdef LOG_TAG
37 #undef LOG_TAG
38 #endif
39 #define LOG_TAG "teecd"
40 
41 #define IOV_LEN 1
42 
43 static unsigned int g_version = 0;
44 
InitMsg(struct msghdr * hmsg,struct iovec * iov,size_t iovLen,char * ctrlBuf,size_t ctrlBufLen)45 static int InitMsg(struct msghdr *hmsg, struct iovec *iov, size_t iovLen,
46                    char *ctrlBuf, size_t ctrlBufLen)
47 {
48     if (hmsg == NULL || iov == NULL || ctrlBuf == NULL) {
49         return EINVAL;
50     }
51     hmsg->msg_name       = NULL;
52     hmsg->msg_namelen    = 0;
53     hmsg->msg_iov        = iov;
54     hmsg->msg_iovlen     = iovLen;
55     hmsg->msg_control    = ctrlBuf;
56     hmsg->msg_controllen = ctrlBufLen;
57     return EOK;
58 }
59 
SendFileDescriptor(int cmd,int socket,int fd)60 static int SendFileDescriptor(int cmd, int socket, int fd)
61 {
62     struct msghdr hmsg;
63     struct iovec iov[IOV_LEN];
64     char ctrlBuf[CMSG_SPACE(sizeof(int))];
65     char base[IOV_LEN];
66     int *cmdata = NULL;
67 
68     errno_t ret = memset_s(&hmsg, sizeof(hmsg), 0, sizeof(hmsg));
69     if (ret != EOK) {
70         tloge("memset failed!\n");
71         return ret;
72     }
73 
74     ret = memset_s(ctrlBuf, CMSG_SPACE(sizeof(int)), 0, CMSG_SPACE(sizeof(int)));
75     if (ret != EOK) {
76         tloge("memset failed!\n");
77         return ret;
78     }
79     /* Pass at least one byte data, recvmsg() will not return 0 */
80     base[0]         = ' ';
81     iov[0].iov_base = base;
82     iov[0].iov_len  = sizeof(base);
83 
84     ret = InitMsg(&hmsg, iov, IOV_LEN, ctrlBuf, CMSG_SPACE(sizeof(int)));
85     if (ret != EOK) {
86         tloge("init msg failed!\n");
87         return ret;
88     }
89 
90     struct cmsghdr *controlMsg = CMSG_FIRSTHDR(&hmsg);
91     if (controlMsg != NULL) {
92         controlMsg->cmsg_level          = SOL_SOCKET;
93         controlMsg->cmsg_type           = SCM_RIGHTS;
94         controlMsg->cmsg_len            = CMSG_LEN(sizeof(int));
95         cmdata = (int *)(uintptr_t)CMSG_DATA(controlMsg);
96         *cmdata = fd;
97     }
98 
99     if (cmd == GET_TEEVERSION) {
100         iov[0].iov_base        = &fd;
101         iov[0].iov_len         = sizeof(int);
102         hmsg.msg_control       = NULL;
103         hmsg.msg_controllen    = 0;
104     }
105 
106     ret = (int)sendmsg(socket, &hmsg, 0);
107     if (ret <= 0) {
108         tloge("sendmsg failed ret=0x%x:%d.\n", ret, errno);
109         return -1;
110     }
111     return 0;
112 }
113 
ProcessCaMsg(const struct ucred * cr,const CaRevMsg * caInfo,int socket)114 static int ProcessCaMsg(const struct ucred *cr, const CaRevMsg *caInfo, int socket)
115 {
116     int ret;
117 
118     if (caInfo->cmd == GET_TEEVERSION) {
119         ret = SendFileDescriptor(caInfo->cmd, socket, (int)g_version);
120         if (ret != 0) {
121             tloge("Failed to send version back. ret = %d\n", ret);
122             return -1;
123         }
124         return 0;
125     }
126 
127     int fd = open(TC_NS_CLIENT_DEV_NAME, O_RDWR);
128     if (fd == -1) {
129         tloge("Failed to open %s: %d\n", TC_NS_CLIENT_DEV_NAME, errno);
130         return -1;
131     }
132 
133     ret = SendLoginInfo(cr, caInfo, fd);
134     if (ret != EOK) {
135         tloge("Failed to send login info. ret=%d\n", ret);
136         close(fd);
137         return -1;
138     }
139 
140     ret = SendFileDescriptor(caInfo->cmd, socket, fd);
141     if (ret != EOK) {
142         tloge("Failed to send fd. ret=%d\n", ret);
143         close(fd);
144         return -1;
145     }
146     close(fd);
147     return 0;
148 }
149 
ProcessAccept(int s,CaRevMsg * caInfo)150 static void ProcessAccept(int s, CaRevMsg *caInfo)
151 {
152     struct ucred cr;
153     struct sockaddr_un remote;
154     int ret;
155 
156     while (1) {
157         /* int done, n; */
158         tlogd("Waiting for a connection...target daemon\n");
159         size_t t = sizeof(remote);
160         int s2   = accept(s, (struct sockaddr *)&remote, (socklen_t *)&t);
161         if (s2 == -1) {
162             tloge("accept() to server socket failed, errno=%d", errno);
163             continue;
164         }
165 
166         socklen_t len = sizeof(struct ucred);
167         if (getsockopt(s2, SOL_SOCKET, SO_PEERCRED, &cr, &len) < 0) {
168             tloge("peercred failed: %d", errno);
169             close(s2);
170             continue;
171         }
172 
173         tlogd("uid %d pid %d\n", cr.uid, cr.pid);
174 
175         ret = RecvCaMsg(s2, caInfo);
176         if (ret != 0) {
177             tloge("tee ca daemon recvmsg failed\n");
178             goto CLOSE_SOCKET;
179         }
180 
181         TrySyncSysTimeToSecure();
182 
183         ret = ProcessCaMsg(&cr, caInfo, s2);
184         if (ret != 0) {
185             tloge("Failed to process ca msg. ret=%d\n", ret);
186             goto CLOSE_SOCKET;
187         }
188 
189     CLOSE_SOCKET:
190         tlogd("close_socket and curret ret=%u\n", ret);
191         close(s2);
192         errno_t rc = memset_s(caInfo, sizeof(CaRevMsg), 0, sizeof(CaRevMsg));
193         if (rc != EOK) {
194             tloge("ca_info memset_s failed\n");
195         }
196     }
197 }
198 
FormatSockAddr(struct sockaddr_un * local,socklen_t * len)199 static int FormatSockAddr(struct sockaddr_un *local, socklen_t *len)
200 {
201     int ret = strncpy_s(local->sun_path, sizeof(local->sun_path), TC_NS_SOCKET_NAME, sizeof(TC_NS_SOCKET_NAME));
202     if (ret != EOK) {
203         tloge("strncpy_s failed\n");
204         return ret;
205     }
206 
207     local->sun_family = AF_UNIX;
208     *len              = (socklen_t)(strlen(local->sun_path) + sizeof(local->sun_family));
209     /* Make the socket in the Abstract Domain(no path but everyone can connect) */
210     local->sun_path[0] = 0;
211 
212     return 0;
213 }
214 
CreateSocket(void)215 static int32_t CreateSocket(void)
216 {
217     int32_t ret;
218 
219     /* Open a socket (a UNIX domain stream socket) */
220     int32_t s = socket(AF_UNIX, SOCK_STREAM, 0);
221     if (s < 0) {
222         tloge("can't open stream socket, errno=%d\n", errno);
223         return -1;
224     }
225 
226     /* Fill in address structure and bind to socket */
227     struct sockaddr_un local;
228     socklen_t len;
229     ret = memset_s(&local, sizeof(local), 0, sizeof(local));
230     if (ret != EOK) {
231         tloge("memset_s sockaddr_un local failed!\n");
232         close(s);
233         return -1;
234     }
235 
236     ret = FormatSockAddr(&local, &len);
237     if (ret != EOK) {
238         tloge("format sock addr failed\n");
239         close(s);
240         return -1;
241     }
242 
243     if (bind(s, (struct sockaddr *)&local, len) < 0) {
244         tloge("bind() to server socket failed, errno=%d\n", errno);
245         close(s);
246         return -1;
247     }
248 
249     return s;
250 }
251 
CaServerWorkThread(void * dummy)252 void *CaServerWorkThread(void *dummy)
253 {
254     (void)dummy;
255     CaRevMsg *caInfo = NULL;
256 
257     int32_t s = CreateSocket();
258     if (s < 0) {
259         return NULL;
260     }
261 
262     /* Start listening on the socket */
263     if (listen(s, BACKLOG_LEN) < 0) {
264         tloge("listen() failed, errno=%d\n", errno);
265         goto CLOSE_EXIT;
266     }
267 
268     tlogv("\n********* deamon successfully initialized!***\n");
269 
270     caInfo = (CaRevMsg *)malloc(sizeof(CaRevMsg));
271     if (caInfo == NULL) {
272         tloge("ca server: Failed to malloc caInfo\n");
273         goto CLOSE_EXIT;
274     }
275 
276     if (memset_s(caInfo, sizeof(CaRevMsg), 0, sizeof(CaRevMsg)) != EOK) {
277         tloge("ca_info memset_s failed\n");
278         free(caInfo);
279         goto CLOSE_EXIT;
280     }
281 
282     ProcessAccept(s, caInfo);
283     free(caInfo);
284 
285     tlogv("\n********* deamon process_accept over!***\n");
286 
287 CLOSE_EXIT:
288     close(s);
289     return NULL;
290 }
291