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