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