xref: /linux/drivers/tee/optee/supp.c (revision ba3e43a9e601636f5edb54e259a74f96ca3b8fd8)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2015, Linaro Limited
4  */
5 #include <linux/device.h>
6 #include <linux/slab.h>
7 #include <linux/uaccess.h>
8 #include "optee_private.h"
9 
10 struct optee_supp_req {
11 	struct list_head link;
12 
13 	int id;
14 
15 	bool in_queue;
16 	bool processed;
17 
18 	u32 func;
19 	u32 ret;
20 	size_t num_params;
21 	struct tee_param *param;
22 
23 	struct completion c;
24 };
25 
26 /* It is temporary request used for revoked pending request in supp->idr. */
27 #define INVALID_REQ_PTR ((struct optee_supp_req *)ERR_PTR(-EBADF))
28 
optee_supp_init(struct optee_supp * supp)29 void optee_supp_init(struct optee_supp *supp)
30 {
31 	memset(supp, 0, sizeof(*supp));
32 	mutex_init(&supp->mutex);
33 	init_completion(&supp->reqs_c);
34 	idr_init(&supp->idr);
35 	INIT_LIST_HEAD(&supp->reqs);
36 	supp->req_id = -1;
37 }
38 
optee_supp_uninit(struct optee_supp * supp)39 void optee_supp_uninit(struct optee_supp *supp)
40 {
41 	mutex_destroy(&supp->mutex);
42 	idr_destroy(&supp->idr);
43 }
44 
optee_supp_release(struct optee_supp * supp)45 void optee_supp_release(struct optee_supp *supp)
46 {
47 	int id;
48 	struct optee_supp_req *req;
49 
50 	mutex_lock(&supp->mutex);
51 
52 	/* Abort all request */
53 	idr_for_each_entry(&supp->idr, req, id) {
54 		idr_remove(&supp->idr, id);
55 		/* Skip if request was already marked invalid */
56 		if (IS_ERR(req))
57 			continue;
58 
59 		/* For queued requests where supplicant has not seen it */
60 		if (req->in_queue) {
61 			list_del(&req->link);
62 			req->in_queue = false;
63 		}
64 
65 		req->processed = true;
66 		req->ret = TEEC_ERROR_COMMUNICATION;
67 		complete(&req->c);
68 	}
69 
70 	supp->ctx = NULL;
71 	supp->req_id = -1;
72 
73 	mutex_unlock(&supp->mutex);
74 }
75 
76 /**
77  * optee_supp_thrd_req() - request service from supplicant
78  * @ctx:	context doing the request
79  * @func:	function requested
80  * @num_params:	number of elements in @param array
81  * @param:	parameters for function
82  *
83  * Returns result of operation to be passed to secure world
84  */
optee_supp_thrd_req(struct tee_context * ctx,u32 func,size_t num_params,struct tee_param * param)85 u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params,
86 			struct tee_param *param)
87 
88 {
89 	struct optee *optee = tee_get_drvdata(ctx->teedev);
90 	struct optee_supp *supp = &optee->supp;
91 	struct optee_supp_req *req;
92 	u32 ret;
93 
94 	/*
95 	 * Return in case there is no supplicant available and
96 	 * non-blocking request.
97 	 */
98 	if (!supp->ctx && ctx->supp_nowait)
99 		return TEEC_ERROR_COMMUNICATION;
100 
101 	req = kzalloc_obj(*req);
102 	if (!req)
103 		return TEEC_ERROR_OUT_OF_MEMORY;
104 
105 	init_completion(&req->c);
106 	req->func = func;
107 	req->num_params = num_params;
108 	req->param = param;
109 
110 	/* Insert the request in the request list */
111 	mutex_lock(&supp->mutex);
112 	req->id = idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL);
113 	if (req->id < 0) {
114 		mutex_unlock(&supp->mutex);
115 		kfree(req);
116 		return TEEC_ERROR_OUT_OF_MEMORY;
117 	}
118 
119 	list_add_tail(&req->link, &supp->reqs);
120 	req->in_queue = true;
121 	req->processed = false;
122 	mutex_unlock(&supp->mutex);
123 
124 	/* Tell an eventual waiter there's a new request */
125 	complete(&supp->reqs_c);
126 
127 	/*
128 	 * Wait for supplicant to process and return result, once we've
129 	 * returned from wait_for_completion(&req->c) successfully we have
130 	 * exclusive access again. Allow the wait to be killable such that
131 	 * the wait doesn't turn into an indefinite state if the supplicant
132 	 * gets hung for some reason.
133 	 */
134 	if (wait_for_completion_killable(&req->c)) {
135 		mutex_lock(&supp->mutex);
136 		if (req->in_queue) {
137 			/* Supplicant has not seen this request yet. */
138 			idr_remove(&supp->idr, req->id);
139 			list_del(&req->link);
140 			req->in_queue = false;
141 
142 			ret = TEEC_ERROR_COMMUNICATION;
143 		} else if (req->processed) {
144 			/*
145 			 * Supplicant has processed this request. Ignore the
146 			 * kill signal for now and submit the result. req is not
147 			 * in supp->reqs (removed by supp_pop_entry()) nor in
148 			 * supp->idr (removed by supp_pop_req()).
149 			 */
150 			ret = req->ret;
151 		} else {
152 			/*
153 			 * Supplicant is in the middle of processing this
154 			 * request. Replace req with INVALID_REQ_PTR so that
155 			 * the ID remains busy, causing optee_supp_send() to
156 			 * fail on the next call to supp_pop_req() with this ID.
157 			 */
158 			idr_replace(&supp->idr, INVALID_REQ_PTR, req->id);
159 			ret = TEEC_ERROR_COMMUNICATION;
160 		}
161 
162 		mutex_unlock(&supp->mutex);
163 	} else {
164 		ret = req->ret;
165 	}
166 
167 	kfree(req);
168 
169 	return ret;
170 }
171 
supp_pop_entry(struct optee_supp * supp,int num_params)172 static struct optee_supp_req  *supp_pop_entry(struct optee_supp *supp,
173 					      int num_params)
174 {
175 	struct optee_supp_req *req;
176 
177 	if (supp->req_id != -1) {
178 		/*
179 		 * Supplicant should not mix synchronous and asnynchronous
180 		 * requests.
181 		 */
182 		return ERR_PTR(-EINVAL);
183 	}
184 
185 	if (list_empty(&supp->reqs))
186 		return NULL;
187 
188 	req = list_first_entry(&supp->reqs, struct optee_supp_req, link);
189 
190 	if (num_params < req->num_params) {
191 		/* Not enough room for parameters */
192 		return ERR_PTR(-EINVAL);
193 	}
194 
195 	list_del(&req->link);
196 	req->in_queue = false;
197 
198 	return req;
199 }
200 
supp_check_recv_params(size_t num_params,struct tee_param * params,size_t * num_meta)201 static int supp_check_recv_params(size_t num_params, struct tee_param *params,
202 				  size_t *num_meta)
203 {
204 	size_t n;
205 
206 	if (!num_params)
207 		return -EINVAL;
208 
209 	/*
210 	 * If there's memrefs we need to decrease those as they where
211 	 * increased earlier and we'll even refuse to accept any below.
212 	 */
213 	for (n = 0; n < num_params; n++)
214 		if (tee_param_is_memref(params + n) && params[n].u.memref.shm)
215 			tee_shm_put(params[n].u.memref.shm);
216 
217 	/*
218 	 * We only expect parameters as TEE_IOCTL_PARAM_ATTR_TYPE_NONE with
219 	 * or without the TEE_IOCTL_PARAM_ATTR_META bit set.
220 	 */
221 	for (n = 0; n < num_params; n++)
222 		if (params[n].attr &&
223 		    params[n].attr != TEE_IOCTL_PARAM_ATTR_META)
224 			return -EINVAL;
225 
226 	/* At most we'll need one meta parameter so no need to check for more */
227 	if (params->attr == TEE_IOCTL_PARAM_ATTR_META)
228 		*num_meta = 1;
229 	else
230 		*num_meta = 0;
231 
232 	return 0;
233 }
234 
235 /**
236  * optee_supp_recv() - receive request for supplicant
237  * @ctx:	context receiving the request
238  * @func:	requested function in supplicant
239  * @num_params:	number of elements allocated in @param, updated with number
240  *		used elements
241  * @param:	space for parameters for @func
242  *
243  * Returns 0 on success or <0 on failure
244  */
optee_supp_recv(struct tee_context * ctx,u32 * func,u32 * num_params,struct tee_param * param)245 int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params,
246 		    struct tee_param *param)
247 {
248 	struct tee_device *teedev = ctx->teedev;
249 	struct optee *optee = tee_get_drvdata(teedev);
250 	struct optee_supp *supp = &optee->supp;
251 	struct optee_supp_req *req = NULL;
252 	size_t num_meta;
253 	int rc;
254 
255 	rc = supp_check_recv_params(*num_params, param, &num_meta);
256 	if (rc)
257 		return rc;
258 
259 	while (true) {
260 		mutex_lock(&supp->mutex);
261 		req = supp_pop_entry(supp, *num_params - num_meta);
262 		if (req)
263 			break; /* Keep mutex held. */
264 		mutex_unlock(&supp->mutex);
265 
266 		/*
267 		 * If we didn't get a request we'll block in
268 		 * wait_for_completion() to avoid needless spinning.
269 		 *
270 		 * This is where supplicant will be hanging most of
271 		 * the time, let's make this interruptable so we
272 		 * can easily restart supplicant if needed.
273 		 */
274 		if (wait_for_completion_interruptible(&supp->reqs_c))
275 			return -ERESTARTSYS;
276 	}
277 
278 	/* supp->mutex held and req != NULL. */
279 
280 	if (IS_ERR(req)) {
281 		mutex_unlock(&supp->mutex);
282 		return PTR_ERR(req);
283 	}
284 
285 	if (num_meta) {
286 		/*
287 		 * tee-supplicant support meta parameters -> requsts can be
288 		 * processed asynchronously.
289 		 */
290 		param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT |
291 			      TEE_IOCTL_PARAM_ATTR_META;
292 		param->u.value.a = req->id;
293 		param->u.value.b = 0;
294 		param->u.value.c = 0;
295 	} else {
296 		supp->req_id = req->id;
297 	}
298 
299 	*func = req->func;
300 	*num_params = req->num_params + num_meta;
301 	memcpy(param + num_meta, req->param,
302 	       sizeof(struct tee_param) * req->num_params);
303 
304 	mutex_unlock(&supp->mutex);
305 	return 0;
306 }
307 
supp_pop_req(struct optee_supp * supp,size_t num_params,struct tee_param * param,size_t * num_meta)308 static struct optee_supp_req *supp_pop_req(struct optee_supp *supp,
309 					   size_t num_params,
310 					   struct tee_param *param,
311 					   size_t *num_meta)
312 {
313 	struct optee_supp_req *req;
314 	int id;
315 	size_t nm;
316 	const u32 attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT |
317 			 TEE_IOCTL_PARAM_ATTR_META;
318 
319 	if (!num_params)
320 		return ERR_PTR(-EINVAL);
321 
322 	if (supp->req_id == -1) {
323 		if (param->attr != attr)
324 			return ERR_PTR(-EINVAL);
325 		id = param->u.value.a;
326 		nm = 1;
327 	} else {
328 		id = supp->req_id;
329 		nm = 0;
330 	}
331 
332 	req = idr_find(&supp->idr, id);
333 	if (!req)
334 		return ERR_PTR(-ENOENT);
335 
336 	/* optee_supp_thrd_req() already returned to optee. */
337 	if (IS_ERR(req))
338 		goto failed_req;
339 
340 	if ((num_params - nm) != req->num_params)
341 		return ERR_PTR(-EINVAL);
342 
343 	*num_meta = nm;
344 failed_req:
345 	idr_remove(&supp->idr, id);
346 	supp->req_id = -1;
347 
348 	return req;
349 }
350 
351 /**
352  * optee_supp_send() - send result of request from supplicant
353  * @ctx:	context sending result
354  * @ret:	return value of request
355  * @num_params:	number of parameters returned
356  * @param:	returned parameters
357  *
358  * Returns 0 on success or <0 on failure.
359  */
optee_supp_send(struct tee_context * ctx,u32 ret,u32 num_params,struct tee_param * param)360 int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params,
361 		    struct tee_param *param)
362 {
363 	struct tee_device *teedev = ctx->teedev;
364 	struct optee *optee = tee_get_drvdata(teedev);
365 	struct optee_supp *supp = &optee->supp;
366 	struct optee_supp_req *req;
367 	size_t n;
368 	size_t num_meta;
369 
370 	mutex_lock(&supp->mutex);
371 	req = supp_pop_req(supp, num_params, param, &num_meta);
372 	if (IS_ERR(req)) {
373 		mutex_unlock(&supp->mutex);
374 		/* Something is wrong, let supplicant handel it. */
375 		return PTR_ERR(req);
376 	}
377 
378 	/* Update out and in/out parameters */
379 	for (n = 0; n < req->num_params; n++) {
380 		struct tee_param *p = req->param + n;
381 
382 		switch (p->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
383 		case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
384 		case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
385 			p->u.value.a = param[n + num_meta].u.value.a;
386 			p->u.value.b = param[n + num_meta].u.value.b;
387 			p->u.value.c = param[n + num_meta].u.value.c;
388 			break;
389 		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
390 		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
391 			p->u.memref.size = param[n + num_meta].u.memref.size;
392 			break;
393 		default:
394 			break;
395 		}
396 	}
397 	req->ret = ret;
398 	req->processed = true;
399 	/* Let the requesting thread continue */
400 	complete(&req->c);
401 	mutex_unlock(&supp->mutex);
402 
403 	return 0;
404 }
405