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 struct tee_fs_dirfile_operations *fops; 38 struct tee_file_handle *fh; 39 int nbits; 40 bitstr_t *files; 41 size_t ndents; 42 }; 43 44 struct dirfile_entry { 45 TEE_UUID uuid; 46 uint8_t oid[TEE_OBJECT_ID_MAX_LEN]; 47 uint32_t oidlen; 48 uint8_t hash[TEE_FS_HTREE_HASH_SIZE]; 49 uint32_t file_number; 50 }; 51 52 /* 53 * File layout 54 * 55 * dirfile_entry.0 56 * ... 57 * dirfile_entry.n 58 * 59 * where n the index is disconnected from file_number in struct dirfile_entry 60 */ 61 62 static TEE_Result maybe_grow_files(struct tee_fs_dirfile_dirh *dirh, int idx) 63 { 64 void *p; 65 66 if (idx < dirh->nbits) 67 return TEE_SUCCESS; 68 69 p = realloc(dirh->files, bitstr_size(idx + 1)); 70 if (!p) 71 return TEE_ERROR_OUT_OF_MEMORY; 72 dirh->files = p; 73 74 bit_nclear(dirh->files, dirh->nbits, idx); 75 dirh->nbits = idx + 1; 76 77 return TEE_SUCCESS; 78 } 79 80 static TEE_Result set_file(struct tee_fs_dirfile_dirh *dirh, int idx) 81 { 82 TEE_Result res = maybe_grow_files(dirh, idx); 83 84 if (!res) 85 bit_set(dirh->files, idx); 86 87 return res; 88 } 89 90 static void clear_file(struct tee_fs_dirfile_dirh *dirh, int idx) 91 { 92 if (idx < dirh->nbits) 93 bit_clear(dirh->files, idx); 94 } 95 96 static bool test_file(struct tee_fs_dirfile_dirh *dirh, int idx) 97 { 98 if (idx < dirh->nbits) 99 return bit_test(dirh->files, idx); 100 101 return false; 102 } 103 104 static TEE_Result read_dent(struct tee_fs_dirfile_dirh *dirh, int idx, 105 struct dirfile_entry *dent) 106 { 107 TEE_Result res; 108 size_t l; 109 110 l = sizeof(*dent); 111 res = dirh->fops->read(dirh->fh, sizeof(struct dirfile_entry) * idx, 112 dent, &l); 113 if (!res && l != sizeof(*dent)) 114 res = TEE_ERROR_ITEM_NOT_FOUND; 115 116 return res; 117 } 118 119 static TEE_Result write_dent(struct tee_fs_dirfile_dirh *dirh, size_t n, 120 struct dirfile_entry *dent) 121 { 122 TEE_Result res; 123 124 res = dirh->fops->write(dirh->fh, sizeof(*dent) * n, 125 dent, sizeof(*dent)); 126 if (!res && n >= dirh->ndents) 127 dirh->ndents = n + 1; 128 129 return res; 130 } 131 132 TEE_Result tee_fs_dirfile_open(bool create, uint8_t *hash, 133 const struct tee_fs_dirfile_operations *fops, 134 struct tee_fs_dirfile_dirh **dirh_ret) 135 { 136 TEE_Result res; 137 struct tee_fs_dirfile_dirh *dirh = calloc(1, sizeof(*dirh)); 138 size_t n; 139 140 if (!dirh) 141 return TEE_ERROR_OUT_OF_MEMORY; 142 143 dirh->fops = fops; 144 res = fops->open(create, hash, NULL, NULL, &dirh->fh); 145 if (res) 146 goto out; 147 148 for (n = 0;; n++) { 149 struct dirfile_entry dent; 150 151 res = read_dent(dirh, n, &dent); 152 if (res) { 153 if (res == TEE_ERROR_ITEM_NOT_FOUND) 154 res = TEE_SUCCESS; 155 goto out; 156 } 157 158 if (!dent.oidlen) 159 continue; 160 161 if (test_file(dirh, dent.file_number)) { 162 DMSG("clearing duplicate file number %" PRIu32, 163 dent.file_number); 164 memset(&dent, 0, sizeof(dent)); 165 res = write_dent(dirh, n, &dent); 166 if (res) 167 goto out; 168 continue; 169 } 170 171 res = set_file(dirh, dent.file_number); 172 if (res != TEE_SUCCESS) 173 goto out; 174 } 175 out: 176 if (!res) { 177 dirh->ndents = n; 178 *dirh_ret = dirh; 179 } else { 180 tee_fs_dirfile_close(dirh); 181 } 182 return res; 183 } 184 185 void tee_fs_dirfile_close(struct tee_fs_dirfile_dirh *dirh) 186 { 187 if (dirh) { 188 dirh->fops->close(dirh->fh); 189 free(dirh->files); 190 free(dirh); 191 } 192 } 193 194 TEE_Result tee_fs_dirfile_commit_writes(struct tee_fs_dirfile_dirh *dirh, 195 uint8_t *hash) 196 { 197 return dirh->fops->commit_writes(dirh->fh, hash); 198 } 199 200 TEE_Result tee_fs_dirfile_get_tmp(struct tee_fs_dirfile_dirh *dirh, 201 struct tee_fs_dirfile_fileh *dfh) 202 { 203 TEE_Result res; 204 int i = 0; 205 206 if (dirh->files) { 207 bit_ffc(dirh->files, dirh->nbits, &i); 208 if (i == -1) 209 i = dirh->nbits; 210 } 211 212 res = set_file(dirh, i); 213 if (!res) 214 dfh->file_number = i; 215 216 return res; 217 } 218 219 TEE_Result tee_fs_dirfile_find(struct tee_fs_dirfile_dirh *dirh, 220 const TEE_UUID *uuid, const void *oid, 221 size_t oidlen, struct tee_fs_dirfile_fileh *dfh) 222 { 223 TEE_Result res; 224 struct dirfile_entry dent; 225 int n; 226 int first_free = -1; 227 228 for (n = 0;; n++) { 229 res = read_dent(dirh, n, &dent); 230 if (res == TEE_ERROR_ITEM_NOT_FOUND && !oidlen) { 231 memset(&dent, 0, sizeof(dent)); 232 if (first_free != -1) 233 n = first_free; 234 break; 235 } 236 if (res) 237 return res; 238 239 /* TODO check this loop when oidlen == 0 */ 240 241 if (!dent.oidlen && first_free == -1) 242 first_free = n; 243 if (dent.oidlen != oidlen) 244 continue; 245 246 assert(!oidlen || !dent.oidlen || 247 test_file(dirh, dent.file_number)); 248 249 if (!memcmp(&dent.uuid, uuid, sizeof(dent.uuid)) && 250 !memcmp(&dent.oid, oid, oidlen)) 251 break; 252 } 253 254 if (dfh) { 255 dfh->idx = n; 256 dfh->file_number = dent.file_number; 257 memcpy(dfh->hash, dent.hash, sizeof(dent.hash)); 258 } 259 260 return TEE_SUCCESS; 261 } 262 263 TEE_Result tee_fs_dirfile_fileh_to_fname(const struct tee_fs_dirfile_fileh *dfh, 264 char *fname, size_t *fnlen) 265 { 266 int r; 267 size_t l = *fnlen; 268 269 if (dfh) 270 r = snprintf(fname, l, "%" PRIx32, dfh->file_number); 271 else 272 r = snprintf(fname, l, "dirf.db"); 273 274 if (r < 0) 275 return TEE_ERROR_GENERIC; 276 277 *fnlen = r + 1; 278 if ((size_t)r >= l) 279 return TEE_ERROR_SHORT_BUFFER; 280 281 return TEE_SUCCESS; 282 } 283 284 TEE_Result tee_fs_dirfile_rename(struct tee_fs_dirfile_dirh *dirh, 285 const TEE_UUID *uuid, 286 struct tee_fs_dirfile_fileh *dfh, 287 const void *oid, size_t oidlen) 288 { 289 TEE_Result res; 290 struct dirfile_entry dent; 291 292 if (!oidlen || oidlen > sizeof(dent.oid)) 293 return TEE_ERROR_BAD_PARAMETERS; 294 memset(&dent, 0, sizeof(dent)); 295 dent.uuid = *uuid; 296 memcpy(dent.oid, oid, oidlen); 297 dent.oidlen = oidlen; 298 memcpy(dent.hash, dfh->hash, sizeof(dent.hash)); 299 dent.file_number = dfh->file_number; 300 301 if (dfh->idx < 0) { 302 struct tee_fs_dirfile_fileh dfh2; 303 304 res = tee_fs_dirfile_find(dirh, uuid, oid, oidlen, &dfh2); 305 if (res) { 306 if (res == TEE_ERROR_ITEM_NOT_FOUND) 307 res = tee_fs_dirfile_find(dirh, uuid, NULL, 0, 308 &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 const TEE_UUID *uuid, int *idx, void *oid, 363 size_t *oidlen) 364 { 365 TEE_Result res; 366 int i = *idx + 1; 367 struct dirfile_entry dent; 368 369 if (i < 0) 370 i = 0; 371 372 for (;; i++) { 373 res = read_dent(dirh, i, &dent); 374 if (res) 375 return res; 376 if (!memcmp(&dent.uuid, uuid, sizeof(dent.uuid)) && 377 dent.oidlen) 378 break; 379 } 380 381 if (*oidlen < dent.oidlen) 382 return TEE_ERROR_SHORT_BUFFER; 383 384 memcpy(oid, dent.oid, dent.oidlen); 385 *oidlen = dent.oidlen; 386 *idx = i; 387 388 return TEE_SUCCESS; 389 } 390