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
tee_pobj_check_access(uint32_t oflags,uint32_t nflags)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
tee_pobj_get(TEE_UUID * uuid,void * obj_id,uint32_t obj_id_len,uint32_t flags,enum tee_pobj_usage usage,const struct tee_file_operations * fops,struct tee_pobj ** obj)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
tee_pobj_create_final(struct tee_pobj * po)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
tee_pobj_release(struct tee_pobj * obj)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
tee_pobj_rename(struct tee_pobj * obj,void * obj_id,uint32_t obj_id_len)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