xref: /optee_os/core/pta/tests/fs_htree.c (revision 623b9bd4ec219aa5d6a4eaec16d341e54ff658a9)
1963051aaSJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
2963051aaSJerome Forissier /*
3963051aaSJerome Forissier  * Copyright (c) 2017, Linaro Limited
4963051aaSJerome Forissier  */
5963051aaSJerome Forissier 
6963051aaSJerome Forissier #include <assert.h>
700b3b9a2SJens Wiklander #include <kernel/ts_manager.h>
8963051aaSJerome Forissier #include <string.h>
9963051aaSJerome Forissier #include <tee/fs_htree.h>
10963051aaSJerome Forissier #include <tee/tee_fs_rpc.h>
11963051aaSJerome Forissier #include <trace.h>
12963051aaSJerome Forissier #include <types_ext.h>
13963051aaSJerome Forissier #include <util.h>
14963051aaSJerome Forissier 
15963051aaSJerome Forissier #include "misc.h"
16963051aaSJerome Forissier 
17963051aaSJerome Forissier /*
18963051aaSJerome Forissier  * The smallest blocks size that can hold two struct
19963051aaSJerome Forissier  * tee_fs_htree_node_image or two struct tee_fs_htree_image.
20963051aaSJerome Forissier  */
21963051aaSJerome Forissier #define TEST_BLOCK_SIZE		144
22963051aaSJerome Forissier 
23963051aaSJerome Forissier struct test_aux {
24963051aaSJerome Forissier 	uint8_t *data;
25963051aaSJerome Forissier 	size_t data_len;
26963051aaSJerome Forissier 	size_t data_alloced;
27963051aaSJerome Forissier 	uint8_t *block;
28963051aaSJerome Forissier };
29963051aaSJerome Forissier 
test_get_offs_size(enum tee_fs_htree_type type,size_t idx,uint8_t vers,size_t * offs,size_t * size)30963051aaSJerome Forissier static TEE_Result test_get_offs_size(enum tee_fs_htree_type type, size_t idx,
31963051aaSJerome Forissier 				     uint8_t vers, size_t *offs, size_t *size)
32963051aaSJerome Forissier {
33963051aaSJerome Forissier 	const size_t node_size = sizeof(struct tee_fs_htree_node_image);
34963051aaSJerome Forissier 	const size_t block_nodes = TEST_BLOCK_SIZE / (node_size * 2);
35195b88beSElvira Khabirova 	size_t pbn = 0;
36195b88beSElvira Khabirova 	size_t bidx = 0;
37963051aaSJerome Forissier 
38963051aaSJerome Forissier 	COMPILE_TIME_ASSERT(TEST_BLOCK_SIZE >
39963051aaSJerome Forissier 			    sizeof(struct tee_fs_htree_node_image) * 2);
40963051aaSJerome Forissier 	COMPILE_TIME_ASSERT(TEST_BLOCK_SIZE >
41963051aaSJerome Forissier 			    sizeof(struct tee_fs_htree_image) * 2);
42963051aaSJerome Forissier 
43963051aaSJerome Forissier 	assert(vers == 0 || vers == 1);
44963051aaSJerome Forissier 
45963051aaSJerome Forissier 	/*
46963051aaSJerome Forissier 	 * File layout
47963051aaSJerome Forissier 	 *
48963051aaSJerome Forissier 	 * phys block 0:
49963051aaSJerome Forissier 	 * tee_fs_htree_image vers 0 @ offs = 0
50963051aaSJerome Forissier 	 * tee_fs_htree_image vers 1 @ offs = sizeof(tee_fs_htree_image)
51963051aaSJerome Forissier 	 *
52963051aaSJerome Forissier 	 * phys block 1:
53963051aaSJerome Forissier 	 * tee_fs_htree_node_image 0  vers 0 @ offs = 0
54963051aaSJerome Forissier 	 * tee_fs_htree_node_image 0  vers 1 @ offs = node_size
55963051aaSJerome Forissier 	 *
56963051aaSJerome Forissier 	 * phys block 2:
57963051aaSJerome Forissier 	 * data block 0 vers 0
58963051aaSJerome Forissier 	 *
59963051aaSJerome Forissier 	 * phys block 3:
60963051aaSJerome Forissier 	 * tee_fs_htree_node_image 1  vers 0 @ offs = 0
61963051aaSJerome Forissier 	 * tee_fs_htree_node_image 1  vers 1 @ offs = node_size
62963051aaSJerome Forissier 	 *
63963051aaSJerome Forissier 	 * phys block 4:
64963051aaSJerome Forissier 	 * data block 0 vers 1
65963051aaSJerome Forissier 	 *
66963051aaSJerome Forissier 	 * ...
67963051aaSJerome Forissier 	 */
68963051aaSJerome Forissier 
69963051aaSJerome Forissier 	switch (type) {
70963051aaSJerome Forissier 	case TEE_FS_HTREE_TYPE_HEAD:
71963051aaSJerome Forissier 		*offs = sizeof(struct tee_fs_htree_image) * vers;
72963051aaSJerome Forissier 		*size = sizeof(struct tee_fs_htree_image);
73963051aaSJerome Forissier 		return TEE_SUCCESS;
74963051aaSJerome Forissier 	case TEE_FS_HTREE_TYPE_NODE:
75963051aaSJerome Forissier 		pbn = 1 + ((idx / block_nodes) * block_nodes * 2);
76963051aaSJerome Forissier 		*offs = pbn * TEST_BLOCK_SIZE +
77963051aaSJerome Forissier 			2 * node_size * (idx % block_nodes) +
78963051aaSJerome Forissier 			node_size * vers;
79963051aaSJerome Forissier 		*size = node_size;
80963051aaSJerome Forissier 		return TEE_SUCCESS;
81963051aaSJerome Forissier 	case TEE_FS_HTREE_TYPE_BLOCK:
82963051aaSJerome Forissier 		bidx = 2 * idx + vers;
83963051aaSJerome Forissier 		pbn = 2 + bidx + bidx / (block_nodes * 2 - 1);
84963051aaSJerome Forissier 		*offs = pbn * TEST_BLOCK_SIZE;
85963051aaSJerome Forissier 		*size = TEST_BLOCK_SIZE;
86963051aaSJerome Forissier 		return TEE_SUCCESS;
87963051aaSJerome Forissier 	default:
88963051aaSJerome Forissier 		return TEE_ERROR_GENERIC;
89963051aaSJerome Forissier 	}
90963051aaSJerome Forissier }
91963051aaSJerome Forissier 
test_read_init(void * aux,struct tee_fs_rpc_operation * op,enum tee_fs_htree_type type,size_t idx,uint8_t vers,void ** data)92963051aaSJerome Forissier static TEE_Result test_read_init(void *aux, struct tee_fs_rpc_operation *op,
93963051aaSJerome Forissier 				 enum tee_fs_htree_type type, size_t idx,
94963051aaSJerome Forissier 				 uint8_t vers, void **data)
95963051aaSJerome Forissier {
96195b88beSElvira Khabirova 	TEE_Result res = TEE_SUCCESS;
97963051aaSJerome Forissier 	struct test_aux *a = aux;
98195b88beSElvira Khabirova 	size_t offs = 0;
99195b88beSElvira Khabirova 	size_t sz = 0;
100963051aaSJerome Forissier 
101963051aaSJerome Forissier 	res = test_get_offs_size(type, idx, vers, &offs, &sz);
102963051aaSJerome Forissier 	if (res == TEE_SUCCESS) {
103963051aaSJerome Forissier 		memset(op, 0, sizeof(*op));
104963051aaSJerome Forissier 		op->params[0].u.value.a = (vaddr_t)aux;
105963051aaSJerome Forissier 		op->params[0].u.value.b = offs;
106963051aaSJerome Forissier 		op->params[0].u.value.c = sz;
107963051aaSJerome Forissier 		*data = a->block;
108963051aaSJerome Forissier 	}
109963051aaSJerome Forissier 
110963051aaSJerome Forissier 	return res;
111963051aaSJerome Forissier }
112963051aaSJerome Forissier 
uint_to_ptr(uintptr_t p)113963051aaSJerome Forissier static void *uint_to_ptr(uintptr_t p)
114963051aaSJerome Forissier {
115963051aaSJerome Forissier 	return (void *)p;
116963051aaSJerome Forissier }
117963051aaSJerome Forissier 
test_read_final(struct tee_fs_rpc_operation * op,size_t * bytes)118963051aaSJerome Forissier static TEE_Result test_read_final(struct tee_fs_rpc_operation *op,
119963051aaSJerome Forissier 				  size_t *bytes)
120963051aaSJerome Forissier {
121963051aaSJerome Forissier 	struct test_aux *a = uint_to_ptr(op->params[0].u.value.a);
122963051aaSJerome Forissier 	size_t offs = op->params[0].u.value.b;
123963051aaSJerome Forissier 	size_t sz = op->params[0].u.value.c;
124963051aaSJerome Forissier 
125963051aaSJerome Forissier 	if (offs + sz <= a->data_len)
126963051aaSJerome Forissier 		*bytes = sz;
127963051aaSJerome Forissier 	else if (offs <= a->data_len)
128963051aaSJerome Forissier 		*bytes = a->data_len - offs;
129963051aaSJerome Forissier 	else
130963051aaSJerome Forissier 		*bytes = 0;
131963051aaSJerome Forissier 
132963051aaSJerome Forissier 	memcpy(a->block, a->data + offs, *bytes);
133963051aaSJerome Forissier 	return TEE_SUCCESS;
134963051aaSJerome Forissier }
135963051aaSJerome Forissier 
test_write_init(void * aux,struct tee_fs_rpc_operation * op,enum tee_fs_htree_type type,size_t idx,uint8_t vers,void ** data)136963051aaSJerome Forissier static TEE_Result test_write_init(void *aux, struct tee_fs_rpc_operation *op,
137963051aaSJerome Forissier 				  enum tee_fs_htree_type type, size_t idx,
138963051aaSJerome Forissier 				  uint8_t vers, void **data)
139963051aaSJerome Forissier {
140963051aaSJerome Forissier 	return test_read_init(aux, op, type, idx, vers, data);
141963051aaSJerome Forissier }
142963051aaSJerome Forissier 
test_write_final(struct tee_fs_rpc_operation * op)143963051aaSJerome Forissier static TEE_Result test_write_final(struct tee_fs_rpc_operation *op)
144963051aaSJerome Forissier {
145963051aaSJerome Forissier 	struct test_aux *a = uint_to_ptr(op->params[0].u.value.a);
146963051aaSJerome Forissier 	size_t offs = op->params[0].u.value.b;
147963051aaSJerome Forissier 	size_t sz = op->params[0].u.value.c;
148963051aaSJerome Forissier 	size_t end = offs + sz;
149963051aaSJerome Forissier 
150963051aaSJerome Forissier 	if (end > a->data_alloced) {
151963051aaSJerome Forissier 		EMSG("out of bounds");
152963051aaSJerome Forissier 		return TEE_ERROR_GENERIC;
153963051aaSJerome Forissier 	}
154963051aaSJerome Forissier 
155963051aaSJerome Forissier 	memcpy(a->data + offs, a->block, sz);
156963051aaSJerome Forissier 	if (end > a->data_len)
157963051aaSJerome Forissier 		a->data_len = end;
158963051aaSJerome Forissier 	return TEE_SUCCESS;
159963051aaSJerome Forissier 
160963051aaSJerome Forissier }
161963051aaSJerome Forissier 
162963051aaSJerome Forissier static const struct tee_fs_htree_storage test_htree_ops = {
163963051aaSJerome Forissier 	.block_size = TEST_BLOCK_SIZE,
164963051aaSJerome Forissier 	.rpc_read_init = test_read_init,
165963051aaSJerome Forissier 	.rpc_read_final = test_read_final,
166963051aaSJerome Forissier 	.rpc_write_init = test_write_init,
167963051aaSJerome Forissier 	.rpc_write_final = test_write_final,
168963051aaSJerome Forissier };
169963051aaSJerome Forissier 
170963051aaSJerome Forissier #define CHECK_RES(res, cleanup)						\
171963051aaSJerome Forissier 		do {							\
172963051aaSJerome Forissier 			TEE_Result _res = (res);			\
173963051aaSJerome Forissier 									\
174963051aaSJerome Forissier 			if (_res != TEE_SUCCESS) {			\
175963051aaSJerome Forissier 				EMSG("error: res = %#" PRIx32, _res);	\
176963051aaSJerome Forissier 				{ cleanup; }				\
177963051aaSJerome Forissier 			}						\
178963051aaSJerome Forissier 		} while (0)
179963051aaSJerome Forissier 
val_from_bn_n_salt(size_t bn,size_t n,uint8_t salt)180963051aaSJerome Forissier static uint32_t val_from_bn_n_salt(size_t bn, size_t n, uint8_t salt)
181963051aaSJerome Forissier {
182963051aaSJerome Forissier 	assert(bn < UINT16_MAX);
183963051aaSJerome Forissier 	assert(n < UINT8_MAX);
184963051aaSJerome Forissier 	return SHIFT_U32(n, 16) | SHIFT_U32(bn, 8) | salt;
185963051aaSJerome Forissier }
186963051aaSJerome Forissier 
write_block(struct tee_fs_htree ** ht,size_t bn,uint8_t salt)187963051aaSJerome Forissier static TEE_Result write_block(struct tee_fs_htree **ht, size_t bn, uint8_t salt)
188963051aaSJerome Forissier {
189195b88beSElvira Khabirova 	uint32_t b[TEST_BLOCK_SIZE / sizeof(uint32_t)] = { 0 };
190195b88beSElvira Khabirova 	size_t n = 0;
191963051aaSJerome Forissier 
192963051aaSJerome Forissier 	for (n = 0; n < ARRAY_SIZE(b); n++)
193963051aaSJerome Forissier 		b[n] = val_from_bn_n_salt(bn, n, salt);
194963051aaSJerome Forissier 
195963051aaSJerome Forissier 	return tee_fs_htree_write_block(ht, bn, b);
196963051aaSJerome Forissier }
197963051aaSJerome Forissier 
read_block(struct tee_fs_htree ** ht,size_t bn,uint8_t salt)198963051aaSJerome Forissier static TEE_Result read_block(struct tee_fs_htree **ht, size_t bn, uint8_t salt)
199963051aaSJerome Forissier {
200195b88beSElvira Khabirova 	TEE_Result res = TEE_SUCCESS;
201195b88beSElvira Khabirova 	uint32_t b[TEST_BLOCK_SIZE / sizeof(uint32_t)] = { 0 };
202195b88beSElvira Khabirova 	size_t n = 0;
203963051aaSJerome Forissier 
204963051aaSJerome Forissier 	res = tee_fs_htree_read_block(ht, bn, b);
205963051aaSJerome Forissier 	if (res != TEE_SUCCESS)
206963051aaSJerome Forissier 		return res;
207963051aaSJerome Forissier 
208963051aaSJerome Forissier 	for (n = 0; n < ARRAY_SIZE(b); n++) {
209963051aaSJerome Forissier 		if (b[n] != val_from_bn_n_salt(bn, n, salt)) {
210963051aaSJerome Forissier 			DMSG("Unpected b[%zu] %#" PRIx32
211963051aaSJerome Forissier 			     "(expected %#" PRIx32 ")",
212963051aaSJerome Forissier 			     n, b[n], val_from_bn_n_salt(bn, n, salt));
213963051aaSJerome Forissier 			return TEE_ERROR_TIME_NOT_SET;
214963051aaSJerome Forissier 		}
215963051aaSJerome Forissier 	}
216963051aaSJerome Forissier 
217963051aaSJerome Forissier 	return TEE_SUCCESS;
218963051aaSJerome Forissier }
219963051aaSJerome Forissier 
do_range(TEE_Result (* fn)(struct tee_fs_htree ** ht,size_t bn,uint8_t salt),struct tee_fs_htree ** ht,size_t begin,size_t num_blocks,size_t salt)220963051aaSJerome Forissier static TEE_Result do_range(TEE_Result (*fn)(struct tee_fs_htree **ht,
221963051aaSJerome Forissier 					    size_t bn, uint8_t salt),
222963051aaSJerome Forissier 			   struct tee_fs_htree **ht, size_t begin,
223963051aaSJerome Forissier 			   size_t num_blocks, size_t salt)
224963051aaSJerome Forissier {
225963051aaSJerome Forissier 	TEE_Result res = TEE_SUCCESS;
226195b88beSElvira Khabirova 	size_t n = 0;
227963051aaSJerome Forissier 
228963051aaSJerome Forissier 	for (n = 0; n < num_blocks; n++) {
229963051aaSJerome Forissier 		res = fn(ht, n + begin, salt);
230963051aaSJerome Forissier 		CHECK_RES(res, goto out);
231963051aaSJerome Forissier 	}
232963051aaSJerome Forissier 
233963051aaSJerome Forissier out:
234963051aaSJerome Forissier 	return res;
235963051aaSJerome Forissier }
236963051aaSJerome Forissier 
do_range_backwards(TEE_Result (* fn)(struct tee_fs_htree ** ht,size_t bn,uint8_t salt),struct tee_fs_htree ** ht,size_t begin,size_t num_blocks,size_t salt)237963051aaSJerome Forissier static TEE_Result do_range_backwards(TEE_Result (*fn)(struct tee_fs_htree **ht,
238963051aaSJerome Forissier 						      size_t bn, uint8_t salt),
239963051aaSJerome Forissier 				     struct tee_fs_htree **ht, size_t begin,
240963051aaSJerome Forissier 				     size_t num_blocks, size_t salt)
241963051aaSJerome Forissier {
242963051aaSJerome Forissier 	TEE_Result res = TEE_SUCCESS;
243195b88beSElvira Khabirova 	size_t n = 0;
244963051aaSJerome Forissier 
245963051aaSJerome Forissier 	for (n = 0; n < num_blocks; n++) {
246963051aaSJerome Forissier 		res = fn(ht, num_blocks - 1 - n + begin, salt);
247963051aaSJerome Forissier 		CHECK_RES(res, goto out);
248963051aaSJerome Forissier 	}
249963051aaSJerome Forissier 
250963051aaSJerome Forissier out:
251963051aaSJerome Forissier 	return res;
252963051aaSJerome Forissier }
253963051aaSJerome Forissier 
htree_test_rewrite(struct test_aux * aux,size_t num_blocks,size_t w_unsync_begin,size_t w_unsync_num)254963051aaSJerome Forissier static TEE_Result htree_test_rewrite(struct test_aux *aux, size_t num_blocks,
255963051aaSJerome Forissier 				     size_t w_unsync_begin, size_t w_unsync_num)
256963051aaSJerome Forissier {
25700b3b9a2SJens Wiklander 	struct ts_session *sess = ts_get_current_session();
25800b3b9a2SJens Wiklander 	const TEE_UUID *uuid = &sess->ctx->uuid;
25900b3b9a2SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
260963051aaSJerome Forissier 	struct tee_fs_htree *ht = NULL;
261963051aaSJerome Forissier 	size_t salt = 23;
26200b3b9a2SJens Wiklander 	uint8_t hash[TEE_FS_HTREE_HASH_SIZE] = { 0 };
263963051aaSJerome Forissier 
264963051aaSJerome Forissier 	assert((w_unsync_begin + w_unsync_num) <= num_blocks);
265963051aaSJerome Forissier 
266963051aaSJerome Forissier 	aux->data_len = 0;
267963051aaSJerome Forissier 	memset(aux->data, 0xce, aux->data_alloced);
268963051aaSJerome Forissier 
269*623b9bd4SJens Wiklander 	res = tee_fs_htree_open(true, hash, 0, uuid, &test_htree_ops, aux, &ht);
270963051aaSJerome Forissier 	CHECK_RES(res, goto out);
271963051aaSJerome Forissier 
272963051aaSJerome Forissier 	/*
273963051aaSJerome Forissier 	 * Intialize all blocks and verify that they read back as
274963051aaSJerome Forissier 	 * expected.
275963051aaSJerome Forissier 	 */
276963051aaSJerome Forissier 	res = do_range(write_block, &ht, 0, num_blocks, salt);
277963051aaSJerome Forissier 	CHECK_RES(res, goto out);
278963051aaSJerome Forissier 
279963051aaSJerome Forissier 	res = do_range(read_block, &ht, 0, num_blocks, salt);
280963051aaSJerome Forissier 	CHECK_RES(res, goto out);
281963051aaSJerome Forissier 
282963051aaSJerome Forissier 	/*
283963051aaSJerome Forissier 	 * Write all blocks again, but starting from the end using a new
284963051aaSJerome Forissier 	 * salt, then verify that that read back as expected.
285963051aaSJerome Forissier 	 */
286963051aaSJerome Forissier 	salt++;
287963051aaSJerome Forissier 	res = do_range_backwards(write_block, &ht, 0, num_blocks, salt);
288963051aaSJerome Forissier 	CHECK_RES(res, goto out);
289963051aaSJerome Forissier 
290963051aaSJerome Forissier 	res = do_range(read_block, &ht, 0, num_blocks, salt);
291963051aaSJerome Forissier 	CHECK_RES(res, goto out);
292963051aaSJerome Forissier 
293963051aaSJerome Forissier 	/*
294963051aaSJerome Forissier 	 * Use a new salt to write all blocks once more and verify that
295963051aaSJerome Forissier 	 * they read back as expected.
296963051aaSJerome Forissier 	 */
297963051aaSJerome Forissier 	salt++;
298963051aaSJerome Forissier 	res = do_range(write_block, &ht, 0, num_blocks, salt);
299963051aaSJerome Forissier 	CHECK_RES(res, goto out);
300963051aaSJerome Forissier 
301963051aaSJerome Forissier 	res = do_range(read_block, &ht, 0, num_blocks, salt);
302963051aaSJerome Forissier 	CHECK_RES(res, goto out);
303963051aaSJerome Forissier 
304963051aaSJerome Forissier 	/*
305963051aaSJerome Forissier 	 * Sync the changes of the nodes to memory, verify that all
306963051aaSJerome Forissier 	 * blocks are read back as expected.
307963051aaSJerome Forissier 	 */
308*623b9bd4SJens Wiklander 	res = tee_fs_htree_sync_to_storage(&ht, hash, NULL);
309963051aaSJerome Forissier 	CHECK_RES(res, goto out);
310963051aaSJerome Forissier 
311963051aaSJerome Forissier 	res = do_range(read_block, &ht, 0, num_blocks, salt);
312963051aaSJerome Forissier 	CHECK_RES(res, goto out);
313963051aaSJerome Forissier 
314963051aaSJerome Forissier 	/*
315963051aaSJerome Forissier 	 * Close and reopen the hash-tree
316963051aaSJerome Forissier 	 */
317963051aaSJerome Forissier 	tee_fs_htree_close(&ht);
318*623b9bd4SJens Wiklander 	res = tee_fs_htree_open(false, hash, 0, uuid, &test_htree_ops, aux,
319*623b9bd4SJens Wiklander 				&ht);
320963051aaSJerome Forissier 	CHECK_RES(res, goto out);
321963051aaSJerome Forissier 
322963051aaSJerome Forissier 	/*
323963051aaSJerome Forissier 	 * Verify that all blocks are read as expected.
324963051aaSJerome Forissier 	 */
325963051aaSJerome Forissier 	res = do_range(read_block, &ht, 0, num_blocks, salt);
326963051aaSJerome Forissier 	CHECK_RES(res, goto out);
327963051aaSJerome Forissier 
328963051aaSJerome Forissier 	/*
329963051aaSJerome Forissier 	 * Rewrite a few blocks and verify that all blocks are read as
330963051aaSJerome Forissier 	 * expected.
331963051aaSJerome Forissier 	 */
332963051aaSJerome Forissier 	res = do_range_backwards(write_block, &ht, w_unsync_begin, w_unsync_num,
333963051aaSJerome Forissier 				 salt + 1);
334963051aaSJerome Forissier 	CHECK_RES(res, goto out);
335963051aaSJerome Forissier 
336963051aaSJerome Forissier 	res = do_range(read_block, &ht, 0, w_unsync_begin, salt);
337963051aaSJerome Forissier 	CHECK_RES(res, goto out);
338963051aaSJerome Forissier 	res = do_range(read_block, &ht, w_unsync_begin, w_unsync_num, salt + 1);
339963051aaSJerome Forissier 	CHECK_RES(res, goto out);
340963051aaSJerome Forissier 	res = do_range(read_block, &ht, w_unsync_begin + w_unsync_num,
341963051aaSJerome Forissier 			num_blocks - (w_unsync_begin + w_unsync_num), salt);
342963051aaSJerome Forissier 	CHECK_RES(res, goto out);
343963051aaSJerome Forissier 
344963051aaSJerome Forissier 	/*
345963051aaSJerome Forissier 	 * Rewrite the blocks from above again with another salt and
346963051aaSJerome Forissier 	 * verify that they are read back as expected.
347963051aaSJerome Forissier 	 */
348963051aaSJerome Forissier 	res = do_range(write_block, &ht, w_unsync_begin, w_unsync_num,
349963051aaSJerome Forissier 		       salt + 2);
350963051aaSJerome Forissier 	CHECK_RES(res, goto out);
351963051aaSJerome Forissier 
352963051aaSJerome Forissier 	res = do_range(read_block, &ht, 0, w_unsync_begin, salt);
353963051aaSJerome Forissier 	CHECK_RES(res, goto out);
354963051aaSJerome Forissier 	res = do_range(read_block, &ht, w_unsync_begin, w_unsync_num, salt + 2);
355963051aaSJerome Forissier 	CHECK_RES(res, goto out);
356963051aaSJerome Forissier 	res = do_range(read_block, &ht, w_unsync_begin + w_unsync_num,
357963051aaSJerome Forissier 			num_blocks - (w_unsync_begin + w_unsync_num), salt);
358963051aaSJerome Forissier 	CHECK_RES(res, goto out);
359963051aaSJerome Forissier 
360963051aaSJerome Forissier 	/*
361963051aaSJerome Forissier 	 * Skip tee_fs_htree_sync_to_storage() and call
362963051aaSJerome Forissier 	 * tee_fs_htree_close() directly to undo the changes since last
363963051aaSJerome Forissier 	 * call to tee_fs_htree_sync_to_storage().  Reopen the hash-tree
364963051aaSJerome Forissier 	 * and verify that recent changes indeed was discarded.
365963051aaSJerome Forissier 	 */
366963051aaSJerome Forissier 	tee_fs_htree_close(&ht);
367*623b9bd4SJens Wiklander 	res = tee_fs_htree_open(false, hash, 0, uuid, &test_htree_ops, aux,
368*623b9bd4SJens Wiklander 				&ht);
369963051aaSJerome Forissier 	CHECK_RES(res, goto out);
370963051aaSJerome Forissier 
371963051aaSJerome Forissier 	res = do_range(read_block, &ht, 0, num_blocks, salt);
372963051aaSJerome Forissier 	CHECK_RES(res, goto out);
373963051aaSJerome Forissier 
374963051aaSJerome Forissier 	/*
375963051aaSJerome Forissier 	 * Close, reopen and verify that all blocks are read as expected
376963051aaSJerome Forissier 	 * again but this time based on the counter value in struct
377963051aaSJerome Forissier 	 * tee_fs_htree_image.
378963051aaSJerome Forissier 	 */
379963051aaSJerome Forissier 	tee_fs_htree_close(&ht);
380*623b9bd4SJens Wiklander 	res = tee_fs_htree_open(false, NULL, 0, uuid, &test_htree_ops, aux,
381*623b9bd4SJens Wiklander 				&ht);
382963051aaSJerome Forissier 	CHECK_RES(res, goto out);
383963051aaSJerome Forissier 
384963051aaSJerome Forissier 	res = do_range(read_block, &ht, 0, num_blocks, salt);
385963051aaSJerome Forissier 	CHECK_RES(res, goto out);
386963051aaSJerome Forissier 
387963051aaSJerome Forissier out:
388963051aaSJerome Forissier 	tee_fs_htree_close(&ht);
389963051aaSJerome Forissier 	/*
390963051aaSJerome Forissier 	 * read_block() returns TEE_ERROR_TIME_NOT_SET in case unexpected
391963051aaSJerome Forissier 	 * data is read.
392963051aaSJerome Forissier 	 */
393963051aaSJerome Forissier 	if (res == TEE_ERROR_TIME_NOT_SET)
394963051aaSJerome Forissier 		res = TEE_ERROR_SECURITY;
395963051aaSJerome Forissier 	return res;
396963051aaSJerome Forissier }
397963051aaSJerome Forissier 
aux_free(struct test_aux * aux)398963051aaSJerome Forissier static void aux_free(struct test_aux *aux)
399963051aaSJerome Forissier {
400963051aaSJerome Forissier 	if (aux) {
401963051aaSJerome Forissier 		free(aux->data);
402963051aaSJerome Forissier 		free(aux->block);
403963051aaSJerome Forissier 		free(aux);
404963051aaSJerome Forissier 	}
405963051aaSJerome Forissier }
406963051aaSJerome Forissier 
aux_alloc(size_t num_blocks)407963051aaSJerome Forissier static struct test_aux *aux_alloc(size_t num_blocks)
408963051aaSJerome Forissier {
409195b88beSElvira Khabirova 	struct test_aux *aux = NULL;
410195b88beSElvira Khabirova 	size_t o = 0;
411195b88beSElvira Khabirova 	size_t sz = 0;
412963051aaSJerome Forissier 
413963051aaSJerome Forissier 	if (test_get_offs_size(TEE_FS_HTREE_TYPE_BLOCK, num_blocks, 1, &o, &sz))
414963051aaSJerome Forissier 		return NULL;
415963051aaSJerome Forissier 
416963051aaSJerome Forissier 	aux = calloc(1, sizeof(*aux));
417963051aaSJerome Forissier 	if (!aux)
418963051aaSJerome Forissier 		return NULL;
419963051aaSJerome Forissier 
420963051aaSJerome Forissier 	aux->data_alloced = o + sz;
421963051aaSJerome Forissier 	aux->data = malloc(aux->data_alloced);
422963051aaSJerome Forissier 	if (!aux->data)
423963051aaSJerome Forissier 		goto err;
424963051aaSJerome Forissier 
425963051aaSJerome Forissier 	aux->block = malloc(TEST_BLOCK_SIZE);
426963051aaSJerome Forissier 	if (!aux->block)
427963051aaSJerome Forissier 		goto err;
428963051aaSJerome Forissier 
429963051aaSJerome Forissier 	return aux;
430963051aaSJerome Forissier err:
431963051aaSJerome Forissier 	aux_free(aux);
432963051aaSJerome Forissier 	return NULL;
433963051aaSJerome Forissier 
434963051aaSJerome Forissier }
435963051aaSJerome Forissier 
test_write_read(size_t num_blocks)436963051aaSJerome Forissier static TEE_Result test_write_read(size_t num_blocks)
437963051aaSJerome Forissier {
438963051aaSJerome Forissier 	struct test_aux *aux = aux_alloc(num_blocks);
439e1761059SElvira Khabirova 	TEE_Result res = TEE_SUCCESS;
440195b88beSElvira Khabirova 	size_t n = 0;
441195b88beSElvira Khabirova 	size_t m = 0;
442195b88beSElvira Khabirova 	size_t o = 0;
443963051aaSJerome Forissier 
444963051aaSJerome Forissier 	if (!aux)
445963051aaSJerome Forissier 		return TEE_ERROR_OUT_OF_MEMORY;
446963051aaSJerome Forissier 
447963051aaSJerome Forissier 	/*
448963051aaSJerome Forissier 	 * n is the number of block we're going to initialize/use.
449963051aaSJerome Forissier 	 * m is the offset from where we'll rewrite blocks and expect
450963051aaSJerome Forissier 	 * the changes to be visible until tee_fs_htree_close() is called
451963051aaSJerome Forissier 	 * without a call to tee_fs_htree_sync_to_storage() before.
452963051aaSJerome Forissier 	 * o is the number of blocks we're rewriting starting at m.
453963051aaSJerome Forissier 	 */
454963051aaSJerome Forissier 	for (n = 0; n < num_blocks; n += 3) {
455963051aaSJerome Forissier 		for (m = 0; m < n; m += 3) {
456963051aaSJerome Forissier 			for (o = 0; o < (n - m); o++) {
457963051aaSJerome Forissier 				res = htree_test_rewrite(aux, n, m, o);
458963051aaSJerome Forissier 				CHECK_RES(res, goto out);
459963051aaSJerome Forissier 				o += 2;
460963051aaSJerome Forissier 			}
461963051aaSJerome Forissier 		}
462963051aaSJerome Forissier 	}
463963051aaSJerome Forissier 
464963051aaSJerome Forissier out:
465963051aaSJerome Forissier 	aux_free(aux);
466963051aaSJerome Forissier 	return res;
467963051aaSJerome Forissier }
468963051aaSJerome Forissier 
test_corrupt_type(const TEE_UUID * uuid,uint8_t * hash,size_t num_blocks,struct test_aux * aux,enum tee_fs_htree_type type,size_t idx)469963051aaSJerome Forissier static TEE_Result test_corrupt_type(const TEE_UUID *uuid, uint8_t *hash,
470963051aaSJerome Forissier 				    size_t num_blocks, struct test_aux *aux,
471963051aaSJerome Forissier 				    enum tee_fs_htree_type type, size_t idx)
472963051aaSJerome Forissier {
473195b88beSElvira Khabirova 	TEE_Result res = TEE_SUCCESS;
474963051aaSJerome Forissier 	struct test_aux aux2 = *aux;
475963051aaSJerome Forissier 	struct tee_fs_htree *ht = NULL;
476195b88beSElvira Khabirova 	size_t offs = 0;
477195b88beSElvira Khabirova 	size_t size = 0;
478195b88beSElvira Khabirova 	size_t size0 = 0;
479195b88beSElvira Khabirova 	size_t n = 0;
480963051aaSJerome Forissier 
481963051aaSJerome Forissier 	res = test_get_offs_size(type, idx, 0, &offs, &size0);
482963051aaSJerome Forissier 	CHECK_RES(res, return res);
483963051aaSJerome Forissier 
484963051aaSJerome Forissier 	aux2.data = malloc(aux->data_alloced);
485963051aaSJerome Forissier 	if (!aux2.data)
486963051aaSJerome Forissier 		return TEE_ERROR_OUT_OF_MEMORY;
487963051aaSJerome Forissier 
488963051aaSJerome Forissier 	n = 0;
489963051aaSJerome Forissier 	while (true) {
490963051aaSJerome Forissier 		memcpy(aux2.data, aux->data, aux->data_len);
491963051aaSJerome Forissier 
492963051aaSJerome Forissier 		res = test_get_offs_size(type, idx, 0, &offs, &size);
493963051aaSJerome Forissier 		CHECK_RES(res, goto out);
494963051aaSJerome Forissier 		aux2.data[offs + n]++;
495963051aaSJerome Forissier 		res = test_get_offs_size(type, idx, 1, &offs, &size);
496963051aaSJerome Forissier 		CHECK_RES(res, goto out);
497963051aaSJerome Forissier 		aux2.data[offs + n]++;
498963051aaSJerome Forissier 
499963051aaSJerome Forissier 		/*
500963051aaSJerome Forissier 		 * Errors in head or node is detected by
501963051aaSJerome Forissier 		 * tee_fs_htree_open() errors in block is detected when
502963051aaSJerome Forissier 		 * actually read by do_range(read_block)
503963051aaSJerome Forissier 		 */
504*623b9bd4SJens Wiklander 		res = tee_fs_htree_open(false, hash, 0, uuid, &test_htree_ops,
505963051aaSJerome Forissier 					&aux2, &ht);
506963051aaSJerome Forissier 		if (!res) {
507963051aaSJerome Forissier 			res = do_range(read_block, &ht, 0, num_blocks, 1);
508963051aaSJerome Forissier 			/*
509963051aaSJerome Forissier 			 * do_range(read_block,) is supposed to detect the
510963051aaSJerome Forissier 			 * error. If TEE_ERROR_TIME_NOT_SET is returned
511963051aaSJerome Forissier 			 * read_block() was acutally able to get some data,
512963051aaSJerome Forissier 			 * but the data was incorrect.
513963051aaSJerome Forissier 			 *
514963051aaSJerome Forissier 			 * If res == TEE_SUCCESS or
515963051aaSJerome Forissier 			 *    res == TEE_ERROR_TIME_NOT_SET
516963051aaSJerome Forissier 			 * there's some problem with the htree
517963051aaSJerome Forissier 			 * implementation.
518963051aaSJerome Forissier 			 */
519963051aaSJerome Forissier 			if (res == TEE_ERROR_TIME_NOT_SET) {
520963051aaSJerome Forissier 				EMSG("error: data silently corrupted");
521963051aaSJerome Forissier 				res = TEE_ERROR_SECURITY;
522963051aaSJerome Forissier 				goto out;
523963051aaSJerome Forissier 			}
524963051aaSJerome Forissier 			if (!res)
525963051aaSJerome Forissier 				break;
526963051aaSJerome Forissier 			tee_fs_htree_close(&ht);
527963051aaSJerome Forissier 		}
528963051aaSJerome Forissier 
529963051aaSJerome Forissier 		/* We've tested the last byte, let's get out of here */
530963051aaSJerome Forissier 		if (n == size0 - 1)
531963051aaSJerome Forissier 			break;
532963051aaSJerome Forissier 
533963051aaSJerome Forissier 		/* Increase n exponentionally after 1 to skip some testing */
534963051aaSJerome Forissier 		if (n)
535963051aaSJerome Forissier 			n += n;
536963051aaSJerome Forissier 		else
537963051aaSJerome Forissier 			n = 1;
538963051aaSJerome Forissier 
539963051aaSJerome Forissier 		/* Make sure we test the last byte too */
540963051aaSJerome Forissier 		if (n >= size0)
541963051aaSJerome Forissier 			n = size0 - 1;
542963051aaSJerome Forissier 	}
543963051aaSJerome Forissier 
544963051aaSJerome Forissier 	if (res) {
545963051aaSJerome Forissier 		res = TEE_SUCCESS;
546963051aaSJerome Forissier 	} else {
547963051aaSJerome Forissier 		EMSG("error: data corruption undetected");
548963051aaSJerome Forissier 		res = TEE_ERROR_SECURITY;
549963051aaSJerome Forissier 	}
550963051aaSJerome Forissier out:
551963051aaSJerome Forissier 	free(aux2.data);
552963051aaSJerome Forissier 	tee_fs_htree_close(&ht);
553963051aaSJerome Forissier 	return res;
554963051aaSJerome Forissier }
555963051aaSJerome Forissier 
556963051aaSJerome Forissier 
557963051aaSJerome Forissier 
test_corrupt(size_t num_blocks)558963051aaSJerome Forissier static TEE_Result test_corrupt(size_t num_blocks)
559963051aaSJerome Forissier {
56000b3b9a2SJens Wiklander 	struct ts_session *sess = ts_get_current_session();
56100b3b9a2SJens Wiklander 	const TEE_UUID *uuid = &sess->ctx->uuid;
56200b3b9a2SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
563963051aaSJerome Forissier 	struct tee_fs_htree *ht = NULL;
56400b3b9a2SJens Wiklander 	uint8_t hash[TEE_FS_HTREE_HASH_SIZE] = { 0 };
56500b3b9a2SJens Wiklander 	struct test_aux *aux = NULL;
56600b3b9a2SJens Wiklander 	size_t n = 0;
567963051aaSJerome Forissier 
568963051aaSJerome Forissier 	aux = aux_alloc(num_blocks);
569963051aaSJerome Forissier 	if (!aux) {
570963051aaSJerome Forissier 		res = TEE_ERROR_OUT_OF_MEMORY;
571963051aaSJerome Forissier 		goto out;
572963051aaSJerome Forissier 	}
573963051aaSJerome Forissier 
574963051aaSJerome Forissier 	aux->data_len = 0;
575963051aaSJerome Forissier 	memset(aux->data, 0xce, aux->data_alloced);
576963051aaSJerome Forissier 
577963051aaSJerome Forissier 	/* Write the object and close it */
578*623b9bd4SJens Wiklander 	res = tee_fs_htree_open(true, hash, 0, uuid, &test_htree_ops, aux, &ht);
579963051aaSJerome Forissier 	CHECK_RES(res, goto out);
580963051aaSJerome Forissier 	res = do_range(write_block, &ht, 0, num_blocks, 1);
581963051aaSJerome Forissier 	CHECK_RES(res, goto out);
582*623b9bd4SJens Wiklander 	res = tee_fs_htree_sync_to_storage(&ht, hash, NULL);
583963051aaSJerome Forissier 	CHECK_RES(res, goto out);
584963051aaSJerome Forissier 	tee_fs_htree_close(&ht);
585963051aaSJerome Forissier 
586963051aaSJerome Forissier 	/* Verify that the object can be read correctly */
587*623b9bd4SJens Wiklander 	res = tee_fs_htree_open(false, hash, 0, uuid, &test_htree_ops, aux,
588*623b9bd4SJens Wiklander 				&ht);
589963051aaSJerome Forissier 	CHECK_RES(res, goto out);
590963051aaSJerome Forissier 	res = do_range(read_block, &ht, 0, num_blocks, 1);
591963051aaSJerome Forissier 	CHECK_RES(res, goto out);
592963051aaSJerome Forissier 	tee_fs_htree_close(&ht);
593963051aaSJerome Forissier 
594963051aaSJerome Forissier 	res = test_corrupt_type(uuid, hash, num_blocks, aux,
595963051aaSJerome Forissier 				TEE_FS_HTREE_TYPE_HEAD, 0);
596963051aaSJerome Forissier 	CHECK_RES(res, goto out);
597963051aaSJerome Forissier 	for (n = 0; n < num_blocks; n++) {
598963051aaSJerome Forissier 		res = test_corrupt_type(uuid, hash, num_blocks, aux,
599963051aaSJerome Forissier 					TEE_FS_HTREE_TYPE_NODE, n);
600963051aaSJerome Forissier 		CHECK_RES(res, goto out);
601963051aaSJerome Forissier 	}
602963051aaSJerome Forissier 	for (n = 0; n < num_blocks; n++) {
603963051aaSJerome Forissier 		res = test_corrupt_type(uuid, hash, num_blocks, aux,
604963051aaSJerome Forissier 					TEE_FS_HTREE_TYPE_BLOCK, n);
605963051aaSJerome Forissier 		CHECK_RES(res, goto out);
606963051aaSJerome Forissier 	}
607963051aaSJerome Forissier 
608963051aaSJerome Forissier out:
609963051aaSJerome Forissier 	tee_fs_htree_close(&ht);
610963051aaSJerome Forissier 	aux_free(aux);
611963051aaSJerome Forissier 	return res;
612963051aaSJerome Forissier }
613963051aaSJerome Forissier 
core_fs_htree_tests(uint32_t nParamTypes,TEE_Param pParams[TEE_NUM_PARAMS]__unused)614963051aaSJerome Forissier TEE_Result core_fs_htree_tests(uint32_t nParamTypes,
615963051aaSJerome Forissier 			       TEE_Param pParams[TEE_NUM_PARAMS] __unused)
616963051aaSJerome Forissier {
617195b88beSElvira Khabirova 	TEE_Result res = TEE_SUCCESS;
618963051aaSJerome Forissier 
619963051aaSJerome Forissier 	if (nParamTypes)
620963051aaSJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
621963051aaSJerome Forissier 
622963051aaSJerome Forissier 	res = test_write_read(10);
623963051aaSJerome Forissier 	if (res)
624963051aaSJerome Forissier 		return res;
625963051aaSJerome Forissier 
626963051aaSJerome Forissier 	return test_corrupt(5);
627963051aaSJerome Forissier }
628