xref: /optee_os/core/tee/fs_dirfile.c (revision d7767217cb365fd91f5d592d1c96f0476cef811b)
1 /*
2  * Copyright (c) 2017, Linaro Limited
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <assert.h>
29 #include <bitstring.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <tee/fs_dirfile.h>
34 #include <types_ext.h>
35 
36 struct tee_fs_dirfile_dirh {
37 	const TEE_UUID *uuid;
38 	const struct tee_fs_dirfile_operations *fops;
39 	struct tee_file_handle *fh;
40 	int nbits;
41 	bitstr_t *files;
42 	size_t ndents;
43 };
44 
45 struct dirfile_entry {
46 	TEE_UUID uuid;
47 	uint8_t oid[TEE_OBJECT_ID_MAX_LEN];
48 	uint32_t oidlen;
49 	uint8_t hash[TEE_FS_HTREE_HASH_SIZE];
50 	uint32_t file_number;
51 };
52 
53 /*
54  * File layout
55  *
56  * dirfile_entry.0
57  * ...
58  * dirfile_entry.n
59  *
60  * where n the index is disconnected from file_number in struct dirfile_entry
61  */
62 
63 static TEE_Result maybe_grow_files(struct tee_fs_dirfile_dirh *dirh, int idx)
64 {
65 	void *p;
66 
67 	if (idx < dirh->nbits)
68 		return TEE_SUCCESS;
69 
70 	p = realloc(dirh->files, bitstr_size(idx + 1));
71 	if (!p)
72 		return TEE_ERROR_OUT_OF_MEMORY;
73 	dirh->files = p;
74 
75 	bit_nclear(dirh->files, dirh->nbits, idx);
76 	dirh->nbits = idx + 1;
77 
78 	return TEE_SUCCESS;
79 }
80 
81 static TEE_Result set_file(struct tee_fs_dirfile_dirh *dirh, int idx)
82 {
83 	TEE_Result res = maybe_grow_files(dirh, idx);
84 
85 	if (!res)
86 		bit_set(dirh->files, idx);
87 
88 	return res;
89 }
90 
91 static void clear_file(struct tee_fs_dirfile_dirh *dirh, int idx)
92 {
93 	if (idx < dirh->nbits)
94 		bit_clear(dirh->files, idx);
95 }
96 
97 static bool test_file(struct tee_fs_dirfile_dirh *dirh, int idx)
98 {
99 	if (idx < dirh->nbits)
100 		return bit_test(dirh->files, idx);
101 
102 	return false;
103 }
104 
105 static TEE_Result read_dent(struct tee_fs_dirfile_dirh *dirh, int idx,
106 			    struct dirfile_entry *dent)
107 {
108 	TEE_Result res;
109 	size_t l;
110 
111 	l = sizeof(*dent);
112 	res = dirh->fops->read(dirh->fh, sizeof(struct dirfile_entry) * idx,
113 			       dent, &l);
114 	if (!res && l != sizeof(*dent))
115 		res = TEE_ERROR_ITEM_NOT_FOUND;
116 
117 	return res;
118 }
119 
120 static TEE_Result write_dent(struct tee_fs_dirfile_dirh *dirh, size_t n,
121 			     struct dirfile_entry *dent)
122 {
123 	TEE_Result res;
124 
125 	res = dirh->fops->write(dirh->fh, sizeof(*dent) * n,
126 				dent, sizeof(*dent));
127 	if (!res && n >= dirh->ndents)
128 		dirh->ndents = n + 1;
129 
130 	return res;
131 }
132 
133 TEE_Result tee_fs_dirfile_open(const TEE_UUID *uuid,
134 			       const struct tee_fs_dirfile_operations *fops,
135 			       struct tee_fs_dirfile_dirh **dirh_ret)
136 {
137 	TEE_Result res;
138 	struct tee_fs_dirfile_dirh *dirh = calloc(1, sizeof(*dirh));
139 	size_t n;
140 
141 	if (!dirh)
142 		return TEE_ERROR_OUT_OF_MEMORY;
143 
144 	dirh->uuid = uuid;
145 	dirh->fops = fops;
146 	res = fops->open(false, NULL, NULL, &dirh->fh);
147 	if (res) {
148 		res = fops->open(true, NULL, NULL, &dirh->fh);
149 		if (res)
150 			goto out;
151 	}
152 
153 	for (n = 0;; n++) {
154 		struct dirfile_entry dent;
155 
156 		res = read_dent(dirh, n, &dent);
157 		if (res) {
158 			if (res == TEE_ERROR_ITEM_NOT_FOUND)
159 				res = TEE_SUCCESS;
160 			goto out;
161 		}
162 
163 		if (!dent.oidlen)
164 			continue;
165 
166 		if (test_file(dirh, dent.file_number)) {
167 			DMSG("clearing duplicate file number %" PRIu32,
168 			     dent.file_number);
169 			memset(&dent, 0, sizeof(dent));
170 			res = write_dent(dirh, n, &dent);
171 			if (res)
172 				goto out;
173 			continue;
174 		}
175 
176 		res = set_file(dirh, dent.file_number);
177 		if (res != TEE_SUCCESS)
178 			goto out;
179 	}
180 out:
181 	if (!res) {
182 		dirh->ndents = n;
183 		*dirh_ret = dirh;
184 	} else {
185 		tee_fs_dirfile_close(dirh);
186 	}
187 	return res;
188 }
189 
190 void tee_fs_dirfile_close(struct tee_fs_dirfile_dirh *dirh)
191 {
192 	if (dirh) {
193 		dirh->fops->close(dirh->fh);
194 		free(dirh->files);
195 		free(dirh);
196 	}
197 }
198 
199 TEE_Result tee_fs_dirfile_commit_writes(struct tee_fs_dirfile_dirh *dirh)
200 {
201 	return dirh->fops->commit_writes(dirh->fh, NULL);
202 }
203 
204 TEE_Result tee_fs_dirfile_get_tmp(struct tee_fs_dirfile_dirh *dirh,
205 				  struct tee_fs_dirfile_fileh *dfh)
206 {
207 	TEE_Result res;
208 	int i = 0;
209 
210 	if (dirh->files) {
211 		bit_ffc(dirh->files, dirh->nbits, &i);
212 		if (i == -1)
213 			i = dirh->nbits;
214 	}
215 
216 	res = set_file(dirh, i);
217 	if (!res)
218 		dfh->file_number = i;
219 
220 	return res;
221 }
222 
223 TEE_Result tee_fs_dirfile_find(struct tee_fs_dirfile_dirh *dirh,
224 			       const void *oid, size_t oidlen,
225 			       struct tee_fs_dirfile_fileh *dfh)
226 {
227 	TEE_Result res;
228 	struct dirfile_entry dent;
229 	int n;
230 	int first_free = -1;
231 
232 	for (n = 0;; n++) {
233 		res = read_dent(dirh, n, &dent);
234 		if (res == TEE_ERROR_ITEM_NOT_FOUND && !oidlen) {
235 			memset(&dent, 0, sizeof(dent));
236 			if (first_free != -1)
237 				n = first_free;
238 			break;
239 		}
240 		if (res)
241 			return res;
242 
243 		if (!dent.oidlen && first_free == -1)
244 			first_free = n;
245 		if (dent.oidlen != oidlen)
246 			continue;
247 
248 		assert(!oidlen || !dent.oidlen ||
249 		       test_file(dirh, dent.file_number));
250 
251 		if (!memcmp(&dent.uuid, dirh->uuid, sizeof(dent.uuid)) &&
252 		    !memcmp(&dent.oid, oid, oidlen))
253 			break;
254 	}
255 
256 	if (dfh) {
257 		dfh->idx = n;
258 		dfh->file_number = dent.file_number;
259 		memcpy(dfh->hash, dent.hash, sizeof(dent.hash));
260 	}
261 
262 	return TEE_SUCCESS;
263 }
264 
265 TEE_Result tee_fs_dirfile_fileh_to_fname(const struct tee_fs_dirfile_fileh *dfh,
266 					 char *fname, size_t *fnlen)
267 {
268 	int r;
269 	size_t l = *fnlen;
270 
271 	if (dfh)
272 		r = snprintf(fname, l, "%" PRIx32, dfh->file_number);
273 	else
274 		r = snprintf(fname, l, "dirf.db");
275 
276 	if (r < 0)
277 		return TEE_ERROR_GENERIC;
278 
279 	*fnlen = r + 1;
280 	if ((size_t)r >= l)
281 		return TEE_ERROR_SHORT_BUFFER;
282 
283 	return TEE_SUCCESS;
284 }
285 
286 TEE_Result tee_fs_dirfile_rename(struct tee_fs_dirfile_dirh *dirh,
287 				 struct tee_fs_dirfile_fileh *dfh,
288 				 const void *oid, size_t oidlen)
289 {
290 	TEE_Result res;
291 	struct dirfile_entry dent;
292 
293 	if (!oidlen || oidlen > sizeof(dent.oid))
294 		return TEE_ERROR_BAD_PARAMETERS;
295 	memset(&dent, 0, sizeof(dent));
296 	dent.uuid = *dirh->uuid;
297 	memcpy(dent.oid, oid, oidlen);
298 	dent.oidlen = oidlen;
299 	memcpy(dent.hash, dfh->hash, sizeof(dent.hash));
300 	dent.file_number = dfh->file_number;
301 
302 	if (dfh->idx < 0) {
303 		struct tee_fs_dirfile_fileh dfh2;
304 
305 		res = tee_fs_dirfile_find(dirh, oid, oidlen, &dfh2);
306 		if (res) {
307 			if (res == TEE_ERROR_ITEM_NOT_FOUND)
308 				res = tee_fs_dirfile_find(dirh, NULL, 0, &dfh2);
309 			if (res)
310 				return res;
311 		}
312 		dfh->idx = dfh2.idx;
313 	}
314 
315 	return write_dent(dirh, dfh->idx, &dent);
316 }
317 
318 TEE_Result tee_fs_dirfile_remove(struct tee_fs_dirfile_dirh *dirh,
319 				 const struct tee_fs_dirfile_fileh *dfh)
320 {
321 	TEE_Result res;
322 	struct dirfile_entry dent;
323 	uint32_t file_number;
324 
325 	res = read_dent(dirh, dfh->idx, &dent);
326 	if (res)
327 		return res;
328 
329 	if (!dent.oidlen)
330 		return TEE_SUCCESS;
331 
332 	file_number = dent.file_number;
333 	assert(dfh->file_number == file_number);
334 	assert(test_file(dirh, file_number));
335 
336 	memset(&dent, 0, sizeof(dent));
337 	res = write_dent(dirh, dfh->idx, &dent);
338 	if (!res)
339 		clear_file(dirh, file_number);
340 
341 	return res;
342 }
343 
344 TEE_Result tee_fs_dirfile_update_hash(struct tee_fs_dirfile_dirh *dirh,
345 				      const struct tee_fs_dirfile_fileh *dfh)
346 {
347 	TEE_Result res;
348 	struct dirfile_entry dent;
349 
350 	res = read_dent(dirh, dfh->idx, &dent);
351 	if (res)
352 		return res;
353 	assert(dent.file_number == dfh->file_number);
354 	assert(test_file(dirh, dent.file_number));
355 
356 	memcpy(&dent.hash, dfh->hash, sizeof(dent.hash));
357 
358 	return write_dent(dirh, dfh->idx, &dent);
359 }
360 
361 TEE_Result tee_fs_dirfile_get_next(struct tee_fs_dirfile_dirh *dirh,
362 				   int *idx, void *oid, size_t *oidlen)
363 {
364 	TEE_Result res;
365 	int i = *idx + 1;
366 	struct dirfile_entry dent;
367 
368 	if (i < 0)
369 		i = 0;
370 
371 	for (;; i++) {
372 		res = read_dent(dirh, i, &dent);
373 		if (res)
374 			return res;
375 		if (!memcmp(&dent.uuid, dirh->uuid, sizeof(dent.uuid)) &&
376 		    dent.oidlen)
377 			break;
378 	}
379 
380 	if (*oidlen < dent.oidlen)
381 		return TEE_ERROR_SHORT_BUFFER;
382 
383 	memcpy(oid, dent.oid, dent.oidlen);
384 	*oidlen = dent.oidlen;
385 	*idx = i;
386 
387 	return TEE_SUCCESS;
388 }
389