xref: /optee_os/lib/libutee/tee_api_property.c (revision 6551d565c2f5a7c61c48ffff2148a4b3dac218a5)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2014, STMicroelectronics International N.V.
4  * Copyright (c) 2017-2020, Linaro Limited
5  */
6 #include <printk.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <tee_api_defines.h>
11 #include <tee_api.h>
12 #include <tee_api_types.h>
13 #include <tee_arith_internal.h>
14 #include <tee_internal_api_extensions.h>
15 #include <tee_isocket.h>
16 #include <user_ta_header.h>
17 #include <utee_syscalls.h>
18 #include <util.h>
19 
20 #include "base64.h"
21 #include "string_ext.h"
22 #include "tee_api_private.h"
23 
24 #define PROP_STR_MAX    80
25 
26 #define PROP_ENUMERATOR_NOT_STARTED 0xffffffff
27 
28 struct prop_enumerator {
29 	uint32_t idx;			/* current index */
30 	TEE_PropSetHandle prop_set;	/* part of TEE_PROPSET_xxx */
31 };
32 
33 const struct user_ta_property tee_props[] = {
34 	{
35 		"gpd.tee.arith.maxBigIntSize",
36 		USER_TA_PROP_TYPE_U32,
37 		&(const uint32_t){CFG_TA_BIGNUM_MAX_BITS}
38 	},
39 	{
40 		"gpd.tee.sockets.version",
41 		USER_TA_PROP_TYPE_U32,
42 		&(const uint32_t){TEE_ISOCKET_VERSION}
43 	},
44 	{
45 		"gpd.tee.sockets.tcp.version",
46 		USER_TA_PROP_TYPE_U32,
47 		&(const uint32_t){TEE_ISOCKET_VERSION}
48 	},
49 };
50 
51 static TEE_Result propset_get(TEE_PropSetHandle h,
52 			      const struct user_ta_property **eps,
53 			      size_t *eps_len)
54 {
55 	if (h == TEE_PROPSET_CURRENT_TA) {
56 		*eps = ta_props;
57 		*eps_len = ta_num_props;
58 	} else if (h == TEE_PROPSET_CURRENT_CLIENT) {
59 		*eps = NULL;
60 		*eps_len = 0;
61 	} else if (h == TEE_PROPSET_TEE_IMPLEMENTATION) {
62 		*eps = tee_props;
63 		*eps_len = ARRAY_SIZE(tee_props);
64 	} else {
65 		return TEE_ERROR_ITEM_NOT_FOUND;
66 	}
67 
68 	return TEE_SUCCESS;
69 }
70 
71 static TEE_Result propget_get_ext_prop(const struct user_ta_property *ep,
72 				       enum user_ta_prop_type *type,
73 				       void *buf, uint32_t *len)
74 {
75 	size_t l;
76 
77 	*type = ep->type;
78 	switch (*type) {
79 	case USER_TA_PROP_TYPE_BOOL:
80 		l = sizeof(bool);
81 		break;
82 	case USER_TA_PROP_TYPE_U32:
83 		l = sizeof(uint32_t);
84 		break;
85 	case USER_TA_PROP_TYPE_U64:
86 		l = sizeof(uint64_t);
87 		break;
88 	case USER_TA_PROP_TYPE_UUID:
89 		l = sizeof(TEE_UUID);
90 		break;
91 	case USER_TA_PROP_TYPE_IDENTITY:
92 		l = sizeof(TEE_Identity);
93 		break;
94 	case USER_TA_PROP_TYPE_STRING:
95 		/* take the leading 0 into account */
96 		l = strlen(ep->value) + 1;
97 		break;
98 	case USER_TA_PROP_TYPE_BINARY_BLOCK:
99 		/*
100 		 * in case of TA property, a binary block is provided as a
101 		 * string, which is base64 encoded. We must first decode it,
102 		 * without taking into account the zero termination of the
103 		 * string
104 		 */
105 		l = *len;
106 		if (!_base64_dec(ep->value, strlen(ep->value), buf, &l) &&
107 		    l <= *len)
108 			return TEE_ERROR_GENERIC;
109 		if (*len < l) {
110 			*len = l;
111 			return TEE_ERROR_SHORT_BUFFER;
112 		}
113 
114 		*len = l;
115 		return TEE_SUCCESS;
116 	default:
117 		return TEE_ERROR_GENERIC;
118 	}
119 
120 	if (*len < l) {
121 		*len = l;
122 		return TEE_ERROR_SHORT_BUFFER;
123 	}
124 
125 	*len = l;
126 	memcpy(buf, ep->value, l);
127 	return TEE_SUCCESS;
128 }
129 
130 static bool is_propset_pseudo_handle(TEE_PropSetHandle h)
131 {
132 	return h == TEE_PROPSET_CURRENT_TA ||
133 	       h == TEE_PROPSET_CURRENT_CLIENT ||
134 	       h == TEE_PROPSET_TEE_IMPLEMENTATION;
135 }
136 
137 static TEE_Result propget_get_property(TEE_PropSetHandle h, const char *name,
138 				       enum user_ta_prop_type *type,
139 				       void *buf, uint32_t *len)
140 {
141 	TEE_Result res;
142 	const struct user_ta_property *eps;
143 	size_t eps_len;
144 	uint32_t prop_type;
145 	uint32_t index;
146 
147 	if (is_propset_pseudo_handle(h)) {
148 		size_t n;
149 
150 		res = propset_get(h, &eps, &eps_len);
151 		if (res != TEE_SUCCESS)
152 			return res;
153 
154 		for (n = 0; n < eps_len; n++) {
155 			if (!strcmp(name, eps[n].name))
156 				return propget_get_ext_prop(eps + n, type,
157 							    buf, len);
158 		}
159 
160 		/* get the index from the name */
161 		res = _utee_get_property_name_to_index((unsigned long)h, name,
162 						       strlen(name) + 1,
163 						       &index);
164 		if (res != TEE_SUCCESS)
165 			return res;
166 		res = _utee_get_property((unsigned long)h, index, NULL, NULL,
167 					 buf, len, &prop_type);
168 	} else {
169 		struct prop_enumerator *pe = (struct prop_enumerator *)h;
170 		uint32_t idx = pe->idx;
171 
172 		if (idx == PROP_ENUMERATOR_NOT_STARTED)
173 			return TEE_ERROR_ITEM_NOT_FOUND;
174 
175 		res = propset_get(pe->prop_set, &eps, &eps_len);
176 		if (res != TEE_SUCCESS)
177 			return res;
178 
179 		if (idx < eps_len)
180 			return propget_get_ext_prop(eps + idx, type, buf, len);
181 		idx -= eps_len;
182 
183 		res = _utee_get_property((unsigned long)pe->prop_set, idx,
184 					 NULL, NULL, buf, len, &prop_type);
185 		if (res == TEE_ERROR_ITEM_NOT_FOUND)
186 			res = TEE_ERROR_BAD_PARAMETERS;
187 	}
188 
189 	*type = prop_type;
190 	return res;
191 }
192 
193 TEE_Result TEE_GetPropertyAsString(TEE_PropSetHandle propsetOrEnumerator,
194 				   const char *name, char *value,
195 				   size_t *value_len)
196 {
197 	TEE_Result res;
198 	size_t l;
199 	enum user_ta_prop_type type;
200 	void *tmp_buf = 0;
201 	uint32_t tmp_len;
202 	uint32_t uint32_val;
203 	bool bool_val;
204 	TEE_Identity *p_identity_val;
205 
206 	if (is_propset_pseudo_handle(propsetOrEnumerator))
207 		__utee_check_instring_annotation(name);
208 	__utee_check_outstring_annotation(value, value_len);
209 
210 	tmp_len = *value_len;
211 	if (tmp_len < sizeof(TEE_Identity))
212 		tmp_len = sizeof(TEE_Identity);
213 	tmp_buf = TEE_Malloc(tmp_len, TEE_USER_MEM_HINT_NO_FILL_ZERO);
214 	if (!tmp_buf) {
215 		res = TEE_ERROR_OUT_OF_MEMORY;
216 		goto out;
217 	}
218 
219 	res = propget_get_property(propsetOrEnumerator, name, &type,
220 				   tmp_buf, &tmp_len);
221 	if (res != TEE_SUCCESS) {
222 		if (res == TEE_ERROR_SHORT_BUFFER) {
223 			if (type == USER_TA_PROP_TYPE_BINARY_BLOCK) {
224 				/*
225 				 * in this case, we must enlarge the buffer
226 				 * with the size of the of the base64 encoded
227 				 * see base64_enc() function
228 				 */
229 				tmp_len = _base64_enc_len(tmp_len);
230 			}
231 			*value_len = tmp_len;
232 		}
233 		goto out;
234 	}
235 
236 	switch (type) {
237 	case USER_TA_PROP_TYPE_BOOL:
238 		bool_val = *((bool *)tmp_buf);
239 		l = strlcpy(value, (bool_val ? "true" : "false"), *value_len);
240 		break;
241 
242 	case USER_TA_PROP_TYPE_U32:
243 		uint32_val = *((uint32_t *)tmp_buf);
244 		l = snprintf(value, *value_len, "%u", uint32_val);
245 		break;
246 
247 	case USER_TA_PROP_TYPE_UUID:
248 		l = snprintk(value, *value_len, "%pUl", tmp_buf);
249 		break;
250 
251 	case USER_TA_PROP_TYPE_IDENTITY:
252 		p_identity_val = ((TEE_Identity *)tmp_buf);
253 		l = snprintk(value, *value_len, "%u:%pUl",
254 			     p_identity_val->login,
255 			     (void *)(&(p_identity_val->uuid)));
256 		break;
257 
258 	case USER_TA_PROP_TYPE_STRING:
259 		l = strlcpy(value, tmp_buf, *value_len);
260 		break;
261 
262 	case USER_TA_PROP_TYPE_BINARY_BLOCK:
263 		l = *value_len;	/* l includes the zero-termination */
264 		if (!_base64_enc(tmp_buf, tmp_len, value, &l) &&
265 		    l <= *value_len) {
266 			res = TEE_ERROR_GENERIC;
267 			goto out;
268 		}
269 		l--;	/* remove the zero-termination that is added later */
270 		break;
271 
272 	default:
273 		res = TEE_ERROR_BAD_FORMAT;
274 		goto out;
275 	}
276 
277 	l++;	/* include zero termination */
278 
279 	if (l > *value_len)
280 		res = TEE_ERROR_SHORT_BUFFER;
281 	*value_len = l;
282 
283 out:
284 	if (tmp_buf)
285 		TEE_Free(tmp_buf);
286 	if (res != TEE_SUCCESS &&
287 	    res != TEE_ERROR_ITEM_NOT_FOUND &&
288 	    res != TEE_ERROR_SHORT_BUFFER)
289 		TEE_Panic(0);
290 
291 	return res;
292 }
293 
294 TEE_Result __GP11_TEE_GetPropertyAsString(TEE_PropSetHandle propsetOrEnumerator,
295 					  const char *name, char *valueBuffer,
296 					  uint32_t *valueBufferLen)
297 {
298 	TEE_Result res = TEE_SUCCESS;
299 	size_t l = 0;
300 
301 	__utee_check_gp11_outstring_annotation(valueBuffer, valueBufferLen);
302 	l = *valueBufferLen;
303 	res = TEE_GetPropertyAsString(propsetOrEnumerator, name, valueBuffer,
304 				      &l);
305 	*valueBufferLen = l;
306 	return res;
307 }
308 
309 TEE_Result TEE_GetPropertyAsBool(TEE_PropSetHandle propsetOrEnumerator,
310 				 const char *name, bool *value)
311 {
312 	TEE_Result res;
313 	enum user_ta_prop_type type;
314 	uint32_t bool_len = sizeof(bool);
315 
316 	if (is_propset_pseudo_handle(propsetOrEnumerator))
317 		__utee_check_instring_annotation(name);
318 	__utee_check_out_annotation(value, sizeof(*value));
319 
320 	type = USER_TA_PROP_TYPE_BOOL;
321 	res = propget_get_property(propsetOrEnumerator, name, &type,
322 				   value, &bool_len);
323 	if (type != USER_TA_PROP_TYPE_BOOL)
324 		res = TEE_ERROR_BAD_FORMAT;
325 	if (res != TEE_SUCCESS)
326 		goto out;
327 
328 out:
329 	if (res != TEE_SUCCESS &&
330 	    res != TEE_ERROR_ITEM_NOT_FOUND &&
331 	    res != TEE_ERROR_BAD_FORMAT)
332 		TEE_Panic(0);
333 
334 	return res;
335 }
336 
337 TEE_Result TEE_GetPropertyAsU32(TEE_PropSetHandle propsetOrEnumerator,
338 				const char *name, uint32_t *value)
339 {
340 	TEE_Result res;
341 	enum user_ta_prop_type type;
342 	uint32_t uint32_len = sizeof(uint32_t);
343 
344 	if (is_propset_pseudo_handle(propsetOrEnumerator))
345 		__utee_check_instring_annotation(name);
346 	__utee_check_out_annotation(value, sizeof(*value));
347 
348 	type = USER_TA_PROP_TYPE_U32;
349 	res = propget_get_property(propsetOrEnumerator, name, &type,
350 				   value, &uint32_len);
351 	if (type != USER_TA_PROP_TYPE_U32)
352 		res = TEE_ERROR_BAD_FORMAT;
353 
354 	if (res != TEE_SUCCESS &&
355 	    res != TEE_ERROR_ITEM_NOT_FOUND &&
356 	    res != TEE_ERROR_BAD_FORMAT)
357 		TEE_Panic(0);
358 
359 	return res;
360 }
361 
362 TEE_Result TEE_GetPropertyAsU64(TEE_PropSetHandle propsetOrEnumerator,
363 				const char *name, uint64_t *value)
364 {
365 	TEE_Result res;
366 	enum user_ta_prop_type type;
367 	uint32_t uint64_len = sizeof(*value);
368 
369 	if (is_propset_pseudo_handle(propsetOrEnumerator))
370 		__utee_check_instring_annotation(name);
371 	__utee_check_out_annotation(value, sizeof(*value));
372 
373 	type = USER_TA_PROP_TYPE_U64;
374 	res = propget_get_property(propsetOrEnumerator, name, &type,
375 				   value, &uint64_len);
376 	if (type != USER_TA_PROP_TYPE_U64)
377 		res = TEE_ERROR_BAD_FORMAT;
378 
379 	if (res != TEE_SUCCESS &&
380 	    res != TEE_ERROR_ITEM_NOT_FOUND &&
381 	    res != TEE_ERROR_BAD_FORMAT)
382 		TEE_Panic(0);
383 
384 	return res;
385 }
386 
387 TEE_Result
388 __GP11_TEE_GetPropertyAsBinaryBlock(TEE_PropSetHandle propsetOrEnumerator,
389 				    const char *name, void *value,
390 				    uint32_t *value_len)
391 {
392 	TEE_Result res = TEE_SUCCESS;
393 	enum user_ta_prop_type type = USER_TA_PROP_TYPE_BOOL;
394 
395 	if (is_propset_pseudo_handle(propsetOrEnumerator))
396 		__utee_check_instring_annotation(name);
397 	__utee_check_gp11_outbuf_annotation(value, value_len);
398 
399 	type = USER_TA_PROP_TYPE_BINARY_BLOCK;
400 	res = propget_get_property(propsetOrEnumerator, name, &type,
401 				   value, value_len);
402 	if (type != USER_TA_PROP_TYPE_BINARY_BLOCK)
403 		res = TEE_ERROR_BAD_FORMAT;
404 
405 	if (res != TEE_SUCCESS &&
406 	    res != TEE_ERROR_ITEM_NOT_FOUND &&
407 	    res != TEE_ERROR_BAD_FORMAT &&
408 	    res != TEE_ERROR_SHORT_BUFFER)
409 		TEE_Panic(0);
410 
411 	return res;
412 }
413 
414 TEE_Result TEE_GetPropertyAsBinaryBlock(TEE_PropSetHandle propsetOrEnumerator,
415 					const char *name, void *value,
416 					size_t *value_len)
417 {
418 	TEE_Result res = TEE_SUCCESS;
419 	uint32_t l = 0;
420 
421 	__utee_check_outbuf_annotation(value, value_len);
422 	l = *value_len;
423 	res = __GP11_TEE_GetPropertyAsBinaryBlock(propsetOrEnumerator, name,
424 						  value, &l);
425 	*value_len = l;
426 	return res;
427 }
428 
429 TEE_Result TEE_GetPropertyAsUUID(TEE_PropSetHandle propsetOrEnumerator,
430 				 const char *name, TEE_UUID *value)
431 {
432 	TEE_Result res;
433 	enum user_ta_prop_type type;
434 	uint32_t uuid_len = sizeof(TEE_UUID);
435 
436 	if (is_propset_pseudo_handle(propsetOrEnumerator))
437 		__utee_check_instring_annotation(name);
438 	__utee_check_out_annotation(value, sizeof(*value));
439 
440 	type = USER_TA_PROP_TYPE_UUID;
441 	res = propget_get_property(propsetOrEnumerator, name, &type,
442 				   value, &uuid_len);
443 	if (type != USER_TA_PROP_TYPE_UUID)
444 		res = TEE_ERROR_BAD_FORMAT;
445 
446 	if (res != TEE_SUCCESS &&
447 	    res != TEE_ERROR_ITEM_NOT_FOUND &&
448 	    res != TEE_ERROR_BAD_FORMAT)
449 		TEE_Panic(0);
450 
451 	return res;
452 }
453 
454 TEE_Result TEE_GetPropertyAsIdentity(TEE_PropSetHandle propsetOrEnumerator,
455 				     const char *name, TEE_Identity *value)
456 {
457 	TEE_Result res;
458 	enum user_ta_prop_type type;
459 	uint32_t identity_len = sizeof(TEE_Identity);
460 
461 	if (is_propset_pseudo_handle(propsetOrEnumerator))
462 		__utee_check_instring_annotation(name);
463 	__utee_check_out_annotation(value, sizeof(*value));
464 
465 	type = USER_TA_PROP_TYPE_IDENTITY;
466 	res = propget_get_property(propsetOrEnumerator, name, &type,
467 				   value, &identity_len);
468 	if (type != USER_TA_PROP_TYPE_IDENTITY)
469 		res = TEE_ERROR_BAD_FORMAT;
470 
471 	if (res != TEE_SUCCESS &&
472 	    res != TEE_ERROR_ITEM_NOT_FOUND &&
473 	    res != TEE_ERROR_BAD_FORMAT)
474 		TEE_Panic(0);
475 
476 	return res;
477 }
478 
479 TEE_Result TEE_AllocatePropertyEnumerator(TEE_PropSetHandle *enumerator)
480 {
481 	TEE_Result res;
482 	struct prop_enumerator *pe;
483 
484 	__utee_check_out_annotation(enumerator, sizeof(*enumerator));
485 
486 	pe = TEE_Malloc(sizeof(struct prop_enumerator),
487 			TEE_USER_MEM_HINT_NO_FILL_ZERO);
488 	if (pe == NULL) {
489 		res = TEE_ERROR_OUT_OF_MEMORY;
490 		goto err;
491 	}
492 
493 	*enumerator = (TEE_PropSetHandle) pe;
494 	TEE_ResetPropertyEnumerator(*enumerator);
495 
496 	goto out;
497 
498 err:
499 	if (res == TEE_ERROR_OUT_OF_MEMORY)
500 		return res;
501 	TEE_Panic(0);
502 out:
503 	return TEE_SUCCESS;
504 }
505 
506 void TEE_ResetPropertyEnumerator(TEE_PropSetHandle enumerator)
507 {
508 	struct prop_enumerator *pe = (struct prop_enumerator *)enumerator;
509 
510 	pe->idx = PROP_ENUMERATOR_NOT_STARTED;
511 }
512 
513 void TEE_FreePropertyEnumerator(TEE_PropSetHandle enumerator)
514 {
515 	struct prop_enumerator *pe = (struct prop_enumerator *)enumerator;
516 
517 	TEE_Free(pe);
518 }
519 
520 void TEE_StartPropertyEnumerator(TEE_PropSetHandle enumerator,
521 				 TEE_PropSetHandle propSet)
522 {
523 	struct prop_enumerator *pe = (struct prop_enumerator *)enumerator;
524 
525 	if (!pe)
526 		return;
527 
528 	pe->idx = 0;
529 	pe->prop_set = propSet;
530 }
531 
532 TEE_Result __GP11_TEE_GetPropertyName(TEE_PropSetHandle enumerator,
533 				      void *name, uint32_t *name_len)
534 {
535 	TEE_Result res;
536 	struct prop_enumerator *pe = (struct prop_enumerator *)enumerator;
537 	const struct user_ta_property *eps;
538 	size_t eps_len;
539 	const char *str;
540 	size_t bufferlen;
541 
542 	if (!pe) {
543 		res = TEE_ERROR_BAD_PARAMETERS;
544 		goto err;
545 	}
546 	__utee_check_gp11_outstring_annotation(name, name_len);
547 
548 	bufferlen = *name_len;
549 	res = propset_get(pe->prop_set, &eps, &eps_len);
550 	if (res != TEE_SUCCESS)
551 		goto err;
552 
553 	if (pe->idx < eps_len) {
554 		str = eps[pe->idx].name;
555 		bufferlen = strlcpy(name, str, *name_len) + 1;
556 		if (bufferlen > *name_len)
557 			res = TEE_ERROR_SHORT_BUFFER;
558 		*name_len = bufferlen;
559 	} else {
560 		res = _utee_get_property((unsigned long)pe->prop_set,
561 					 pe->idx - eps_len, name, name_len,
562 					 NULL, NULL, NULL);
563 		if (res != TEE_SUCCESS)
564 			goto err;
565 	}
566 
567 err:
568 	if (res != TEE_SUCCESS &&
569 	    res != TEE_ERROR_ITEM_NOT_FOUND &&
570 	    res != TEE_ERROR_SHORT_BUFFER)
571 		TEE_Panic(0);
572 	return res;
573 }
574 
575 TEE_Result TEE_GetPropertyName(TEE_PropSetHandle enumerator,
576 			       void *nameBuffer, size_t *nameBufferLen)
577 {
578 	TEE_Result res = TEE_SUCCESS;
579 	uint32_t l = 0;
580 
581 	__utee_check_outstring_annotation(nameBuffer, nameBufferLen);
582 	l = *nameBufferLen;
583 	res = __GP11_TEE_GetPropertyName(enumerator, nameBuffer, &l);
584 	*nameBufferLen = l;
585 	return res;
586 }
587 
588 TEE_Result TEE_GetNextProperty(TEE_PropSetHandle enumerator)
589 {
590 	TEE_Result res;
591 	struct prop_enumerator *pe = (struct prop_enumerator *)enumerator;
592 	uint32_t next_idx;
593 	const struct user_ta_property *eps;
594 	size_t eps_len;
595 
596 	if (!pe) {
597 		res = TEE_ERROR_BAD_PARAMETERS;
598 		goto out;
599 	}
600 
601 	if (pe->idx == PROP_ENUMERATOR_NOT_STARTED) {
602 		res = TEE_ERROR_ITEM_NOT_FOUND;
603 		goto out;
604 	}
605 
606 	res = propset_get(pe->prop_set, &eps, &eps_len);
607 	if (res != TEE_SUCCESS)
608 		goto out;
609 
610 	next_idx = pe->idx + 1;
611 	pe->idx = next_idx;
612 	if (next_idx < eps_len)
613 		res = TEE_SUCCESS;
614 	else
615 		res = _utee_get_property((unsigned long)pe->prop_set,
616 					 next_idx - eps_len, NULL, NULL, NULL,
617 					 NULL, NULL);
618 
619 out:
620 	if (res != TEE_SUCCESS &&
621 	    res != TEE_ERROR_ITEM_NOT_FOUND)
622 		TEE_Panic(0);
623 	return res;
624 }
625