• 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 #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