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