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