xref: /optee_os/core/tee/tee_pobj.c (revision 79f8990d9d28539864d8f97f9f1cb32e289e595f)
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