xref: /optee_os/core/tee/tee_pobj.c (revision 5ca2c36555d169a2be60964e2cbe39340c5245a4)
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 
pobj_need_usage_lock(struct tee_pobj * obj)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 
tee_pobj_lock_usage(struct tee_pobj * obj)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 
tee_pobj_unlock_usage(struct tee_pobj * obj)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 
tee_pobj_check_access(uint32_t oflags,uint32_t nflags)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 
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)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 
tee_pobj_create_final(struct tee_pobj * po)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 
tee_pobj_release(struct tee_pobj * obj)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 
tee_pobj_rename(struct tee_pobj * obj,void * obj_id,uint32_t obj_id_len)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