1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2014, STMicroelectronics International N.V. 4 */ 5 6 #include <kernel/mutex.h> 7 #include <stdlib.h> 8 #include <string.h> 9 #include <tee/tee_pobj.h> 10 #include <trace.h> 11 12 static TAILQ_HEAD(tee_pobjs, tee_pobj) tee_pobjs = 13 TAILQ_HEAD_INITIALIZER(tee_pobjs); 14 static struct mutex pobjs_mutex = MUTEX_INITIALIZER; 15 static struct mutex pobjs_usage_mutex = MUTEX_INITIALIZER; 16 17 static bool pobj_need_usage_lock(struct tee_pobj *obj) 18 { 19 /* Only lock if we don't have exclusive access to the object */ 20 return obj->flags & (TEE_DATA_FLAG_SHARE_WRITE | 21 TEE_DATA_FLAG_SHARE_READ); 22 } 23 24 void tee_pobj_lock_usage(struct tee_pobj *obj) 25 { 26 if (pobj_need_usage_lock(obj)) 27 mutex_lock(&pobjs_usage_mutex); 28 } 29 30 void tee_pobj_unlock_usage(struct tee_pobj *obj) 31 { 32 if (pobj_need_usage_lock(obj)) 33 mutex_unlock(&pobjs_usage_mutex); 34 } 35 36 static TEE_Result tee_pobj_check_access(uint32_t oflags, uint32_t nflags) 37 { 38 /* meta is exclusive */ 39 if ((oflags & TEE_DATA_FLAG_ACCESS_WRITE_META) || 40 (nflags & TEE_DATA_FLAG_ACCESS_WRITE_META)) 41 return TEE_ERROR_ACCESS_CONFLICT; 42 43 /* 44 * Excerpt of TEE Internal Core API Specification v1.1: 45 * If more than one handle is opened on the same object, and if any 46 * of these object handles was opened with the flag 47 * TEE_DATA_FLAG_ACCESS_READ, then all the object handles MUST have been 48 * opened with the flag TEE_DATA_FLAG_SHARE_READ 49 */ 50 if (((oflags & TEE_DATA_FLAG_ACCESS_READ) || 51 (nflags & TEE_DATA_FLAG_ACCESS_READ)) && 52 !((nflags & TEE_DATA_FLAG_SHARE_READ) && 53 (oflags & TEE_DATA_FLAG_SHARE_READ))) 54 return TEE_ERROR_ACCESS_CONFLICT; 55 56 /* 57 * Excerpt of TEE Internal Core API Specification v1.1: 58 * An object can be opened with only share flags, which locks the access 59 * to an object against a given mode. 60 * An object can be opened with no flag set, which completely locks all 61 * subsequent attempts to access the object 62 */ 63 if ((nflags & TEE_DATA_FLAG_SHARE_READ) != 64 (oflags & TEE_DATA_FLAG_SHARE_READ)) 65 return TEE_ERROR_ACCESS_CONFLICT; 66 67 /* Same on WRITE access */ 68 if (((oflags & TEE_DATA_FLAG_ACCESS_WRITE) || 69 (nflags & TEE_DATA_FLAG_ACCESS_WRITE)) && 70 !((nflags & TEE_DATA_FLAG_SHARE_WRITE) && 71 (oflags & TEE_DATA_FLAG_SHARE_WRITE))) 72 return TEE_ERROR_ACCESS_CONFLICT; 73 if ((nflags & TEE_DATA_FLAG_SHARE_WRITE) != 74 (oflags & TEE_DATA_FLAG_SHARE_WRITE)) 75 return TEE_ERROR_ACCESS_CONFLICT; 76 77 return TEE_SUCCESS; 78 } 79 80 TEE_Result tee_pobj_get(TEE_UUID *uuid, void *obj_id, uint32_t obj_id_len, 81 uint32_t flags, enum tee_pobj_usage usage, 82 const struct tee_file_operations *fops, 83 struct tee_pobj **obj) 84 { 85 TEE_Result res = TEE_SUCCESS; 86 struct tee_pobj *o = NULL; 87 88 *obj = NULL; 89 90 mutex_lock(&pobjs_mutex); 91 /* Check if file is open */ 92 TAILQ_FOREACH(o, &tee_pobjs, link) { 93 if ((obj_id_len == o->obj_id_len) && 94 (memcmp(obj_id, o->obj_id, obj_id_len) == 0) && 95 (memcmp(uuid, &o->uuid, sizeof(TEE_UUID)) == 0) && 96 (fops == o->fops)) { 97 *obj = o; 98 } 99 } 100 101 if (*obj) { 102 if (usage == TEE_POBJ_USAGE_ENUM) { 103 (*obj)->refcnt++; 104 goto out; 105 } 106 if ((*obj)->creating || (usage == TEE_POBJ_USAGE_CREATE && 107 !(flags & TEE_DATA_FLAG_OVERWRITE))) { 108 res = TEE_ERROR_ACCESS_CONFLICT; 109 goto out; 110 } 111 res = tee_pobj_check_access((*obj)->flags, flags); 112 if (res == TEE_SUCCESS) 113 (*obj)->refcnt++; 114 goto out; 115 } 116 117 /* new file */ 118 o = calloc(1, sizeof(struct tee_pobj)); 119 if (!o) { 120 res = TEE_ERROR_OUT_OF_MEMORY; 121 goto out; 122 } 123 124 o->refcnt = 1; 125 memcpy(&o->uuid, uuid, sizeof(TEE_UUID)); 126 o->flags = flags; 127 o->fops = fops; 128 129 if (usage == TEE_POBJ_USAGE_CREATE) { 130 o->temporary = true; 131 o->creating = true; 132 } 133 134 o->obj_id = malloc(obj_id_len); 135 if (o->obj_id == NULL) { 136 free(o); 137 res = TEE_ERROR_OUT_OF_MEMORY; 138 goto out; 139 } 140 memcpy(o->obj_id, obj_id, obj_id_len); 141 o->obj_id_len = obj_id_len; 142 143 TAILQ_INSERT_TAIL(&tee_pobjs, o, link); 144 *obj = o; 145 146 res = TEE_SUCCESS; 147 out: 148 if (res != TEE_SUCCESS) 149 *obj = NULL; 150 mutex_unlock(&pobjs_mutex); 151 return res; 152 } 153 154 void tee_pobj_create_final(struct tee_pobj *po) 155 { 156 mutex_lock(&pobjs_mutex); 157 po->temporary = false; 158 po->creating = false; 159 mutex_unlock(&pobjs_mutex); 160 } 161 162 TEE_Result tee_pobj_release(struct tee_pobj *obj) 163 { 164 if (obj == NULL) 165 return TEE_ERROR_BAD_PARAMETERS; 166 167 mutex_lock(&pobjs_mutex); 168 obj->refcnt--; 169 if (obj->refcnt == 0) { 170 TAILQ_REMOVE(&tee_pobjs, obj, link); 171 free(obj->obj_id); 172 free(obj); 173 } 174 mutex_unlock(&pobjs_mutex); 175 176 return TEE_SUCCESS; 177 } 178 179 TEE_Result tee_pobj_rename(struct tee_pobj *obj, void *obj_id, 180 uint32_t obj_id_len) 181 { 182 TEE_Result res = TEE_SUCCESS; 183 void *new_obj_id = NULL; 184 185 if (obj == NULL || obj_id == NULL) 186 return TEE_ERROR_BAD_PARAMETERS; 187 188 mutex_lock(&pobjs_mutex); 189 if (obj->refcnt != 1) { 190 res = TEE_ERROR_BAD_STATE; 191 goto exit; 192 } 193 194 new_obj_id = malloc(obj_id_len); 195 if (new_obj_id == NULL) { 196 res = TEE_ERROR_OUT_OF_MEMORY; 197 goto exit; 198 } 199 memcpy(new_obj_id, obj_id, obj_id_len); 200 201 /* update internal data */ 202 free(obj->obj_id); 203 obj->obj_id = new_obj_id; 204 obj->obj_id_len = obj_id_len; 205 new_obj_id = NULL; 206 207 exit: 208 mutex_unlock(&pobjs_mutex); 209 free(new_obj_id); 210 return res; 211 } 212