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 */
is_region_valid(struct vm_region * r)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 */
cmp_regions(const void * a,const void * b)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
hash_regions(struct vm_info * vm_info,uint8_t hash[TEE_SHA256_HASH_SIZE])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
get_hash_ta_memory(uint8_t out[TEE_SHA256_HASH_SIZE])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