xref: /optee_os/core/tee/tee_pobj.c (revision 75200110483dcee11cdcf4cef3d0ac4d92f63c14)
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, bool temporary,
84 			const struct tee_file_operations *fops,
85 			struct tee_pobj **obj)
86 {
87 	struct tee_pobj *o;
88 	TEE_Result res;
89 
90 	*obj = NULL;
91 
92 	mutex_lock(&pobjs_mutex);
93 	/* Check if file is open */
94 	TAILQ_FOREACH(o, &tee_pobjs, link) {
95 		if ((obj_id_len == o->obj_id_len) &&
96 		    (memcmp(obj_id, o->obj_id, obj_id_len) == 0) &&
97 		    (memcmp(uuid, &o->uuid, sizeof(TEE_UUID)) == 0) &&
98 		    (fops == o->fops)) {
99 			*obj = o;
100 		}
101 	}
102 
103 	if (*obj) {
104 		if (temporary != (*obj)->temporary) {
105 			res = TEE_ERROR_ACCESS_CONFLICT;
106 			goto out;
107 		}
108 		res = tee_pobj_check_access((*obj)->flags, flags);
109 		if (res == TEE_SUCCESS)
110 			(*obj)->refcnt++;
111 		goto out;
112 	}
113 
114 	/* new file */
115 	o = calloc(1, sizeof(struct tee_pobj));
116 	if (!o) {
117 		res = TEE_ERROR_OUT_OF_MEMORY;
118 		goto out;
119 	}
120 
121 	o->refcnt = 1;
122 	memcpy(&o->uuid, uuid, sizeof(TEE_UUID));
123 	o->flags = flags;
124 	o->fops = fops;
125 	o->temporary = temporary;
126 
127 	o->obj_id = malloc(obj_id_len);
128 	if (o->obj_id == NULL) {
129 		free(o);
130 		res = TEE_ERROR_OUT_OF_MEMORY;
131 		goto out;
132 	}
133 	memcpy(o->obj_id, obj_id, obj_id_len);
134 	o->obj_id_len = obj_id_len;
135 
136 	TAILQ_INSERT_TAIL(&tee_pobjs, o, link);
137 	*obj = o;
138 
139 	res = TEE_SUCCESS;
140 out:
141 	if (res != TEE_SUCCESS)
142 		*obj = NULL;
143 	mutex_unlock(&pobjs_mutex);
144 	return res;
145 }
146 
147 TEE_Result tee_pobj_release(struct tee_pobj *obj)
148 {
149 	if (obj == NULL)
150 		return TEE_ERROR_BAD_PARAMETERS;
151 
152 	mutex_lock(&pobjs_mutex);
153 	obj->refcnt--;
154 	if (obj->refcnt == 0) {
155 		TAILQ_REMOVE(&tee_pobjs, obj, link);
156 		free(obj->obj_id);
157 		free(obj);
158 	}
159 	mutex_unlock(&pobjs_mutex);
160 
161 	return TEE_SUCCESS;
162 }
163 
164 TEE_Result tee_pobj_rename(struct tee_pobj *obj, void *obj_id,
165 			   uint32_t obj_id_len)
166 {
167 	TEE_Result res = TEE_SUCCESS;
168 	void *new_obj_id = NULL;
169 
170 	if (obj == NULL || obj_id == NULL)
171 		return TEE_ERROR_BAD_PARAMETERS;
172 
173 	mutex_lock(&pobjs_mutex);
174 	if (obj->refcnt != 1) {
175 		res = TEE_ERROR_BAD_STATE;
176 		goto exit;
177 	}
178 
179 	new_obj_id = malloc(obj_id_len);
180 	if (new_obj_id == NULL) {
181 		res = TEE_ERROR_OUT_OF_MEMORY;
182 		goto exit;
183 	}
184 	memcpy(new_obj_id, obj_id, obj_id_len);
185 
186 	/* update internal data */
187 	free(obj->obj_id);
188 	obj->obj_id = new_obj_id;
189 	obj->obj_id_len = obj_id_len;
190 	new_obj_id = NULL;
191 
192 exit:
193 	mutex_unlock(&pobjs_mutex);
194 	free(new_obj_id);
195 	return res;
196 }
197