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