1 /*
2 * Copyright (C) 2023 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_load_dynamic.h"
14 #include <sys/stat.h> /* for stat */
15 #include <dirent.h>
16 #include <limits.h>
17
18 #include "securec.h"
19 #include "tc_ns_client.h"
20 #include "tee_log.h"
21 #include "secfile_load_agent.h"
22
23 #ifdef LOG_TAG
24 #undef LOG_TAG
25 #endif
26 #define LOG_TAG "teecd_load_dynamic"
27
28 #if defined(DYNAMIC_DRV_DIR) || defined(DYNAMIC_CRYPTO_DRV_DIR) || defined(DYNAMIC_SRV_DIR)
29 #define MAX_FILE_NAME_LEN 128
30
OpenDynamicDir(const char * dynDir)31 static DIR *OpenDynamicDir(const char *dynDir)
32 {
33 DIR *dir = opendir(dynDir);
34 if (dir == NULL) {
35 tlogw("open drv dir: %" PUBLIC "s failed\n", dynDir);
36 }
37
38 return dir;
39 }
40
endsWith(const char * str,const char * suffix)41 static int32_t endsWith(const char *str, const char *suffix)
42 {
43 size_t strLen = strnlen(str, MAX_FILE_NAME_LEN);
44 size_t suffixLen = strnlen(suffix, MAX_FILE_NAME_LEN);
45 if (suffixLen > strLen || strLen == 0 || strLen >= MAX_FILE_NAME_LEN || suffixLen == 0) {
46 return -1;
47 }
48
49 const char *ptr = str + (strLen - suffixLen);
50 if (strcmp(ptr, suffix) == 0) {
51 return 0;
52 }
53
54 return -1;
55 }
56
LoadOneFile(const char * dynDir,const struct dirent * dirFile,int32_t fd,uint32_t loadType)57 static int32_t LoadOneFile(const char *dynDir, const struct dirent *dirFile, int32_t fd, uint32_t loadType)
58 {
59 char name[MAX_FILE_NAME_LEN];
60 FILE *fp = NULL;
61 int32_t ret = -1;
62
63 if (endsWith(dirFile->d_name, ".sec") != 0) {
64 tloge("file name does not end with .sec\n");
65 goto END;
66 }
67
68 if (memset_s(name, sizeof(name), 0, sizeof(name)) != 0) {
69 tloge("mem set failed, name: %" PUBLIC "s, size: %" PUBLIC "u\n", name, (uint32_t)sizeof(name));
70 goto END;
71 }
72 if (strcat_s(name, MAX_FILE_NAME_LEN, dynDir) != 0) {
73 tloge("dir name too long: %" PUBLIC "s\n", dynDir);
74 goto END;
75 }
76 if (strcat_s(name, MAX_FILE_NAME_LEN, dirFile->d_name) != 0) {
77 tloge("drv name too long: %" PUBLIC "s\n", dirFile->d_name);
78 goto END;
79 }
80
81 fp = fopen(name, "r");
82 if (fp == NULL) {
83 tloge("open drv failed: %" PUBLIC "s\n", name);
84 goto END;
85 }
86
87 ret = LoadSecFile(fd, fp, loadType, NULL);
88 if (ret != 0) {
89 tloge("load dynamic failed: %" PUBLIC "s\n", name);
90 }
91
92 END:
93 if (fp != NULL) {
94 (void)fclose(fp);
95 }
96
97 return ret;
98 }
99
LoadOneDynamicDir(int32_t fd,const char * dynDir,uint32_t loadType)100 static void LoadOneDynamicDir(int32_t fd, const char *dynDir, uint32_t loadType)
101 {
102 int32_t ret;
103 struct dirent *dirFile = NULL;
104
105 DIR *dir = OpenDynamicDir(dynDir);
106 if (dir == NULL) {
107 tlogd("dynamic dir not exist\n");
108 return;
109 }
110 while ((dirFile = readdir(dir)) != NULL) {
111 if (dirFile->d_type != DT_REG) {
112 tlogd("no need to load\n");
113 continue;
114 }
115 ret = LoadOneFile(dynDir, dirFile, fd, loadType);
116 if (ret != 0) {
117 tlogd("load dynamic failed\n");
118 continue;
119 }
120 }
121 (void)closedir(dir);
122 }
123
LoadDynamicCryptoDir(void)124 void LoadDynamicCryptoDir(void)
125 {
126 #ifdef DYNAMIC_CRYPTO_DRV_DIR
127 int32_t fd = GetSecLoadAgentFd();
128 LoadOneDynamicDir(fd, DYNAMIC_CRYPTO_DRV_DIR, LOAD_DYNAMIC_DRV);
129 #endif
130 }
131
CheckPath(const char * drvPath,uint32_t drvPathLen,char * trustDrvPath)132 static int32_t CheckPath(const char *drvPath, uint32_t drvPathLen, char *trustDrvPath)
133 {
134 char trustDrvRootPath[PATH_MAX] = {0};
135 size_t optLen = strnlen(drvPath, MAX_FILE_NAME_LEN);
136 if (optLen == 0 || optLen >= MAX_FILE_NAME_LEN || drvPathLen != optLen) {
137 tloge("drv path is invalid\n");
138 return -1;
139 }
140
141 size_t rootLen = strnlen(DYNAMIC_DRV_DIR, MAX_FILE_NAME_LEN);
142 if (rootLen == 0 || rootLen >= MAX_FILE_NAME_LEN) {
143 tloge("drv root path is invalid\n");
144 return -1;
145 }
146
147 if (realpath(drvPath, trustDrvPath) == NULL) {
148 tloge("check realpath failed\n");
149 return -1;
150 }
151
152 if (realpath(DYNAMIC_DRV_DIR, trustDrvRootPath) == NULL) {
153 tloge("check realpath failed\n");
154 return -1;
155 }
156
157 rootLen = strnlen(trustDrvRootPath, MAX_FILE_NAME_LEN);
158 if (rootLen == 0 || rootLen >= MAX_FILE_NAME_LEN) {
159 tloge("drv root path is invalid\n");
160 return -1;
161 }
162
163 optLen = strnlen(trustDrvPath, MAX_FILE_NAME_LEN);
164 if (optLen <= rootLen || optLen >= MAX_FILE_NAME_LEN) {
165 tloge("drv path is invalid\n");
166 return -1;
167 }
168
169 if (strncmp(trustDrvPath, trustDrvRootPath, rootLen) != 0) {
170 tloge("drv path is invalid, %" PUBLIC "s, %" PUBLIC "s\n", trustDrvPath, trustDrvRootPath);
171 return -1;
172 }
173
174 return 0;
175 }
176
LoadDynamicDrvDir(const char * drvPath,uint32_t drvPathLen)177 void LoadDynamicDrvDir(const char *drvPath, uint32_t drvPathLen)
178 {
179 #ifdef DYNAMIC_DRV_DIR
180 int32_t fd = GetSecLoadAgentFd();
181 if (drvPathLen == 0 || drvPath == NULL) {
182 LoadOneDynamicDir(fd, DYNAMIC_DRV_DIR, LOAD_DYNAMIC_DRV);
183 } else {
184 char trustDrvPath[PATH_MAX] = {0};
185 if (CheckPath(drvPath, drvPathLen, trustDrvPath) != 0) {
186 tloge("check path failed\n");
187 return;
188 }
189 if (strcat_s(trustDrvPath, PATH_MAX, "/") != 0) {
190 tloge("add / to trust drv path failed\n");
191 return;
192 }
193
194 LoadOneDynamicDir(fd, drvPath, LOAD_DYNAMIC_DRV);
195 }
196 #endif
197 }
198
LoadDynamicSrvDir(void)199 void LoadDynamicSrvDir(void)
200 {
201 #ifdef DYNAMIC_SRV_DIR
202 int32_t fd = GetSecLoadAgentFd();
203 LoadOneDynamicDir(fd, DYNAMIC_SRV_DIR, LOAD_SERVICE);
204 #endif
205 }
206 #endif
207