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 "secfile_load_agent.h"
14 #include <limits.h>
15 #include <securec.h>
16 #include <sys/prctl.h>
17 #include "tc_ns_client.h"
18 #include "tee_log.h"
19
20 #define MAX_PATH_LEN 256
21 #ifdef LOG_TAG
22 #undef LOG_TAG
23 #endif
24 #define LOG_TAG "teecd_agent"
25 #define MAX_BUFFER_LEN (8 * 1024 * 1024)
26 #define H_OFFSET 32
27 int g_secLoadAgentFd = -1;
28
GetSecLoadAgentFd(void)29 int GetSecLoadAgentFd(void)
30 {
31 return g_secLoadAgentFd;
32 }
33
SetSecLoadAgentFd(int secLoadAgentFd)34 void SetSecLoadAgentFd(int secLoadAgentFd)
35 {
36 g_secLoadAgentFd = secLoadAgentFd;
37 }
38
GetImgLen(FILE * fp,long * totalLlen)39 static int GetImgLen(FILE *fp, long *totalLlen)
40 {
41 int ret;
42
43 ret = fseek(fp, 0, SEEK_END);
44 if (ret != 0) {
45 tloge("fseek error\n");
46 return -1;
47 }
48 *totalLlen = ftell(fp);
49 if (*totalLlen <= 0 || *totalLlen > MAX_BUFFER_LEN) {
50 tloge("file is not exist or size is too large, filesize = %" PUBLIC "ld\n", *totalLlen);
51 return -1;
52 }
53 ret = fseek(fp, 0, SEEK_SET);
54 if (ret != 0) {
55 tloge("fseek error\n");
56 return -1;
57 }
58 return ret;
59 }
60
SecFileLoadWork(int tzFd,const char * filePath,enum SecFileType fileType,const TEEC_UUID * uuid)61 static int32_t SecFileLoadWork(int tzFd, const char *filePath, enum SecFileType fileType, const TEEC_UUID *uuid)
62 {
63 char realPath[PATH_MAX + 1] = { 0 };
64 FILE *fp = NULL;
65 int ret;
66
67 if (tzFd < 0) {
68 tloge("fd of tzdriver is valid!\n");
69 return -1;
70 }
71 if (realpath(filePath, realPath) == NULL) {
72 tloge("realpath open file err=%" PUBLIC "d, filePath=%" PUBLIC "s\n", errno, filePath);
73 return -1;
74 }
75
76 #ifndef TEE_LOAD_FROM_ROOTFS
77 if (strncmp(realPath, TEE_DEFAULT_PATH, strlen(TEE_DEFAULT_PATH)) != 0 &&
78 strncmp(realPath, TEE_FEIMA_DEFAULT_PATH, strlen(TEE_FEIMA_DEFAULT_PATH)) != 0) {
79 tloge("realpath -%" PUBLIC "s- is invalid\n", realPath);
80 return -1;
81 }
82 #else
83 if (strncmp(realPath, TEE_DEFAULT_PATH_ROOTFS, strlen(TEE_DEFAULT_PATH_ROOTFS)) != 0) {
84 tloge("realpath -%" PUBLIC "s- is invalid\n", realPath);
85 return -1;
86 }
87 #endif
88
89 fp = fopen(realPath, "r");
90 if (fp == NULL) {
91 tloge("open file err=%" PUBLIC "d, path=%" PUBLIC "s\n", errno, filePath);
92 return -1;
93 }
94 ret = LoadSecFile(tzFd, fp, fileType, uuid);
95 if (fp != NULL) {
96 fclose(fp);
97 }
98 return ret;
99 }
100
101 // input param uuid may be NULL, so don need to check if uuid is NULL
LoadSecFile(int tzFd,FILE * fp,enum SecFileType fileType,const TEEC_UUID * uuid)102 int32_t LoadSecFile(int tzFd, FILE *fp, enum SecFileType fileType, const TEEC_UUID *uuid)
103 {
104 int32_t ret;
105 char *fileBuffer = NULL;
106 struct SecLoadIoctlStruct ioctlArg = {{ 0 }, { 0 }, { NULL } };
107
108 if (tzFd < 0 || fp == NULL) {
109 tloge("param erro!\n");
110 return -1;
111 }
112
113 do {
114 long totalLen = 0;
115 ret = GetImgLen(fp, &totalLen);
116 if (ret != 0) {
117 break;
118 }
119
120 if (totalLen <= 0 || totalLen > MAX_BUFFER_LEN) {
121 ret = -1;
122 tloge("totalLen is invalid\n");
123 break;
124 }
125
126 /* alloc a less than 8M heap memory, it needn't slice. */
127 fileBuffer = malloc((size_t)totalLen);
128 if (fileBuffer == NULL) {
129 tloge("alloc TA file buffer(size=%" PUBLIC "ld) failed\n", totalLen);
130 ret = -1;
131 break;
132 }
133
134 /* read total ta file to file buffer */
135 long fileSize = (long)fread(fileBuffer, 1, totalLen, fp);
136 if (fileSize != totalLen) {
137 tloge("read ta file failed, read size/total size=%" PUBLIC "ld/%" PUBLIC "ld\n", fileSize, totalLen);
138 ret = -1;
139 break;
140 }
141
142 ioctlArg.secFileInfo.fileType = fileType;
143 ioctlArg.secFileInfo.fileSize = (uint32_t)totalLen;
144 ioctlArg.memref.file_addr = (uint32_t)(uintptr_t)fileBuffer;
145 ioctlArg.memref.file_h_addr = (uint32_t)(((uint64_t)(uintptr_t)fileBuffer) >> H_OFFSET);
146 if (uuid != NULL && memcpy_s((void *)(&ioctlArg.uuid), sizeof(ioctlArg.uuid), uuid, sizeof(*uuid)) != EOK) {
147 tloge("memcpy uuid fail\n");
148 break;
149 }
150
151 ret = ioctl(tzFd, (int)TC_NS_CLIENT_IOCTL_LOAD_APP_REQ, &ioctlArg);
152 if (ret != 0) {
153 tloge("ioctl to load sec file failed, ret = 0x%" PUBLIC "x\n", ret);
154 }
155 } while (false);
156
157 if (fileBuffer != NULL) {
158 free(fileBuffer);
159 }
160 return ret;
161 }
162
IsTaLib(const TEEC_UUID * uuid)163 static bool IsTaLib(const TEEC_UUID *uuid)
164 {
165 char *chr = (char *)uuid;
166 uint32_t i;
167
168 for (i = 0; i < sizeof(*uuid); i++) {
169 if (chr[i] != 0) {
170 return true;
171 }
172 }
173 return false;
174 }
175
GetFeimaSecFileName(const struct SecAgentControlType * secAgentControl,char * fname,int32_t fnameLen)176 static int32_t GetFeimaSecFileName(const struct SecAgentControlType *secAgentControl, char *fname, int32_t fnameLen)
177 {
178 int32_t ret = -1;
179
180 if (IsTaLib(&(secAgentControl->LibSec.uuid))) {
181 ret = snprintf_s(fname, fnameLen, MAX_PATH_LEN - 1,
182 "%s/%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x%s.sec",
183 TEE_FEIMA_DEFAULT_PATH, secAgentControl->LibSec.uuid.timeLow, secAgentControl->LibSec.uuid.timeMid,
184 secAgentControl->LibSec.uuid.timeHiAndVersion, secAgentControl->LibSec.uuid.clockSeqAndNode[0],
185 secAgentControl->LibSec.uuid.clockSeqAndNode[1], secAgentControl->LibSec.uuid.clockSeqAndNode[2],
186 secAgentControl->LibSec.uuid.clockSeqAndNode[3], secAgentControl->LibSec.uuid.clockSeqAndNode[4],
187 secAgentControl->LibSec.uuid.clockSeqAndNode[5], secAgentControl->LibSec.uuid.clockSeqAndNode[6],
188 secAgentControl->LibSec.uuid.clockSeqAndNode[7], secAgentControl->LibSec.libName);
189 } else {
190 ret = snprintf_s(fname, fnameLen, MAX_PATH_LEN - 1,
191 "%s/%s.sec", TEE_FEIMA_DEFAULT_PATH, secAgentControl->LibSec.libName);
192 }
193
194 if (ret < 0) {
195 tloge("pack fname err\n");
196 memset_s(fname, fnameLen, 0, fnameLen);
197 return -1;
198 }
199
200 char realPath[PATH_MAX + 1] = { 0 };
201 if (realpath(fname, realPath) == NULL) {
202 tlogi("GetNewSecFileName err=%" PUBLIC "d, filePath=%" PUBLIC "s, will get from old path\n", errno, fname);
203 memset_s(fname, fnameLen, 0, fnameLen);
204 return -1;
205 }
206
207 return 0;
208 }
209
LoadLib(struct SecAgentControlType * secAgentControl)210 static void LoadLib(struct SecAgentControlType *secAgentControl)
211 {
212 int32_t ret;
213 char fname[MAX_PATH_LEN] = { 0 };
214
215 if (secAgentControl == NULL) {
216 tloge("secAgentControl is null\n");
217 return;
218 }
219 if (strnlen(secAgentControl->LibSec.libName, MAX_SEC_FILE_NAME_LEN) >= MAX_SEC_FILE_NAME_LEN) {
220 tloge("libName is too long!\n");
221 secAgentControl->ret = -1;
222 return;
223 }
224
225 if (GetFeimaSecFileName(secAgentControl, fname, MAX_PATH_LEN) == -1) {
226 if (IsTaLib(&(secAgentControl->LibSec.uuid))) {
227 ret = snprintf_s(fname, sizeof(fname), MAX_PATH_LEN - 1,
228 "%s/%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x%s.sec",
229 TEE_DEFAULT_PATH, secAgentControl->LibSec.uuid.timeLow, secAgentControl->LibSec.uuid.timeMid,
230 secAgentControl->LibSec.uuid.timeHiAndVersion, secAgentControl->LibSec.uuid.clockSeqAndNode[0],
231 secAgentControl->LibSec.uuid.clockSeqAndNode[1], secAgentControl->LibSec.uuid.clockSeqAndNode[2],
232 secAgentControl->LibSec.uuid.clockSeqAndNode[3], secAgentControl->LibSec.uuid.clockSeqAndNode[4],
233 secAgentControl->LibSec.uuid.clockSeqAndNode[5], secAgentControl->LibSec.uuid.clockSeqAndNode[6],
234 secAgentControl->LibSec.uuid.clockSeqAndNode[7], secAgentControl->LibSec.libName);
235 } else {
236 ret = snprintf_s(fname, sizeof(fname), MAX_PATH_LEN - 1,
237 "%s/%s.sec", TEE_DEFAULT_PATH, secAgentControl->LibSec.libName);
238 }
239 if (ret < 0) {
240 tloge("pack fname err\n");
241 secAgentControl->ret = -1;
242 return;
243 }
244 }
245 ret = SecFileLoadWork(g_secLoadAgentFd, (const char *)fname, LOAD_LIB, NULL);
246 if (ret != 0) {
247 tloge("teec load app failed\n");
248 secAgentControl->ret = -1;
249 secAgentControl->error = errno;
250 return;
251 }
252 secAgentControl->ret = 0;
253 return;
254 }
255
GetTaPath(const TEEC_UUID * uuid,char * fname,unsigned int len)256 static int GetTaPath(const TEEC_UUID *uuid, char *fname, unsigned int len)
257 {
258 int32_t ret = -1;
259 char realPath[PATH_MAX + 1] = { 0 };
260
261 ret = snprintf_s(fname, len, MAX_PATH_LEN - 1, "%s/%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x.sec",
262 TEE_FEIMA_DEFAULT_PATH, uuid->timeLow, uuid->timeMid,
263 uuid->timeHiAndVersion, uuid->clockSeqAndNode[0],
264 uuid->clockSeqAndNode[1], uuid->clockSeqAndNode[2],
265 uuid->clockSeqAndNode[3], uuid->clockSeqAndNode[4],
266 uuid->clockSeqAndNode[5], uuid->clockSeqAndNode[6],
267 uuid->clockSeqAndNode[7]);
268 if (ret < 0) {
269 tloge("pack new path fname err");
270 return -1;
271 }
272
273 if (realpath(fname, realPath) == NULL) {
274 tloge("realpath open file err=" PUBLIC "d, filePath=" PUBLIC "s, will use old path\n", errno, fname);
275 ret = snprintf_s(fname, len, MAX_PATH_LEN - 1, "%s/%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x.sec",
276 TEE_DEFAULT_PATH, uuid->timeLow, uuid->timeMid,
277 uuid->timeHiAndVersion, uuid->clockSeqAndNode[0],
278 uuid->clockSeqAndNode[1], uuid->clockSeqAndNode[2],
279 uuid->clockSeqAndNode[3], uuid->clockSeqAndNode[4],
280 uuid->clockSeqAndNode[5], uuid->clockSeqAndNode[6],
281 uuid->clockSeqAndNode[7]);
282 if (ret < 0) {
283 tloge("pack old path fname err");
284 return -1;
285 }
286 }
287
288 return 0;
289 }
290
LoadTa(struct SecAgentControlType * secAgentControl)291 static void LoadTa(struct SecAgentControlType *secAgentControl)
292 {
293 int32_t ret;
294 char fname[MAX_PATH_LEN] = { 0 };
295
296 if (secAgentControl == NULL) {
297 tloge("secAgentControl is null\n");
298 return;
299 }
300
301 ret = GetTaPath(&(secAgentControl->TaSec.uuid), fname, MAX_PATH_LEN);
302 if (ret < 0) {
303 tloge("pack fname err\n");
304 secAgentControl->ret = -1;
305 return;
306 }
307 secAgentControl->ret = 0;
308 ret = SecFileLoadWork(g_secLoadAgentFd, (const char *)fname, LOAD_TA, &(secAgentControl->TaSec.uuid));
309 if (ret != 0) {
310 tloge("teec load TA app failed\n");
311 secAgentControl->ret = ret;
312 secAgentControl->error = errno;
313 return;
314 }
315 return;
316 }
317
SecLoadAgentWork(struct SecAgentControlType * secAgentControl)318 static void SecLoadAgentWork(struct SecAgentControlType *secAgentControl)
319 {
320 if (secAgentControl == NULL) {
321 tloge("secAgentControl is null\n");
322 return;
323 }
324 switch (secAgentControl->cmd) {
325 case LOAD_LIB_SEC:
326 LoadLib(secAgentControl);
327 break;
328 case LOAD_TA_SEC:
329 LoadTa(secAgentControl);
330 break;
331 case LOAD_SERVICE_SEC:
332 default:
333 tloge("gtask agent error cmd:%" PUBLIC "d\n", secAgentControl->cmd);
334 secAgentControl->ret = -1;
335 break;
336 }
337 }
338
SecfileLoadAgentThread(void * control)339 void *SecfileLoadAgentThread(void *control)
340 {
341 (void)prctl(PR_SET_NAME, "teecd_sec_load_agent", 0, 0, 0);
342 struct SecAgentControlType *secAgentControl = NULL;
343 if (control == NULL) {
344 tloge("control is NULL\n");
345 return NULL;
346 }
347 secAgentControl = (struct SecAgentControlType *)control;
348 if (g_secLoadAgentFd < 0) {
349 tloge("m_gtask_agent_fd is -1\n");
350 return NULL;
351 }
352 secAgentControl->magic = SECFILE_LOAD_AGENT_ID;
353 while (true) {
354 int ret = ioctl(g_secLoadAgentFd, (int)TC_NS_CLIENT_IOCTL_WAIT_EVENT, SECFILE_LOAD_AGENT_ID);
355 if (ret) {
356 tloge("gtask agent wait event failed, errno = %" PUBLIC "d\n", errno);
357 break;
358 }
359 SecLoadAgentWork(secAgentControl);
360
361 __asm__ volatile("isb");
362 __asm__ volatile("dsb sy");
363
364 secAgentControl->magic = SECFILE_LOAD_AGENT_ID;
365
366 __asm__ volatile("isb");
367 __asm__ volatile("dsb sy");
368 ret = ioctl(g_secLoadAgentFd, (int)TC_NS_CLIENT_IOCTL_SEND_EVENT_RESPONSE, SECFILE_LOAD_AGENT_ID);
369 if (ret) {
370 tloge("gtask agent send reponse failed\n");
371 break;
372 }
373 }
374 return NULL;
375 }
376