1 /* 2 * Copyright (c) 2014, STMicroelectronics International N.V. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <kernel/mutex.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <tee/tee_pobj.h> 32 #include <trace.h> 33 34 static TAILQ_HEAD(tee_pobjs, tee_pobj) tee_pobjs = 35 TAILQ_HEAD_INITIALIZER(tee_pobjs); 36 static struct mutex pobjs_mutex = MUTEX_INITIALIZER; 37 38 static TEE_Result tee_pobj_check_access(uint32_t oflags, uint32_t nflags) 39 { 40 /* meta is exclusive */ 41 if ((oflags & TEE_DATA_FLAG_ACCESS_WRITE_META) || 42 (nflags & TEE_DATA_FLAG_ACCESS_WRITE_META)) 43 return TEE_ERROR_ACCESS_CONFLICT; 44 45 /* 46 * Excerpt of TEE Internal Core API Specification v1.1: 47 * If more than one handle is opened on the same object, and if any 48 * of these object handles was opened with the flag 49 * TEE_DATA_FLAG_ACCESS_READ, then all the object handles MUST have been 50 * opened with the flag TEE_DATA_FLAG_SHARE_READ 51 */ 52 if (((oflags & TEE_DATA_FLAG_ACCESS_READ) || 53 (nflags & TEE_DATA_FLAG_ACCESS_READ)) && 54 !((nflags & TEE_DATA_FLAG_SHARE_READ) && 55 (oflags & TEE_DATA_FLAG_SHARE_READ))) 56 return TEE_ERROR_ACCESS_CONFLICT; 57 58 /* 59 * Excerpt of TEE Internal Core API Specification v1.1: 60 * An object can be opened with only share flags, which locks the access 61 * to an object against a given mode. 62 * An object can be opened with no flag set, which completely locks all 63 * subsequent attempts to access the object 64 */ 65 if ((nflags & TEE_DATA_FLAG_SHARE_READ) != 66 (oflags & TEE_DATA_FLAG_SHARE_READ)) 67 return TEE_ERROR_ACCESS_CONFLICT; 68 69 /* Same on WRITE access */ 70 if (((oflags & TEE_DATA_FLAG_ACCESS_WRITE) || 71 (nflags & TEE_DATA_FLAG_ACCESS_WRITE)) && 72 !((nflags & TEE_DATA_FLAG_SHARE_WRITE) && 73 (oflags & TEE_DATA_FLAG_SHARE_WRITE))) 74 return TEE_ERROR_ACCESS_CONFLICT; 75 if ((nflags & TEE_DATA_FLAG_SHARE_WRITE) != 76 (oflags & TEE_DATA_FLAG_SHARE_WRITE)) 77 return TEE_ERROR_ACCESS_CONFLICT; 78 79 return TEE_SUCCESS; 80 } 81 82 TEE_Result tee_pobj_get(TEE_UUID *uuid, void *obj_id, uint32_t obj_id_len, 83 uint32_t flags, const struct tee_file_operations *fops, 84 struct tee_pobj **obj) 85 { 86 struct tee_pobj *o; 87 TEE_Result res; 88 89 *obj = NULL; 90 91 mutex_lock(&pobjs_mutex); 92 /* Check if file is open */ 93 TAILQ_FOREACH(o, &tee_pobjs, link) { 94 if ((obj_id_len == o->obj_id_len) && 95 (memcmp(obj_id, o->obj_id, obj_id_len) == 0) && 96 (memcmp(uuid, &o->uuid, sizeof(TEE_UUID)) == 0) && 97 (fops == o->fops)) { 98 *obj = o; 99 } 100 } 101 102 if (*obj) { 103 res = tee_pobj_check_access((*obj)->flags, flags); 104 if (res != TEE_SUCCESS) 105 *obj = NULL; 106 else 107 (*obj)->refcnt++; 108 goto out; 109 } 110 111 /* new file */ 112 o = calloc(sizeof(struct tee_pobj), 1); 113 if (!o) { 114 res = TEE_ERROR_OUT_OF_MEMORY; 115 goto out; 116 } 117 118 o->refcnt = 1; 119 memcpy(&o->uuid, uuid, sizeof(TEE_UUID)); 120 o->flags = flags; 121 o->fops = fops; 122 123 o->obj_id = malloc(obj_id_len); 124 if (o->obj_id == NULL) { 125 free(o); 126 res = TEE_ERROR_OUT_OF_MEMORY; 127 goto out; 128 } 129 memcpy(o->obj_id, obj_id, obj_id_len); 130 o->obj_id_len = obj_id_len; 131 132 TAILQ_INSERT_TAIL(&tee_pobjs, o, link); 133 *obj = o; 134 135 res = TEE_SUCCESS; 136 out: 137 mutex_unlock(&pobjs_mutex); 138 return res; 139 } 140 141 TEE_Result tee_pobj_release(struct tee_pobj *obj) 142 { 143 if (obj == NULL) 144 return TEE_ERROR_BAD_PARAMETERS; 145 146 mutex_lock(&pobjs_mutex); 147 obj->refcnt--; 148 if (obj->refcnt == 0) { 149 TAILQ_REMOVE(&tee_pobjs, obj, link); 150 free(obj->obj_id); 151 free(obj); 152 } 153 mutex_unlock(&pobjs_mutex); 154 155 return TEE_SUCCESS; 156 } 157 158 TEE_Result tee_pobj_rename(struct tee_pobj *obj, void *obj_id, 159 uint32_t obj_id_len) 160 { 161 TEE_Result res = TEE_SUCCESS; 162 void *new_obj_id = NULL; 163 164 if (obj == NULL || obj_id == NULL) 165 return TEE_ERROR_BAD_PARAMETERS; 166 167 mutex_lock(&pobjs_mutex); 168 if (obj->refcnt != 1) { 169 res = TEE_ERROR_BAD_STATE; 170 goto exit; 171 } 172 173 new_obj_id = malloc(obj_id_len); 174 if (new_obj_id == NULL) { 175 res = TEE_ERROR_OUT_OF_MEMORY; 176 goto exit; 177 } 178 memcpy(new_obj_id, obj_id, obj_id_len); 179 180 /* update internal data */ 181 free(obj->obj_id); 182 obj->obj_id = new_obj_id; 183 obj->obj_id_len = obj_id_len; 184 new_obj_id = NULL; 185 186 exit: 187 mutex_unlock(&pobjs_mutex); 188 free(new_obj_id); 189 return res; 190 } 191