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_app_load.h"
14 #include <fcntl.h>
15 #include <limits.h>
16 #include <securec.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <sys/mman.h> /* for mmap */
21 #include <sys/ioctl.h> /* for ioctl */
22 #include <sys/stat.h>
23 #include <sys/types.h> /* for open close */
24 #include "load_sec_file.h"
25 #include "tc_ns_client.h"
26 #include "tee_client_inner.h"
27 #include "tee_log.h"
28
29 #ifdef LOG_TAG
30 #undef LOG_TAG
31 #endif
32 #define LOG_TAG "teec_app_load"
33
34 #define MAX_PATH_LEN 256
35
36 static int32_t TEEC_ReadApp(const TaFileInfo *taFile, const char *loadFile, bool defaultPath,
37 TC_NS_ClientContext *cliContext);
38
TEEC_GetApp(const TaFileInfo * taFile,const TEEC_UUID * srvUuid,TC_NS_ClientContext * cliContext)39 int32_t TEEC_GetApp(const TaFileInfo *taFile, const TEEC_UUID *srvUuid, TC_NS_ClientContext *cliContext)
40 {
41 int32_t ret;
42
43 if ((taFile == NULL) || (srvUuid == NULL) || (cliContext == NULL)) {
44 tloge("param is null\n");
45 return -1;
46 }
47
48 /* get file name and file patch */
49 bool condition = (taFile->taPath != NULL) && (strlen((const char *)taFile->taPath) < MAX_PATH_LEN) &&
50 strstr((const char *)taFile->taPath, ".sec");
51 if (condition) {
52 ret = TEEC_ReadApp(taFile, (const char *)taFile->taPath, false, cliContext);
53 if (ret < 0) {
54 tlogi("ta path is not NULL, ta file will be readed by driver\n");
55 ret = 0;
56 }
57 } else {
58 char fileName[MAX_FILE_NAME_LEN] = { 0 };
59 char tempName[MAX_FILE_PATH_LEN + MAX_FILE_NAME_LEN + MAX_FILE_EXT_LEN] = { 0 };
60 const char *filePath = TEE_FEIMA_DEFAULT_PATH;
61 ret = snprintf_s(fileName, sizeof(fileName), sizeof(fileName) - 1,
62 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", srvUuid->timeLow, srvUuid->timeMid,
63 srvUuid->timeHiAndVersion, srvUuid->clockSeqAndNode[0], srvUuid->clockSeqAndNode[1],
64 srvUuid->clockSeqAndNode[2], srvUuid->clockSeqAndNode[3], srvUuid->clockSeqAndNode[4],
65 srvUuid->clockSeqAndNode[5], srvUuid->clockSeqAndNode[6], srvUuid->clockSeqAndNode[7]);
66 if (ret < 0) {
67 tloge("get file name err\n");
68 return -1;
69 }
70
71 size_t filePathLen = strnlen(filePath, MAX_FILE_PATH_LEN);
72 filePathLen = filePathLen + strnlen(fileName, MAX_FILE_NAME_LEN) + MAX_FILE_EXT_LEN;
73 if (snprintf_s(tempName, sizeof(tempName), filePathLen, "%s/%s.sec", filePath, fileName) < 0) {
74 tloge("file path too long\n");
75 return -1;
76 }
77
78 if (TEEC_ReadApp(taFile, (const char *)tempName, true, cliContext) != 0) {
79 tlogi("teec load app from feima path failed, try to load from old path\n");
80 memset_s(tempName, sizeof(tempName), 0, sizeof(tempName));
81 if (snprintf_s(tempName, sizeof(tempName), filePathLen, "%s/%s.sec", TEE_DEFAULT_PATH, fileName) < 0) {
82 return -1;
83 }
84
85 if (TEEC_ReadApp(taFile, (const char *)tempName, true, cliContext) < 0) {
86 tloge("teec load app erro\n");
87 return -1;
88 }
89 /* TA file is not in the default path and feima default path, maybe it's a build-in TA */
90 ret = 0;
91 }
92 }
93
94 return ret;
95 }
96
GetTaVersion(FILE * fp,uint32_t * taHeadLen,uint32_t * version,uint32_t * contextLen,uint32_t * totalImgLen)97 static int32_t GetTaVersion(FILE *fp, uint32_t *taHeadLen, uint32_t *version,
98 uint32_t *contextLen, uint32_t *totalImgLen)
99 {
100 int32_t ret;
101 TaImageHdrV3 imgHdr = { { 0 }, 0, 0 };
102
103 if (fp == NULL) {
104 tloge("invalid fp\n");
105 return -1;
106 }
107
108 /* get magic-num & version-num */
109 ret = (int32_t)fread(&imgHdr, sizeof(imgHdr), 1, fp);
110 if (ret != 1) {
111 tloge("read file failed, ret=%" PUBLIC "d, error=%" PUBLIC "d\n", ret, ferror(fp));
112 return -1;
113 }
114
115 bool condition = (imgHdr.imgIdentity.magicNum1 == TA_HEAD_MAGIC1) &&
116 (imgHdr.imgIdentity.magicNum2 == TA_HEAD_MAGIC2 ||
117 imgHdr.imgIdentity.magicNum2 == TA_OH_HEAD_MAGIC2) &&
118 (imgHdr.imgIdentity.versionNum > 1);
119 if (condition) {
120 tlogd("new verison ta\n");
121 *taHeadLen = sizeof(TeecTaHead);
122 *version = imgHdr.imgIdentity.versionNum;
123 if (*version >= CIPHER_LAYER_VERSION) {
124 *contextLen = imgHdr.contextLen;
125 *totalImgLen = *contextLen + sizeof(imgHdr);
126 } else {
127 ret = fseek(fp, sizeof(imgHdr.imgIdentity), SEEK_SET);
128 if (ret != 0) {
129 tloge("fseek error\n");
130 return -1;
131 }
132 }
133 } else {
134 /* read the oldverison head again */
135 tlogd("old verison ta\n");
136 *taHeadLen = sizeof(TeecImageHead);
137 ret = fseek(fp, 0, SEEK_SET);
138 if (ret != 0) {
139 tloge("fseek error\n");
140 return -1;
141 }
142 }
143 return 0;
144 }
145
TEEC_GetImageLenth(FILE * fp,uint32_t * imgLen)146 static int32_t TEEC_GetImageLenth(FILE *fp, uint32_t *imgLen)
147 {
148 int32_t ret;
149 TeecImageHead imageHead = { 0 };
150 uint32_t totalImgLen;
151 uint32_t taHeadLen = 0;
152 uint32_t readSize;
153 uint32_t version = 0;
154 uint32_t contextLen = 0;
155
156 /* decide the TA verison */
157 ret = GetTaVersion(fp, &taHeadLen, &version, &contextLen, &totalImgLen);
158 if (ret != 0) {
159 tloge("get Ta version failed\n");
160 return ret;
161 }
162
163 if (version >= CIPHER_LAYER_VERSION) {
164 goto CHECK_LENTH;
165 }
166
167 /* get image head */
168 readSize = (uint32_t)fread(&imageHead, sizeof(TeecImageHead), 1, fp);
169 if (readSize != 1) {
170 tloge("read file failed, err=%" PUBLIC "u\n", readSize);
171 return -1;
172 }
173 contextLen = imageHead.contextLen;
174 totalImgLen = contextLen + taHeadLen;
175
176 CHECK_LENTH:
177 /* for no overflow */
178 if ((contextLen > MAX_IMAGE_LEN) || (totalImgLen > MAX_IMAGE_LEN)) {
179 tloge("check img size failed\n");
180 return -1;
181 }
182
183 ret = fseek(fp, 0, SEEK_SET);
184 if (ret != 0) {
185 tloge("fseek error\n");
186 return -1;
187 }
188
189 *imgLen = totalImgLen;
190 return 0;
191 }
192
TEEC_DoReadApp(FILE * fp,TC_NS_ClientContext * cliContext)193 static int32_t TEEC_DoReadApp(FILE *fp, TC_NS_ClientContext *cliContext)
194 {
195 uint32_t totalImgLen = 0;
196
197 /* get magic-num & version-num */
198 int32_t ret = TEEC_GetImageLenth(fp, &totalImgLen);
199 if (ret) {
200 tloge("get image lenth fail\n");
201 return -1;
202 }
203
204 if (totalImgLen == 0 || totalImgLen > MAX_IMAGE_LEN) {
205 tloge("image lenth invalid\n");
206 return -1;
207 }
208
209 /* alloc a less than 8M heap memory, it needn't slice. */
210 char *fileBuffer = malloc(totalImgLen);
211 if (fileBuffer == NULL) {
212 tloge("alloc TA file buffer(size=%" PUBLIC "u) failed\n", totalImgLen);
213 return -1;
214 }
215
216 /* read total ta file to file buffer */
217 uint32_t readSize = (uint32_t)fread(fileBuffer, 1, totalImgLen, fp);
218 if (readSize != totalImgLen) {
219 tloge("read ta file failed, read size/total size=%" PUBLIC "u/%" PUBLIC "u\n", readSize, totalImgLen);
220 free(fileBuffer);
221 return -1;
222 }
223 cliContext->file_size = totalImgLen;
224 cliContext->file_buffer = fileBuffer;
225 return 0;
226 }
227
TEEC_ReadApp(const TaFileInfo * taFile,const char * loadFile,bool defaultPath,TC_NS_ClientContext * cliContext)228 static int32_t TEEC_ReadApp(const TaFileInfo *taFile, const char *loadFile, bool defaultPath,
229 TC_NS_ClientContext *cliContext)
230 {
231 int32_t ret = 0;
232 int32_t retBuildInTa = 1;
233 FILE *fp = NULL;
234 FILE *fpTmp = NULL;
235 char realLoadFile[PATH_MAX + 1] = { 0 };
236
237 if (taFile->taFp != NULL) {
238 fp = taFile->taFp;
239 tlogd("libteec_vendor-read_app: get fp from ta fp\n");
240 goto READ_APP;
241 }
242
243 if (realpath(loadFile, realLoadFile) == NULL) {
244 if (!defaultPath) {
245 tloge("get file realpath error%" PUBLIC "d\n", errno);
246 return -1;
247 }
248
249 /* maybe it's a built-in TA */
250 tlogd("maybe it's a built-in TA or file is not in default path\n");
251 return retBuildInTa;
252 }
253
254 /* open image file */
255 fpTmp = fopen(realLoadFile, "r");
256 if (fpTmp == NULL) {
257 tloge("open file error%" PUBLIC "d\n", errno);
258 return -1;
259 }
260 fp = fpTmp;
261
262 READ_APP:
263 ret = TEEC_DoReadApp(fp, cliContext);
264 if (ret != 0) {
265 tloge("do read app fail\n");
266 }
267
268 if (fpTmp != NULL) {
269 fclose(fpTmp);
270 }
271
272 return ret;
273 }
274
TEEC_LoadSecfile(const char * filePath,int tzFd,FILE * fp)275 int32_t TEEC_LoadSecfile(const char *filePath, int tzFd, FILE *fp)
276 {
277 int ret;
278 FILE *fpUsable = NULL;
279 bool checkValue = (tzFd < 0 || filePath == NULL);
280 FILE *fpCur = NULL;
281
282 if (checkValue) {
283 tloge("Param err!\n");
284 return -1;
285 }
286 if (fp == NULL) {
287 char realPath[PATH_MAX + 1] = { 0 };
288 if (realpath(filePath, realPath) != NULL) {
289 fpCur = fopen(realPath, "r");
290 }
291 if (fpCur == NULL) {
292 tloge("realpath open file erro%" PUBLIC "d, path=%" PUBLIC "s\n", errno, filePath);
293 return -1;
294 }
295 fpUsable = fpCur;
296 } else {
297 fpUsable = fp;
298 }
299 ret = LoadSecFile(tzFd, fpUsable, LOAD_LIB, NULL);
300 if (fpCur != NULL) {
301 fclose(fpCur);
302 }
303 return ret;
304 }
305