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 #include "tee_obj.h"
13 #include <dlist.h>
14 #include <securec.h>
15
16 #include "tee_mem_mgmt_api.h"
17 #include "tee_log.h"
18 #include "ta_framework.h"
19 #include "tee_fs.h"
20 #include "tee_trusted_storage_api.h"
21
22 #define OBJ_ROBUST_MAX_VALUE 1
23 #define OBJ_SUCCESS 0
24 #define OBJ_ERROR (-1)
25 #define TEE_OBJECT_FREE_MAGIC 0xabcdabcd
26
27 struct valid_objects {
28 TEE_ObjectHandle obj_id;
29 TEE_ObjectHandle first_obj_link;
30 struct dlist_node list;
31 };
32
33 static struct dlist_node g_object_head;
34 static pthread_mutex_t g_object_mutex;
35
36 struct valid_enum_objects {
37 TEE_ObjectEnumHandle enum_obj_id;
38 struct dlist_node list;
39 };
40 static struct dlist_node g_enum_obj_info_list;
41
42 #define MEMORY_DUMP_BLOCK_SIZE 16
43 #define MEMORY_DUMP_LINE_SIZE 64
44
tee_memory_dump(const uint8_t * data,uint32_t count)45 void tee_memory_dump(const uint8_t *data, uint32_t count)
46 {
47 // backward compatibility
48 (void)data;
49 (void)count;
50 }
51
tee_obj_setname(TEE_ObjectHandle object,const uint8_t * name,uint32_t len)52 TEE_Result tee_obj_setname(TEE_ObjectHandle object, const uint8_t *name, uint32_t len)
53 {
54 errno_t rc;
55
56 if ((object == NULL) || (name == NULL) || (len > (HASH_NAME_BUFF_LEN - 1)))
57 return TEE_ERROR_BAD_PARAMETERS;
58
59 rc = memmove_s(object->dataName, sizeof(object->dataName), name, len);
60 if (rc != EOK) {
61 tloge("move name is failed, name : %s\n", name);
62 return TEE_ERROR_SECURITY;
63 }
64
65 object->dataName[len] = '\0';
66 object->dataLen = len;
67
68 return TEE_SUCCESS;
69 }
70
tee_obj_new(TEE_ObjectHandle * object)71 TEE_Result tee_obj_new(TEE_ObjectHandle *object)
72 {
73 if (object == NULL)
74 return TEE_ERROR_BAD_PARAMETERS;
75
76 *object = TEE_Malloc(sizeof(struct __TEE_ObjectHandle) + sizeof(TEE_ObjectInfo), 0);
77 if (*object == NULL) {
78 tloge("not available to allocate the object handle\n");
79 return TEE_ERROR_OUT_OF_MEMORY;
80 }
81
82 (*object)->ObjectInfo = (TEE_ObjectInfo *)(*object + 1);
83
84 return TEE_SUCCESS;
85 }
86
tee_obj_free(TEE_ObjectHandle * object)87 TEE_Result tee_obj_free(TEE_ObjectHandle *object)
88 {
89 if ((object == NULL) || (*object == NULL))
90 return TEE_ERROR_BAD_PARAMETERS;
91
92 (*object)->infoattrfd = (void *)TEE_OBJECT_FREE_MAGIC;
93
94 TEE_Free(*object);
95 *object = NULL;
96
97 return TEE_SUCCESS;
98 }
99
tee_obj_init(void)100 TEE_Result tee_obj_init(void)
101 {
102 (void)pthread_mutex_init(&g_object_mutex, NULL);
103 dlist_init(&g_object_head);
104 dlist_init(&g_enum_obj_info_list);
105 return TEE_SUCCESS;
106 }
107
mutex_lock_ops(pthread_mutex_t * mutex)108 int mutex_lock_ops(pthread_mutex_t *mutex)
109 {
110 int ret;
111 if (mutex == NULL)
112 return OBJ_ERROR;
113
114 ret = pthread_mutex_lock(mutex);
115 if (ret == EOWNERDEAD) /* owner died, use consistent to recover and lock the mutex */
116 return pthread_mutex_consistent(mutex);
117
118 return ret;
119 }
120
dump_object(void)121 void dump_object(void)
122 {
123 struct valid_objects *vo = NULL;
124 TEE_ObjectHandle object = NULL;
125
126 if (dlist_empty(&g_object_head)) {
127 tlogd("not found any valid obj in list\n");
128 return;
129 }
130
131 if (mutex_lock_ops(&g_object_mutex) != 0) {
132 tloge("mutex lock ops is failed\n");
133 return;
134 }
135 dlist_for_each_entry(vo, &g_object_head, struct valid_objects, list) {
136 object = vo->obj_id;
137 if (object && object->ObjectInfo != 0)
138 tlogd("obj_id=0x%x, type=0x%x, fileName=%s\n", vo->obj_id, object->ObjectInfo->objectType,
139 object->dataName);
140 }
141 (void)pthread_mutex_unlock(&g_object_mutex); /* no need to verify return value here */
142 }
143
check_object(const TEE_ObjectHandle object)144 TEE_Result check_object(const TEE_ObjectHandle object)
145 {
146 struct valid_objects *vo = NULL;
147
148 if (object == NULL)
149 return TEE_ERROR_BAD_PARAMETERS;
150
151 if (mutex_lock_ops(&g_object_mutex) != 0) {
152 tloge("mutex lock ops is failed\n");
153 return TEE_ERROR_GENERIC;
154 }
155 dlist_for_each_entry(vo, &g_object_head, struct valid_objects, list) {
156 if (vo->obj_id == object) {
157 (void)pthread_mutex_unlock(&g_object_mutex); /* no need to verify return value here */
158 return TEE_SUCCESS;
159 }
160 }
161 (void)pthread_mutex_unlock(&g_object_mutex); /* no need to verify return value here */
162 return TEE_ERROR_BAD_PARAMETERS;
163 }
164
add_object(TEE_ObjectHandle object)165 TEE_Result add_object(TEE_ObjectHandle object)
166 {
167 struct valid_objects *new_vo = NULL;
168 struct valid_objects *tmp_vo = NULL;
169 TEE_ObjectHandle tmp_object = NULL;
170
171 if (object == NULL)
172 return TEE_ERROR_BAD_PARAMETERS;
173
174 new_vo = TEE_Malloc(sizeof(*new_vo), 0);
175 if (new_vo == NULL) {
176 tloge("apply new valid object failed\n");
177 return TEE_ERROR_OUT_OF_MEMORY;
178 }
179
180 /* Init new list entry */
181 dlist_init(&new_vo->list);
182 new_vo->obj_id = object;
183 new_vo->first_obj_link = NULL;
184
185 if (mutex_lock_ops(&g_object_mutex) != 0) {
186 tloge("mutex lock ops failed\n");
187 TEE_Free(new_vo);
188 return TEE_ERROR_GENERIC;
189 }
190 /* Find the first same object for permission checking in future */
191 dlist_for_each_entry(tmp_vo, &g_object_head, struct valid_objects, list) {
192 tmp_object = tmp_vo->obj_id;
193 if ((tmp_object != NULL) && (tmp_object->dataLen == object->dataLen) &&
194 (TEE_MemCompare(tmp_object->dataName, object->dataName, object->dataLen) == 0)) {
195 new_vo->first_obj_link = tmp_vo->obj_id;
196 break;
197 }
198 }
199
200 /* Insert to list head */
201 dlist_insert_head(&new_vo->list, &g_object_head);
202 (void)pthread_mutex_unlock(&g_object_mutex); /* no need to verify return value here */
203
204 return TEE_SUCCESS;
205 }
206
delete_object(const TEE_ObjectHandle object)207 TEE_Result delete_object(const TEE_ObjectHandle object)
208 {
209 struct valid_objects *vo = NULL;
210 struct valid_objects *tmp = NULL;
211
212 if (object == NULL)
213 return TEE_ERROR_BAD_PARAMETERS;
214
215 if (check_object(object) != TEE_SUCCESS) {
216 tloge("object is invalid\n");
217 return TEE_ERROR_BAD_PARAMETERS;
218 }
219
220 if (mutex_lock_ops(&g_object_mutex) != 0) {
221 tloge("mutex lock ops failed\n");
222 return TEE_ERROR_GENERIC;
223 }
224 dlist_for_each_entry_safe(vo, tmp, &g_object_head, struct valid_objects, list) {
225 if (vo->obj_id == object) {
226 dlist_delete(&vo->list);
227 TEE_Free(vo);
228 vo = NULL;
229 break;
230 }
231 }
232 (void)pthread_mutex_unlock(&g_object_mutex); /* no need to verify return value here */
233 return TEE_SUCCESS;
234 }
235
236 struct object_permission {
237 bool r;
238 bool w;
239 bool rs;
240 bool ws;
241 bool ro;
242 bool wo;
243 };
244
245 #define perm_bool(value) (((value) != 0) ? true : false)
246
check_permission(const char * object_id,size_t object_id_len,uint32_t flags)247 TEE_Result check_permission(const char *object_id, size_t object_id_len, uint32_t flags)
248 {
249 struct valid_objects *vo = NULL;
250 struct object_permission perm = { 0 };
251 bool perm_check_ret = false;
252 TEE_ObjectHandle object = NULL;
253
254 if (object_id == NULL)
255 return TEE_ERROR_BAD_PARAMETERS;
256
257 if (mutex_lock_ops(&g_object_mutex) != 0) {
258 tloge("mutex lock ops failed\n");
259 return TEE_ERROR_GENERIC;
260 }
261 dlist_for_each_entry(vo, &g_object_head, struct valid_objects, list) {
262 if (vo->first_obj_link != NULL)
263 object = vo->first_obj_link;
264 else
265 object = vo->obj_id;
266
267 if ((object != NULL) && (object->dataLen == object_id_len) &&
268 (TEE_MemCompare(object->dataName, object_id, object_id_len) == 0)) {
269 /* check permission */
270 if ((object->ObjectInfo == NULL) ||
271 ((object->ObjectInfo->handleFlags & TEE_DATA_FLAG_ACCESS_WRITE_META) != 0)) {
272 (void)pthread_mutex_unlock(&g_object_mutex); /* no need to verify return value here */
273 return TEE_ERROR_ACCESS_CONFLICT;
274 }
275 perm.r = perm_bool(flags & TEE_DATA_FLAG_ACCESS_READ) && perm_bool(flags & TEE_DATA_FLAG_SHARE_READ);
276 perm.w = perm_bool(flags & TEE_DATA_FLAG_ACCESS_WRITE) && perm_bool(flags & TEE_DATA_FLAG_SHARE_WRITE);
277 perm.ro = perm_bool(flags & TEE_DATA_FLAG_ACCESS_READ) && perm_bool(flags);
278 perm.wo = perm_bool(flags & TEE_DATA_FLAG_ACCESS_WRITE) && perm_bool(flags);
279 perm.ws = perm_bool(object->ObjectInfo->handleFlags & TEE_DATA_FLAG_SHARE_WRITE);
280 perm.rs = perm_bool(object->ObjectInfo->handleFlags & TEE_DATA_FLAG_SHARE_READ);
281 perm_check_ret = ((perm.r && perm.rs && (!perm.wo)) || (perm.w && perm.ws && (!perm.ro)) ||
282 (perm.r && perm.rs && perm.w && perm.ws));
283
284 if (!perm_check_ret) {
285 tloge("can't share\n");
286 (void)pthread_mutex_unlock(&g_object_mutex); /* no need to verify return value here */
287 return TEE_ERROR_ACCESS_CONFLICT;
288 }
289 }
290 }
291 (void)pthread_mutex_unlock(&g_object_mutex); /* no need to verify return value here */
292 return TEE_SUCCESS;
293 }
294
check_enum_object_in_list(const TEE_ObjectEnumHandle object)295 TEE_Result check_enum_object_in_list(const TEE_ObjectEnumHandle object)
296 {
297 struct valid_enum_objects *valid_enum_obj = NULL;
298
299 if (object == NULL)
300 return TEE_ERROR_BAD_PARAMETERS;
301
302 dlist_for_each_entry(valid_enum_obj, &g_enum_obj_info_list, struct valid_enum_objects, list) {
303 if (valid_enum_obj->enum_obj_id == object)
304 return TEE_SUCCESS;
305 }
306
307 return TEE_ERROR_BAD_PARAMETERS;
308 }
309
add_enum_object_in_list(const TEE_ObjectEnumHandle object)310 TEE_Result add_enum_object_in_list(const TEE_ObjectEnumHandle object)
311 {
312 struct valid_enum_objects *new_enum_obj = NULL;
313
314 if (object == NULL)
315 return TEE_ERROR_BAD_PARAMETERS;
316
317 new_enum_obj = TEE_Malloc(sizeof(*new_enum_obj), 0);
318 if (new_enum_obj == NULL) {
319 tloge("apply new valid object failed\n");
320 return TEE_ERROR_OUT_OF_MEMORY;
321 }
322
323 /* Init new list entry */
324 dlist_init(&new_enum_obj->list);
325 new_enum_obj->enum_obj_id = object;
326
327 dlist_insert_head(&new_enum_obj->list, &g_enum_obj_info_list);
328 return TEE_SUCCESS;
329 }
330
delete_enum_object_in_list(const TEE_ObjectEnumHandle object)331 void delete_enum_object_in_list(const TEE_ObjectEnumHandle object)
332 {
333 struct valid_enum_objects *valid_enum_obj = NULL;
334 struct valid_enum_objects *tmp_enum_obj = NULL;
335
336 if (object == NULL)
337 return;
338
339 dlist_for_each_entry_safe(valid_enum_obj, tmp_enum_obj, &g_enum_obj_info_list, struct valid_enum_objects, list) {
340 if (valid_enum_obj->enum_obj_id == object) {
341 dlist_delete(&valid_enum_obj->list);
342 TEE_Free(valid_enum_obj);
343 break;
344 }
345 }
346 }
347