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