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