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 <mempool.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <trace.h>
15 #include <utee_defines.h>
16 #include <util.h>
17 #include <zlib.h>
18 
19 struct ts_store_handle {
20 	const struct embedded_ts *ts;
21 	size_t offs;
22 	z_stream strm;
23 };
24 
zalloc(void * opaque __unused,unsigned int items,unsigned int size)25 static void *zalloc(void *opaque __unused, unsigned int items,
26 		    unsigned int size)
27 {
28 	return mempool_alloc(mempool_default, items * size);
29 }
30 
zfree(void * opaque __unused,void * address)31 static void zfree(void *opaque __unused, void *address)
32 {
33 	mempool_free(mempool_default, address);
34 }
35 
decompression_init(z_stream * strm,const struct embedded_ts * ts)36 static bool decompression_init(z_stream *strm,
37 			       const struct embedded_ts *ts)
38 {
39 	int st = Z_OK;
40 
41 	strm->next_in = ts->ts;
42 	strm->avail_in = ts->size;
43 	strm->zalloc = zalloc;
44 	strm->zfree = zfree;
45 	st = inflateInit(strm);
46 	if (st != Z_OK) {
47 		EMSG("Decompression initialization error (%d)", st);
48 		return false;
49 	}
50 
51 	return true;
52 }
53 
emb_ts_open(const TEE_UUID * uuid,struct ts_store_handle ** h,const struct embedded_ts * (* find_ts)(const TEE_UUID * uuid))54 TEE_Result emb_ts_open(const TEE_UUID *uuid,
55 		       struct ts_store_handle **h,
56 		       const struct embedded_ts*
57 		       (*find_ts) (const TEE_UUID *uuid))
58 {
59 	struct ts_store_handle *handle = NULL;
60 	const struct embedded_ts *ts = NULL;
61 
62 	ts = find_ts(uuid);
63 	if (!ts)
64 		return TEE_ERROR_ITEM_NOT_FOUND;
65 
66 	handle = calloc(1, sizeof(*handle));
67 	if (!handle)
68 		return TEE_ERROR_OUT_OF_MEMORY;
69 
70 	if (ts->uncompressed_size) {
71 		if (!decompression_init(&handle->strm, ts)) {
72 			free(handle);
73 			return TEE_ERROR_BAD_FORMAT;
74 		}
75 	}
76 	handle->ts = ts;
77 	*h = handle;
78 
79 	return TEE_SUCCESS;
80 }
81 
emb_ts_get_size(const struct ts_store_handle * h,size_t * size)82 TEE_Result emb_ts_get_size(const struct ts_store_handle *h, size_t *size)
83 {
84 	const struct embedded_ts *ts = h->ts;
85 
86 	if (ts->uncompressed_size)
87 		*size = ts->uncompressed_size;
88 	else
89 		*size = ts->size;
90 
91 	return TEE_SUCCESS;
92 }
93 
emb_ts_get_tag(const struct ts_store_handle * h,uint8_t * tag,unsigned int * tag_len)94 TEE_Result emb_ts_get_tag(const struct ts_store_handle *h,
95 			  uint8_t *tag, unsigned int *tag_len)
96 {
97 	TEE_Result res = TEE_SUCCESS;
98 	void *ctx = NULL;
99 
100 	if (!tag || *tag_len < TEE_SHA256_HASH_SIZE) {
101 		*tag_len = TEE_SHA256_HASH_SIZE;
102 		return TEE_ERROR_SHORT_BUFFER;
103 	}
104 	*tag_len = TEE_SHA256_HASH_SIZE;
105 
106 	res = crypto_hash_alloc_ctx(&ctx, TEE_ALG_SHA256);
107 	if (res)
108 		return res;
109 	res = crypto_hash_init(ctx);
110 	if (res)
111 		goto out;
112 	res = crypto_hash_update(ctx, h->ts->ts, h->ts->size);
113 	if (res)
114 		goto out;
115 	res = crypto_hash_final(ctx, tag, *tag_len);
116 out:
117 	crypto_hash_free_ctx(ctx);
118 	return res;
119 }
120 
read_uncompressed(struct ts_store_handle * h,void * data,size_t len)121 static TEE_Result read_uncompressed(struct ts_store_handle *h, void *data,
122 				    size_t len)
123 {
124 	uint8_t *src = (uint8_t *)h->ts->ts + h->offs;
125 	size_t next_offs = 0;
126 
127 	if (ADD_OVERFLOW(h->offs, len, &next_offs) ||
128 	    next_offs > h->ts->size)
129 		return TEE_ERROR_BAD_PARAMETERS;
130 	if (data)
131 		memcpy(data, src, len);
132 	h->offs = next_offs;
133 
134 	return TEE_SUCCESS;
135 }
136 
read_compressed(struct ts_store_handle * h,void * data,size_t len)137 static TEE_Result read_compressed(struct ts_store_handle *h, void *data,
138 				  size_t len)
139 {
140 	z_stream *strm = &h->strm;
141 	size_t total = 0;
142 	uint8_t *tmpbuf = NULL;
143 	TEE_Result ret = TEE_SUCCESS;
144 	size_t out = 0;
145 	int st = Z_OK;
146 
147 	if (data) {
148 		strm->next_out = data;
149 		strm->avail_out = len;
150 	} else {
151 		/*
152 		 * inflate() does not support a NULL strm->next_out. So, to
153 		 * discard data, we have to allocate a temporary buffer. 1K
154 		 * seems reasonable.
155 		 */
156 		strm->avail_out = MIN(len, 1024U);
157 		tmpbuf = malloc(strm->avail_out);
158 		if (!tmpbuf) {
159 			EMSG("Out of memory");
160 			return TEE_ERROR_OUT_OF_MEMORY;
161 		}
162 		strm->next_out = tmpbuf;
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 		total += out;
179 		FMSG("%zu bytes", out);
180 		if (!data) {
181 			/*
182 			 * Reset the pointer to throw away what we've just read
183 			 * and read again as much as possible.
184 			 */
185 			strm->next_out = tmpbuf;
186 			strm->avail_out = MIN(len - total, 1024U);
187 		}
188 	} while ((st == Z_OK || st == Z_BUF_ERROR) && (total != len));
189 
190 	if (st != Z_OK && st != Z_STREAM_END) {
191 		EMSG("Decompression error (%d)", st);
192 		ret = TEE_ERROR_GENERIC;
193 		goto out;
194 	}
195 	ret = TEE_SUCCESS;
196 out:
197 	free(tmpbuf);
198 
199 	return ret;
200 }
201 
emb_ts_read(struct ts_store_handle * h,void * data,size_t len)202 TEE_Result emb_ts_read(struct ts_store_handle *h, void *data, size_t len)
203 {
204 	if (h->ts->uncompressed_size)
205 		return read_compressed(h, data, len);
206 	else
207 		return read_uncompressed(h, data, len);
208 }
209 
emb_ts_close(struct ts_store_handle * h)210 void emb_ts_close(struct ts_store_handle *h)
211 {
212 	if (h->ts->uncompressed_size)
213 		inflateEnd(&h->strm);
214 	free(h);
215 }
216 
217