1 /*
2 * Copyright (c) 2017-2021, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include "ps_object_system.h"
9
10 #include <stddef.h>
11 #include <string.h>
12
13 #include "cmsis_compiler.h"
14 #include "psa/internal_trusted_storage.h"
15 #ifdef PS_ENCRYPTION
16 #include "ps_encrypted_object.h"
17 #endif
18 #include "ps_object_defs.h"
19 #include "ps_object_table.h"
20 #include "ps_utils.h"
21 #include "tfm_ps_req_mngr.h"
22
23 #ifndef PS_ENCRYPTION
24 /* Gets the size of object written to the object system below */
25 #define PS_OBJECT_SIZE(max_size) (PS_OBJECT_HEADER_SIZE + (max_size))
26 #define PS_OBJECT_START_POSITION 0
27 #endif /* PS_ENCRYPTION */
28
29 /* Allocate static variables to process objects */
30 static struct ps_object_t g_ps_object;
31 static struct ps_obj_table_info_t g_obj_tbl_info;
32
33 /**
34 * \brief Initialize g_ps_object based on the input parameters and empty data.
35 *
36 * \param[in] create_flags Object create flags
37 * \param[in] size Object size
38 * \param[out] obj Object to initialize
39 *
40 */
41 __attribute__ ((always_inline))
ps_init_empty_object(psa_storage_create_flags_t create_flags,uint32_t size,struct ps_object_t * obj)42 __STATIC_INLINE void ps_init_empty_object(
43 psa_storage_create_flags_t create_flags,
44 uint32_t size,
45 struct ps_object_t *obj)
46 {
47 /* Set all object data to 0 */
48 (void)memset(obj, PS_DEFAULT_EMPTY_BUFF_VAL, PS_MAX_OBJECT_SIZE);
49
50 #ifndef PS_ENCRYPTION
51 /* Initialize object version */
52 obj->header.version = 0;
53 #endif
54
55 /* Set object header based on input parameters */
56 obj->header.info.max_size = size;
57 obj->header.info.create_flags = create_flags;
58 }
59
60 /**
61 * \brief Removes the old object table and object from the file system.
62 *
63 * \param[in] old_fid Old file ID to remove.
64 *
65 * \return Returns error code as specified in \ref psa_status_t
66 */
ps_remove_old_data(uint32_t old_fid)67 static psa_status_t ps_remove_old_data(uint32_t old_fid)
68 {
69 psa_status_t err;
70
71 /* Delete old object table from the persistent area */
72 err = ps_object_table_delete_old_table();
73 if (err != PSA_SUCCESS) {
74 return err;
75 }
76
77 /* Delete old file from the persistent area */
78 return psa_its_remove(old_fid);
79 }
80
81 #ifndef PS_ENCRYPTION
82 enum read_type_t {
83 READ_HEADER_ONLY = 0,
84 READ_ALL_OBJECT,
85 };
86
87 /**
88 * \brief Reads and validates an object header based on its object table info
89 * stored in g_obj_tbl_info.
90 *
91 * \param[in] type Read type as specified in \ref read_type_t
92 *
93 * \return Returns error code as specified in \ref psa_status_t
94 */
ps_read_object(enum read_type_t type)95 static psa_status_t ps_read_object(enum read_type_t type)
96 {
97 psa_status_t err;
98 size_t data_length;
99
100 /* Read object header */
101 err = psa_its_get(g_obj_tbl_info.fid,
102 PS_OBJECT_START_POSITION,
103 PS_OBJECT_HEADER_SIZE,
104 (void *)&g_ps_object.header,
105 &data_length);
106 if (err != PSA_SUCCESS) {
107 return err;
108 }
109
110 /* As PS encryption support is not enabled, check file ID and version to
111 * detect inconsistency after read the object header from flash.
112 */
113 if (g_ps_object.header.fid != g_obj_tbl_info.fid ||
114 g_ps_object.header.version != g_obj_tbl_info.version) {
115 return PSA_ERROR_DATA_CORRUPT;
116 }
117
118 /* Read object data if any */
119 if (type == READ_ALL_OBJECT && g_ps_object.header.info.current_size > 0) {
120 err = psa_its_get(g_obj_tbl_info.fid,
121 PS_OBJECT_HEADER_SIZE,
122 g_ps_object.header.info.current_size,
123 (void *)g_ps_object.data,
124 &data_length);
125 if (err != PSA_SUCCESS) {
126 return err;
127 }
128 }
129
130 return PSA_SUCCESS;
131 }
132
133 /**
134 * \brief Writes an object based on its object table info stored in
135 * g_obj_tbl_info and the input parameter.
136 *
137 * \param[in] wrt_size Number of bytes to write
138 *
139 * \return Returns error code as specified in \ref psa_status_t
140 */
ps_write_object(uint32_t wrt_size)141 static psa_status_t ps_write_object(uint32_t wrt_size)
142 {
143 /* Add object identification and increase object version */
144 g_ps_object.header.fid = g_obj_tbl_info.fid;
145 g_ps_object.header.version++;
146
147 /* Save object version to be stored in the object table */
148 g_obj_tbl_info.version = g_ps_object.header.version;
149
150 return psa_its_set(g_obj_tbl_info.fid, wrt_size,
151 (const void *)&g_ps_object,
152 PSA_STORAGE_FLAG_NONE);
153 }
154
155 #endif /* !PS_ENCRYPTION */
156
ps_system_prepare(void)157 psa_status_t ps_system_prepare(void)
158 {
159 psa_status_t err;
160
161 /* Reuse the allocated g_ps_object.data to store a temporary object table
162 * data to be validate inside the function.
163 * The stored date will be cleaned up when the g_ps_object.data will
164 * be used for the first time in the object system.
165 */
166 err = ps_object_table_init(g_ps_object.data);
167
168 #ifdef PS_ENCRYPTION
169 g_obj_tbl_info.tag = g_ps_object.header.crypto.ref.tag;
170 #endif
171
172 return err;
173 }
174
ps_object_read(psa_storage_uid_t uid,int32_t client_id,uint32_t offset,uint32_t size,size_t * p_data_length)175 psa_status_t ps_object_read(psa_storage_uid_t uid, int32_t client_id,
176 uint32_t offset, uint32_t size,
177 size_t *p_data_length)
178 {
179 psa_status_t err;
180
181 /* Retrieve the object information from the object table if the object
182 * exists.
183 */
184 err = ps_object_table_get_obj_tbl_info(uid, client_id, &g_obj_tbl_info);
185 if (err != PSA_SUCCESS) {
186 return err;
187 }
188
189 /* Read object */
190 #ifdef PS_ENCRYPTION
191 g_ps_object.header.crypto.ref.uid = uid;
192 g_ps_object.header.crypto.ref.client_id = client_id;
193
194 err = ps_encrypted_object_read(g_obj_tbl_info.fid, &g_ps_object);
195 #else
196 /* Read object header */
197 err = ps_read_object(READ_ALL_OBJECT);
198 #endif
199 if (err != PSA_SUCCESS) {
200 goto clear_data_and_return;
201 }
202
203 /* Boundary check the incoming request */
204 if (offset > g_ps_object.header.info.current_size) {
205 err = PSA_ERROR_INVALID_ARGUMENT;
206 goto clear_data_and_return;
207 }
208
209 size = PS_UTILS_MIN(size,
210 g_ps_object.header.info.current_size - offset);
211
212 /* Copy the decrypted object data to the output buffer */
213 ps_req_mngr_write_asset_data(g_ps_object.data + offset, size);
214
215 *p_data_length = size;
216
217 clear_data_and_return:
218 /* Remove data stored in the object before leaving the function */
219 (void)memset(&g_ps_object, PS_DEFAULT_EMPTY_BUFF_VAL,
220 PS_MAX_OBJECT_SIZE);
221
222 return err;
223 }
224
ps_object_create(psa_storage_uid_t uid,int32_t client_id,psa_storage_create_flags_t create_flags,uint32_t size)225 psa_status_t ps_object_create(psa_storage_uid_t uid, int32_t client_id,
226 psa_storage_create_flags_t create_flags,
227 uint32_t size)
228 {
229 psa_status_t err;
230 uint32_t old_fid = PS_INVALID_FID;
231 uint32_t fid_am_reserved = 1;
232
233 #ifndef PS_ENCRYPTION
234 uint32_t wrt_size;
235 #endif
236
237 /* Boundary check the incoming request */
238 if (size > PS_MAX_ASSET_SIZE) {
239 return PSA_ERROR_INVALID_ARGUMENT;
240 }
241
242 /* Retrieve the object information from the object table if the object
243 * exists.
244 */
245 err = ps_object_table_get_obj_tbl_info(uid, client_id, &g_obj_tbl_info);
246 if (err == PSA_SUCCESS) {
247 #ifdef PS_ENCRYPTION
248 /* Read the object */
249 g_ps_object.header.crypto.ref.uid = uid;
250 g_ps_object.header.crypto.ref.client_id = client_id;
251
252 err = ps_encrypted_object_read(g_obj_tbl_info.fid, &g_ps_object);
253 #else
254 /* Read the object header */
255 err = ps_read_object(READ_HEADER_ONLY);
256 #endif
257 if (err != PSA_SUCCESS) {
258 goto clear_data_and_return;
259 }
260
261 /* If the object exists and has the write once flag set, then it cannot
262 * be modified.
263 */
264 if (g_ps_object.header.info.create_flags
265 & PSA_STORAGE_FLAG_WRITE_ONCE) {
266 err = PSA_ERROR_NOT_PERMITTED;
267 goto clear_data_and_return;
268 }
269
270 /* Update the create flags and max object size */
271 g_ps_object.header.info.create_flags = create_flags;
272 g_ps_object.header.info.max_size = size;
273
274 /* Save old file ID */
275 old_fid = g_obj_tbl_info.fid;
276 } else if (err == PSA_ERROR_DOES_NOT_EXIST) {
277 /* If the object does not exist, then initialize it based on the input
278 * arguments and empty content. Requests 2 FIDs to prevent exhaustion.
279 */
280 fid_am_reserved = 2;
281 ps_init_empty_object(create_flags, size, &g_ps_object);
282 } else {
283 goto clear_data_and_return;
284 }
285
286 /* Update the object data */
287 err = ps_req_mngr_read_asset_data(g_ps_object.data, size);
288 if (err != PSA_SUCCESS) {
289 goto clear_data_and_return;
290 }
291
292 /* Update the current object size */
293 g_ps_object.header.info.current_size = size;
294
295 /* Get new file ID */
296 err = ps_object_table_get_free_fid(fid_am_reserved,
297 &g_obj_tbl_info.fid);
298 if (err != PSA_SUCCESS) {
299 goto clear_data_and_return;
300 }
301
302 #ifdef PS_ENCRYPTION
303 g_ps_object.header.crypto.ref.uid = uid;
304 g_ps_object.header.crypto.ref.client_id = client_id;
305
306 err = ps_encrypted_object_write(g_obj_tbl_info.fid, &g_ps_object);
307 #else
308 wrt_size = PS_OBJECT_SIZE(g_ps_object.header.info.current_size);
309
310 /* Write g_ps_object */
311 err = ps_write_object(wrt_size);
312 #endif
313 if (err != PSA_SUCCESS) {
314 goto clear_data_and_return;
315 }
316
317 /* Update the table with the new internal ID and version for the object, and
318 * store it in the persistent area.
319 */
320 err = ps_object_table_set_obj_tbl_info(uid, client_id, &g_obj_tbl_info);
321 if (err != PSA_SUCCESS) {
322 /* Remove new object as object table is not persistent and propagate
323 * object table manipulation error.
324 */
325 (void)psa_its_remove(g_obj_tbl_info.fid);
326
327 goto clear_data_and_return;
328 }
329
330 if (old_fid == PS_INVALID_FID) {
331 /* Delete old object table from the persistent area */
332 err = ps_object_table_delete_old_table();
333 } else {
334 /* Remove old object and delete old object table */
335 err = ps_remove_old_data(old_fid);
336 }
337
338 clear_data_and_return:
339 /* Remove data stored in the object before leaving the function */
340 (void)memset(&g_ps_object, PS_DEFAULT_EMPTY_BUFF_VAL, PS_MAX_OBJECT_SIZE);
341
342 return err;
343 }
344
ps_object_write(psa_storage_uid_t uid,int32_t client_id,uint32_t offset,uint32_t size)345 psa_status_t ps_object_write(psa_storage_uid_t uid, int32_t client_id,
346 uint32_t offset, uint32_t size)
347 {
348 psa_status_t err;
349 uint32_t old_fid;
350
351 #ifndef PS_ENCRYPTION
352 uint32_t wrt_size;
353 #endif
354
355 /* Retrieve the object information from the object table if the object
356 * exists.
357 */
358 err = ps_object_table_get_obj_tbl_info(uid, client_id, &g_obj_tbl_info);
359 if (err != PSA_SUCCESS) {
360 return err;
361 }
362
363 /* Read the object */
364 #ifdef PS_ENCRYPTION
365 g_ps_object.header.crypto.ref.uid = uid;
366 g_ps_object.header.crypto.ref.client_id = client_id;
367
368 err = ps_encrypted_object_read(g_obj_tbl_info.fid, &g_ps_object);
369 #else
370 err = ps_read_object(READ_ALL_OBJECT);
371 #endif
372 if (err != PSA_SUCCESS) {
373 goto clear_data_and_return;
374 }
375
376 /* If the object has the write once flag set, then it cannot be modified. */
377 if (g_ps_object.header.info.create_flags & PSA_STORAGE_FLAG_WRITE_ONCE) {
378 err = PSA_ERROR_NOT_PERMITTED;
379 goto clear_data_and_return;
380 }
381
382 /* Offset must not be larger than the object's current size to prevent gaps
383 * being created in the object data.
384 */
385 if (offset > g_ps_object.header.info.current_size) {
386 err = PSA_ERROR_INVALID_ARGUMENT;
387 goto clear_data_and_return;
388 }
389
390 /* Boundary check the incoming request */
391 err = ps_utils_check_contained_in(g_ps_object.header.info.max_size,
392 offset, size);
393 if (err != PSA_SUCCESS) {
394 goto clear_data_and_return;
395 }
396
397 /* Update the object data */
398 err = ps_req_mngr_read_asset_data(g_ps_object.data + offset, size);
399 if (err != PSA_SUCCESS) {
400 goto clear_data_and_return;
401 }
402
403 /* Update the current object size if necessary */
404 if ((offset + size) > g_ps_object.header.info.current_size) {
405 g_ps_object.header.info.current_size = offset + size;
406 }
407
408 /* Save old file ID */
409 old_fid = g_obj_tbl_info.fid;
410
411 /* Get new file ID */
412 err = ps_object_table_get_free_fid(1, &g_obj_tbl_info.fid);
413 if (err != PSA_SUCCESS) {
414 goto clear_data_and_return;
415 }
416
417 #ifdef PS_ENCRYPTION
418 g_ps_object.header.crypto.ref.uid = uid;
419 g_ps_object.header.crypto.ref.client_id = client_id;
420
421 err = ps_encrypted_object_write(g_obj_tbl_info.fid, &g_ps_object);
422 #else
423 wrt_size = PS_OBJECT_SIZE(g_ps_object.header.info.current_size);
424
425 /* Write g_ps_object */
426 err = ps_write_object(wrt_size);
427 #endif
428 if (err != PSA_SUCCESS) {
429 goto clear_data_and_return;
430 }
431
432 /* Update the table with the new internal ID and version for the object, and
433 * store it in the persistent area.
434 */
435 err = ps_object_table_set_obj_tbl_info(uid, client_id, &g_obj_tbl_info);
436 if (err != PSA_SUCCESS) {
437 /* Remove new object as object table is not persistent and propagate
438 * object table manipulation error.
439 */
440 (void)psa_its_remove(g_obj_tbl_info.fid);
441
442 goto clear_data_and_return;
443 }
444
445 /* Remove old object table and object */
446 err = ps_remove_old_data(old_fid);
447
448 clear_data_and_return:
449 /* Remove data stored in the object before leaving the function */
450 (void)memset(&g_ps_object, PS_DEFAULT_EMPTY_BUFF_VAL,
451 PS_MAX_OBJECT_SIZE);
452
453 return err;
454 }
455
ps_object_get_info(psa_storage_uid_t uid,int32_t client_id,struct psa_storage_info_t * info)456 psa_status_t ps_object_get_info(psa_storage_uid_t uid, int32_t client_id,
457 struct psa_storage_info_t *info)
458 {
459 psa_status_t err;
460
461 /* Retrieve the object information from the object table if the object
462 * exists.
463 */
464 err = ps_object_table_get_obj_tbl_info(uid, client_id, &g_obj_tbl_info);
465 if (err != PSA_SUCCESS) {
466 return err;
467 }
468
469 #ifdef PS_ENCRYPTION
470 g_ps_object.header.crypto.ref.uid = uid;
471 g_ps_object.header.crypto.ref.client_id = client_id;
472
473 err = ps_encrypted_object_read(g_obj_tbl_info.fid, &g_ps_object);
474 #else
475 err = ps_read_object(READ_HEADER_ONLY);
476 #endif
477 if (err != PSA_SUCCESS) {
478 goto clear_data_and_return;
479 }
480
481 /* Copy PS object info to the PSA PS info struct */
482 info->size = g_ps_object.header.info.current_size;
483 info->flags = g_ps_object.header.info.create_flags;
484
485 clear_data_and_return:
486 /* Remove data stored in the object before leaving the function */
487 (void)memset(&g_ps_object, PS_DEFAULT_EMPTY_BUFF_VAL,
488 PS_MAX_OBJECT_SIZE);
489
490 return err;
491 }
492
ps_object_delete(psa_storage_uid_t uid,int32_t client_id)493 psa_status_t ps_object_delete(psa_storage_uid_t uid, int32_t client_id)
494 {
495 psa_status_t err;
496
497 /* Retrieve the object information from the object table if the object
498 * exists.
499 */
500 err = ps_object_table_get_obj_tbl_info(uid, client_id, &g_obj_tbl_info);
501 if (err != PSA_SUCCESS) {
502 return err;
503 }
504
505 #ifdef PS_ENCRYPTION
506 g_ps_object.header.crypto.ref.uid = uid;
507 g_ps_object.header.crypto.ref.client_id = client_id;
508
509 err = ps_encrypted_object_read(g_obj_tbl_info.fid, &g_ps_object);
510 #else
511 err = ps_read_object(READ_HEADER_ONLY);
512 #endif
513 if (err != PSA_SUCCESS) {
514 goto clear_data_and_return;
515 }
516
517 /* Check that the write once flag is not set */
518 if (g_ps_object.header.info.create_flags & PSA_STORAGE_FLAG_WRITE_ONCE) {
519 err = PSA_ERROR_NOT_PERMITTED;
520 goto clear_data_and_return;
521 }
522
523 /* Delete object from the table and stores the table in the persistent
524 * area.
525 */
526 err = ps_object_table_delete_object(uid, client_id);
527 if (err != PSA_SUCCESS) {
528 goto clear_data_and_return;
529 }
530
531 /* Remove old object table and file */
532 err = ps_remove_old_data(g_obj_tbl_info.fid);
533
534 clear_data_and_return:
535 /* Remove data stored in the object before leaving the function */
536 (void)memset(&g_ps_object, PS_DEFAULT_EMPTY_BUFF_VAL,
537 PS_MAX_OBJECT_SIZE);
538
539 return err;
540 }
541
ps_system_wipe_all(void)542 psa_status_t ps_system_wipe_all(void)
543 {
544 /* This function may get called as a corrective action
545 * if a system level security violation is detected.
546 * This could be asynchronous to normal system operation
547 * and state of the ps system lock is unknown. Hence
548 * this function doesn't block on the lock and directly
549 * moves to erasing the flash instead.
550 */
551 return ps_object_table_create();
552 }
553