1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2017, Linaro Limited
4 * Copyright (c) 2020, Arm Limited.
5 */
6 #include <crypto/crypto.h>
7 #include <initcall.h>
8 #include <kernel/embedded_ts.h>
9 #include <kernel/ts_store.h>
10 #include <kernel/user_access.h>
11 #include <mempool.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <trace.h>
16 #include <utee_defines.h>
17 #include <util.h>
18 #include <zlib.h>
19
20 struct ts_store_handle {
21 const struct embedded_ts *ts;
22 size_t offs;
23 z_stream strm;
24 };
25
zalloc(void * opaque __unused,unsigned int items,unsigned int size)26 static void *zalloc(void *opaque __unused, unsigned int items,
27 unsigned int size)
28 {
29 return mempool_alloc(mempool_default, items * size);
30 }
31
zfree(void * opaque __unused,void * address)32 static void zfree(void *opaque __unused, void *address)
33 {
34 mempool_free(mempool_default, address);
35 }
36
decompression_init(z_stream * strm,const struct embedded_ts * ts)37 static bool decompression_init(z_stream *strm,
38 const struct embedded_ts *ts)
39 {
40 int st = Z_OK;
41
42 strm->next_in = ts->ts;
43 strm->avail_in = ts->size;
44 strm->zalloc = zalloc;
45 strm->zfree = zfree;
46 st = inflateInit(strm);
47 if (st != Z_OK) {
48 EMSG("Decompression initialization error (%d)", st);
49 return false;
50 }
51
52 return true;
53 }
54
emb_ts_open(const TEE_UUID * uuid,struct ts_store_handle ** h,const struct embedded_ts * (* find_ts)(const TEE_UUID * uuid))55 TEE_Result emb_ts_open(const TEE_UUID *uuid,
56 struct ts_store_handle **h,
57 const struct embedded_ts*
58 (*find_ts) (const TEE_UUID *uuid))
59 {
60 struct ts_store_handle *handle = NULL;
61 const struct embedded_ts *ts = NULL;
62
63 ts = find_ts(uuid);
64 if (!ts)
65 return TEE_ERROR_ITEM_NOT_FOUND;
66
67 handle = calloc(1, sizeof(*handle));
68 if (!handle)
69 return TEE_ERROR_OUT_OF_MEMORY;
70
71 if (ts->uncompressed_size) {
72 if (!decompression_init(&handle->strm, ts)) {
73 free(handle);
74 return TEE_ERROR_BAD_FORMAT;
75 }
76 }
77 handle->ts = ts;
78 *h = handle;
79
80 return TEE_SUCCESS;
81 }
82
emb_ts_get_size(const struct ts_store_handle * h,size_t * size)83 TEE_Result emb_ts_get_size(const struct ts_store_handle *h, size_t *size)
84 {
85 const struct embedded_ts *ts = h->ts;
86
87 if (ts->uncompressed_size)
88 *size = ts->uncompressed_size;
89 else
90 *size = ts->size;
91
92 return TEE_SUCCESS;
93 }
94
emb_ts_get_tag(const struct ts_store_handle * h,uint8_t * tag,unsigned int * tag_len)95 TEE_Result emb_ts_get_tag(const struct ts_store_handle *h,
96 uint8_t *tag, unsigned int *tag_len)
97 {
98 TEE_Result res = TEE_SUCCESS;
99 void *ctx = NULL;
100
101 if (!tag || *tag_len < TEE_SHA256_HASH_SIZE) {
102 *tag_len = TEE_SHA256_HASH_SIZE;
103 return TEE_ERROR_SHORT_BUFFER;
104 }
105 *tag_len = TEE_SHA256_HASH_SIZE;
106
107 res = crypto_hash_alloc_ctx(&ctx, TEE_ALG_SHA256);
108 if (res)
109 return res;
110 res = crypto_hash_init(ctx);
111 if (res)
112 goto out;
113 res = crypto_hash_update(ctx, h->ts->ts, h->ts->size);
114 if (res)
115 goto out;
116 res = crypto_hash_final(ctx, tag, *tag_len);
117 out:
118 crypto_hash_free_ctx(ctx);
119 return res;
120 }
121
read_uncompressed(struct ts_store_handle * h,void * data_core,void * data_user,size_t len)122 static TEE_Result read_uncompressed(struct ts_store_handle *h, void *data_core,
123 void *data_user, size_t len)
124 {
125 TEE_Result res = TEE_SUCCESS;
126 uint8_t *src = (uint8_t *)h->ts->ts + h->offs;
127 size_t next_offs = 0;
128
129 if (ADD_OVERFLOW(h->offs, len, &next_offs) ||
130 next_offs > h->ts->size)
131 return TEE_ERROR_BAD_PARAMETERS;
132 if (data_core)
133 memcpy(data_core, src, len);
134 if (data_user)
135 res = copy_to_user(data_user, src, len);
136 if (!res)
137 h->offs = next_offs;
138
139 return res;
140 }
141
read_compressed(struct ts_store_handle * h,void * data_core,void * data_user,size_t len)142 static TEE_Result read_compressed(struct ts_store_handle *h, void *data_core,
143 void *data_user, size_t len)
144 {
145 TEE_Result res = TEE_SUCCESS;
146 z_stream *strm = &h->strm;
147 size_t total = 0;
148 uint8_t *bb = NULL;
149 size_t bb_len = 0;
150 size_t out = 0;
151 int st = Z_OK;
152
153 /* Inflate into a 1kB bounce buffer */
154 bb_len = MIN(len, 1024U);
155 bb = bb_alloc(bb_len);
156 if (!bb) {
157 EMSG("Out of memory");
158 return TEE_ERROR_OUT_OF_MEMORY;
159 }
160
161 strm->avail_out = bb_len;
162 strm->next_out = bb;
163
164 /*
165 * Loop until we get as many bytes as requested, or an error occurs.
166 * inflate() returns:
167 * - Z_OK when progress was made, but neither the end of the input
168 * stream nor the end of the output buffer were met.
169 * - Z_STREAM_END when the end of the intput stream was reached.
170 * - Z_BUF_ERROR when there is still input to process but the output
171 * buffer is full (not a "hard" error, decompression can proceeed
172 * later).
173 */
174 do {
175 out = strm->total_out;
176 st = inflate(strm, Z_SYNC_FLUSH);
177 out = strm->total_out - out;
178 FMSG("%zu bytes", out);
179 if (data_core)
180 memcpy((uint8_t *)data_core + total, bb, out);
181 if (data_user) {
182 res = copy_to_user((uint8_t *)data_user + total, bb,
183 out);
184 if (res)
185 goto out;
186 }
187 total += out;
188 /*
189 * Reset the pointer since we've just copied out the last
190 * data.
191 */
192 strm->next_out = bb;
193 strm->avail_out = MIN(len - total, bb_len);
194 } while ((st == Z_OK || st == Z_BUF_ERROR) && (total != len));
195
196 if (st != Z_OK && st != Z_STREAM_END) {
197 EMSG("Decompression error (%d)", st);
198 res = TEE_ERROR_GENERIC;
199 goto out;
200 }
201 res = TEE_SUCCESS;
202 out:
203 bb_free(bb, bb_len);
204
205 return res;
206 }
207
emb_ts_read(struct ts_store_handle * h,void * data_core,void * data_user,size_t len)208 TEE_Result emb_ts_read(struct ts_store_handle *h, void *data_core,
209 void *data_user, size_t len)
210 {
211 if (h->ts->uncompressed_size)
212 return read_compressed(h, data_core, data_user, len);
213 else
214 return read_uncompressed(h, data_core, data_user, len);
215 }
216
emb_ts_close(struct ts_store_handle * h)217 void emb_ts_close(struct ts_store_handle *h)
218 {
219 if (h->ts->uncompressed_size)
220 inflateEnd(&h->strm);
221 free(h);
222 }
223
224