• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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