xref: /optee_os/core/pta/veraison_attestation/hash.c (revision 5d5d7d0b1c038a6836be9f0b38585f5aa6a4dd01)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (C) 2024, Institute of Information Security (IISEC)
4  */
5 
6 #include <crypto/crypto.h>
7 #include <kernel/user_mode_ctx.h>
8 
9 #include "hash.h"
10 
11 /*
12  * Is region valid for hashing?
13  * Exclude writable regions as well as those that are not specific to the TA
14  * (ldelf, kernel or temporary mappings).
15  */
16 static bool is_region_valid(struct vm_region *r)
17 {
18 	uint32_t dontwant = VM_FLAG_EPHEMERAL | VM_FLAG_PERMANENT |
19 			    VM_FLAG_LDELF;
20 	uint32_t want = VM_FLAG_READONLY;
21 
22 	return ((r->flags & want) == want && !(r->flags & dontwant));
23 }
24 
25 /*
26  * With this comparison function, we're hashing the smaller regions first.
27  * Regions of equal size are ordered based on their content (memcmp()).
28  * Identical regions can be in any order since they will yield the same hash
29  * anyways.
30  */
31 static int cmp_regions(const void *a, const void *b)
32 {
33 	const struct vm_region *r1 = *(const struct vm_region **)a;
34 	const struct vm_region *r2 = *(const struct vm_region **)b;
35 
36 	if (r1->size < r2->size)
37 		return -1;
38 
39 	if (r1->size > r2->size)
40 		return 1;
41 
42 	return memcmp((void *)r1->va, (void *)r2->va, r1->size);
43 }
44 
45 static TEE_Result hash_regions(struct vm_info *vm_info,
46 			       uint8_t hash[TEE_SHA256_HASH_SIZE])
47 {
48 	TEE_Result res = TEE_SUCCESS;
49 	struct vm_region *r = NULL;
50 	struct vm_region **regions = NULL;
51 	size_t nregions = 0;
52 	void *ctx = NULL;
53 	size_t i = 0;
54 
55 	res = crypto_hash_alloc_ctx(&ctx, TEE_ALG_SHA256);
56 	if (res)
57 		return res;
58 
59 	res = crypto_hash_init(ctx);
60 	if (res)
61 		goto out;
62 
63 	/*
64 	 * Make an array of region pointers so we can use qsort() to order it.
65 	 */
66 
67 	TAILQ_FOREACH(r, &vm_info->regions, link)
68 		if (is_region_valid(r))
69 			nregions++;
70 
71 	regions = calloc(nregions, sizeof(*regions));
72 	if (!regions) {
73 		res = TEE_ERROR_OUT_OF_MEMORY;
74 		goto out;
75 	}
76 
77 	TAILQ_FOREACH(r, &vm_info->regions, link)
78 		if (is_region_valid(r))
79 			regions[i++] = r;
80 
81 	/*
82 	 * Sort regions so that they are in a consistent order even when TA ASLR
83 	 * is enabled.
84 	 */
85 	qsort(regions, nregions, sizeof(*regions), cmp_regions);
86 
87 	/* Hash regions in order */
88 	for (i = 0; i < nregions; i++) {
89 		r = regions[i];
90 		DMSG("va %p size %zu", (void *)r->va, r->size);
91 		res = crypto_hash_update(ctx, (uint8_t *)r->va, r->size);
92 		if (res)
93 			goto out;
94 	}
95 
96 	res = crypto_hash_final(ctx, hash, TEE_SHA256_HASH_SIZE);
97 out:
98 	free(regions);
99 	crypto_hash_free_ctx(ctx);
100 	return res;
101 }
102 
103 TEE_Result get_hash_ta_memory(uint8_t out[TEE_SHA256_HASH_SIZE])
104 {
105 	struct user_mode_ctx *uctx = NULL;
106 	TEE_Result res = TEE_SUCCESS;
107 	struct ts_session *s = NULL;
108 
109 	/* Check that we're called from a user TA */
110 	s = ts_get_calling_session();
111 	if (!s)
112 		return TEE_ERROR_ACCESS_DENIED;
113 	uctx = to_user_mode_ctx(s->ctx);
114 	if (!uctx)
115 		return TEE_ERROR_ACCESS_DENIED;
116 
117 	s = ts_pop_current_session();
118 	res = hash_regions(&uctx->vm_info, out);
119 	ts_push_current_session(s);
120 	return res;
121 }
122