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