TF-M Reference Manual  1.2.0
TrustedFirmware-M
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ps_object_system.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017-2020, 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 
12 #include "cmsis_compiler.h"
14 #include "tfm_memory_utils.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 
41 __attribute__ ((always_inline))
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 */
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 
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 */
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
85 };
86 
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,
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,
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 
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,
153 }
154 
155 #endif /* !PS_ENCRYPTION */
156 
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 
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  err = ps_encrypted_object_read(g_obj_tbl_info.fid, &g_ps_object);
192 #else
193  /* Read object header */
194  err = ps_read_object(READ_ALL_OBJECT);
195 #endif
196  if (err != PSA_SUCCESS) {
197  goto clear_data_and_return;
198  }
199 
200  /* Boundary check the incoming request */
201  if (offset > g_ps_object.header.info.current_size) {
203  goto clear_data_and_return;
204  }
205 
206  size = PS_UTILS_MIN(size,
207  g_ps_object.header.info.current_size - offset);
208 
209  /* Copy the decrypted object data to the output buffer */
210  ps_req_mngr_write_asset_data(g_ps_object.data + offset, size);
211 
212  *p_data_length = size;
213 
214 clear_data_and_return:
215  /* Remove data stored in the object before leaving the function */
216  (void)tfm_memset(&g_ps_object, PS_DEFAULT_EMPTY_BUFF_VAL,
218 
219  return err;
220 }
221 
223  psa_storage_create_flags_t create_flags,
224  uint32_t size)
225 {
226  psa_status_t err;
227  uint32_t old_fid = PS_INVALID_FID;
228  uint32_t fid_am_reserved = 1;
229 
230 #ifndef PS_ENCRYPTION
231  uint32_t wrt_size;
232 #endif
233 
234  /* Boundary check the incoming request */
235  if (size > PS_MAX_ASSET_SIZE) {
237  }
238 
239  /* Retrieve the object information from the object table if the object
240  * exists.
241  */
242  err = ps_object_table_get_obj_tbl_info(uid, client_id, &g_obj_tbl_info);
243  if (err == PSA_SUCCESS) {
244 #ifdef PS_ENCRYPTION
245  /* Read the object */
246  err = ps_encrypted_object_read(g_obj_tbl_info.fid, &g_ps_object);
247 #else
248  /* Read the object header */
249  err = ps_read_object(READ_HEADER_ONLY);
250 #endif
251  if (err != PSA_SUCCESS) {
252  goto clear_data_and_return;
253  }
254 
255  /* If the object exists and has the write once flag set, then it cannot
256  * be modified.
257  */
258  if (g_ps_object.header.info.create_flags
261  goto clear_data_and_return;
262  }
263 
264  /* Update the create flags and max object size */
265  g_ps_object.header.info.create_flags = create_flags;
266  g_ps_object.header.info.max_size = size;
267 
268  /* Save old file ID */
269  old_fid = g_obj_tbl_info.fid;
270  } else if (err == PSA_ERROR_DOES_NOT_EXIST) {
271  /* If the object does not exist, then initialize it based on the input
272  * arguments and empty content. Requests 2 FIDs to prevent exhaustion.
273  */
274  fid_am_reserved = 2;
275  ps_init_empty_object(create_flags, size, &g_ps_object);
276  } else {
277  goto clear_data_and_return;
278  }
279 
280  /* Update the object data */
281  err = ps_req_mngr_read_asset_data(g_ps_object.data, size);
282  if (err != PSA_SUCCESS) {
283  goto clear_data_and_return;
284  }
285 
286  /* Update the current object size */
287  g_ps_object.header.info.current_size = size;
288 
289  /* Get new file ID */
290  err = ps_object_table_get_free_fid(fid_am_reserved,
291  &g_obj_tbl_info.fid);
292  if (err != PSA_SUCCESS) {
293  goto clear_data_and_return;
294  }
295 
296 #ifdef PS_ENCRYPTION
297  err = ps_encrypted_object_write(g_obj_tbl_info.fid, &g_ps_object);
298 #else
299  wrt_size = PS_OBJECT_SIZE(g_ps_object.header.info.current_size);
300 
301  /* Write g_ps_object */
302  err = ps_write_object(wrt_size);
303 #endif
304  if (err != PSA_SUCCESS) {
305  goto clear_data_and_return;
306  }
307 
308  /* Update the table with the new internal ID and version for the object, and
309  * store it in the persistent area.
310  */
311  err = ps_object_table_set_obj_tbl_info(uid, client_id, &g_obj_tbl_info);
312  if (err != PSA_SUCCESS) {
313  /* Remove new object as object table is not persistent and propagate
314  * object table manipulation error.
315  */
316  (void)psa_its_remove(g_obj_tbl_info.fid);
317 
318  goto clear_data_and_return;
319  }
320 
321  if (old_fid == PS_INVALID_FID) {
322  /* Delete old object table from the persistent area */
324  } else {
325  /* Remove old object and delete old object table */
326  err = ps_remove_old_data(old_fid);
327  }
328 
329 clear_data_and_return:
330  /* Remove data stored in the object before leaving the function */
331  (void)tfm_memset(&g_ps_object, PS_DEFAULT_EMPTY_BUFF_VAL,
333 
334  return err;
335 }
336 
338  uint32_t offset, uint32_t size)
339 {
340  psa_status_t err;
341  uint32_t old_fid;
342 
343 #ifndef PS_ENCRYPTION
344  uint32_t wrt_size;
345 #endif
346 
347  /* Retrieve the object information from the object table if the object
348  * exists.
349  */
350  err = ps_object_table_get_obj_tbl_info(uid, client_id, &g_obj_tbl_info);
351  if (err != PSA_SUCCESS) {
352  return err;
353  }
354 
355  /* Read the object */
356 #ifdef PS_ENCRYPTION
357  err = ps_encrypted_object_read(g_obj_tbl_info.fid, &g_ps_object);
358 #else
359  err = ps_read_object(READ_ALL_OBJECT);
360 #endif
361  if (err != PSA_SUCCESS) {
362  goto clear_data_and_return;
363  }
364 
365  /* If the object has the write once flag set, then it cannot be modified. */
368  goto clear_data_and_return;
369  }
370 
371  /* Offset must not be larger than the object's current size to prevent gaps
372  * being created in the object data.
373  */
374  if (offset > g_ps_object.header.info.current_size) {
376  goto clear_data_and_return;
377  }
378 
379  /* Boundary check the incoming request */
381  offset, size);
382  if (err != PSA_SUCCESS) {
383  goto clear_data_and_return;
384  }
385 
386  /* Update the object data */
387  err = ps_req_mngr_read_asset_data(g_ps_object.data + offset, size);
388  if (err != PSA_SUCCESS) {
389  goto clear_data_and_return;
390  }
391 
392  /* Update the current object size if necessary */
393  if ((offset + size) > g_ps_object.header.info.current_size) {
394  g_ps_object.header.info.current_size = offset + size;
395  }
396 
397  /* Save old file ID */
398  old_fid = g_obj_tbl_info.fid;
399 
400  /* Get new file ID */
401  err = ps_object_table_get_free_fid(1, &g_obj_tbl_info.fid);
402  if (err != PSA_SUCCESS) {
403  goto clear_data_and_return;
404  }
405 
406 #ifdef PS_ENCRYPTION
407  err = ps_encrypted_object_write(g_obj_tbl_info.fid, &g_ps_object);
408 #else
409  wrt_size = PS_OBJECT_SIZE(g_ps_object.header.info.current_size);
410 
411  /* Write g_ps_object */
412  err = ps_write_object(wrt_size);
413 #endif
414  if (err != PSA_SUCCESS) {
415  goto clear_data_and_return;
416  }
417 
418  /* Update the table with the new internal ID and version for the object, and
419  * store it in the persistent area.
420  */
421  err = ps_object_table_set_obj_tbl_info(uid, client_id, &g_obj_tbl_info);
422  if (err != PSA_SUCCESS) {
423  /* Remove new object as object table is not persistent and propagate
424  * object table manipulation error.
425  */
426  (void)psa_its_remove(g_obj_tbl_info.fid);
427 
428  goto clear_data_and_return;
429  }
430 
431  /* Remove old object table and object */
432  err = ps_remove_old_data(old_fid);
433 
434 clear_data_and_return:
435  /* Remove data stored in the object before leaving the function */
436  (void)tfm_memset(&g_ps_object, PS_DEFAULT_EMPTY_BUFF_VAL,
438 
439  return err;
440 }
441 
443  struct psa_storage_info_t *info)
444 {
445  psa_status_t err;
446 
447  /* Retrieve the object information from the object table if the object
448  * exists.
449  */
450  err = ps_object_table_get_obj_tbl_info(uid, client_id, &g_obj_tbl_info);
451  if (err != PSA_SUCCESS) {
452  return err;
453  }
454 
455 #ifdef PS_ENCRYPTION
456  err = ps_encrypted_object_read(g_obj_tbl_info.fid, &g_ps_object);
457 #else
458  err = ps_read_object(READ_HEADER_ONLY);
459 #endif
460  if (err != PSA_SUCCESS) {
461  goto clear_data_and_return;
462  }
463 
464  /* Copy PS object info to the PSA PS info struct */
465  info->size = g_ps_object.header.info.current_size;
466  info->flags = g_ps_object.header.info.create_flags;
467 
468 clear_data_and_return:
469  /* Remove data stored in the object before leaving the function */
470  (void)tfm_memset(&g_ps_object, PS_DEFAULT_EMPTY_BUFF_VAL,
472 
473  return err;
474 }
475 
477 {
478  psa_status_t err;
479 
480  /* Retrieve the object information from the object table if the object
481  * exists.
482  */
483  err = ps_object_table_get_obj_tbl_info(uid, client_id, &g_obj_tbl_info);
484  if (err != PSA_SUCCESS) {
485  return err;
486  }
487 
488 #ifdef PS_ENCRYPTION
489  err = ps_encrypted_object_read(g_obj_tbl_info.fid, &g_ps_object);
490 #else
491  err = ps_read_object(READ_HEADER_ONLY);
492 #endif
493  if (err != PSA_SUCCESS) {
494  goto clear_data_and_return;
495  }
496 
497  /* Check that the write once flag is not set */
500  goto clear_data_and_return;
501  }
502 
503  /* Delete object from the table and stores the table in the persistent
504  * area.
505  */
506  err = ps_object_table_delete_object(uid, client_id);
507  if (err != PSA_SUCCESS) {
508  goto clear_data_and_return;
509  }
510 
511  /* Remove old object table and file */
512  err = ps_remove_old_data(g_obj_tbl_info.fid);
513 
514 clear_data_and_return:
515  /* Remove data stored in the object before leaving the function */
516  (void)tfm_memset(&g_ps_object, PS_DEFAULT_EMPTY_BUFF_VAL,
518 
519  return err;
520 }
521 
523 {
524  /* This function may get called as a corrective action
525  * if a system level security violation is detected.
526  * This could be asynchronous to normal system operation
527  * and state of the ps system lock is unknown. Hence
528  * this function doesn't block on the lock and directly
529  * moves to erasing the flash instead.
530  */
531  return ps_object_table_create();
532 }
read_type_t
psa_status_t ps_encrypted_object_read(uint32_t fid, struct ps_object_t *obj)
Reads object referenced by the object File ID.
psa_status_t ps_object_table_init(uint8_t *obj_data)
Initializes object table.
__STATIC_INLINE void * tfm_memset(void *ptr, int value, size_t num)
#define PSA_SUCCESS
Definition: crypto_values.h:35
#define PS_OBJECT_HEADER_SIZE
struct ps_object_info_t info
uint8_t data[PS_MAX_ASSET_SIZE]
#define PS_MAX_OBJECT_SIZE
__STATIC_INLINE void ps_init_empty_object(psa_storage_create_flags_t create_flags, uint32_t size, struct ps_object_t *obj)
Initialize g_ps_object based on the input parameters and empty data.
#define PS_INVALID_FID
Definition: ps_utils.h:20
#define PSA_STORAGE_FLAG_WRITE_ONCE
psa_status_t psa_its_get(psa_storage_uid_t uid, size_t data_offset, size_t data_size, void *p_data, size_t *p_data_length)
Retrieve data associated with a provided UID.
psa_status_t psa_its_remove(psa_storage_uid_t uid)
Remove the provided uid and its associated data from the storage.
psa_status_t ps_object_get_info(psa_storage_uid_t uid, int32_t client_id, struct psa_storage_info_t *info)
Gets the asset information for the object with the provided UID and client ID.
psa_status_t ps_object_table_delete_object(psa_storage_uid_t uid, int32_t client_id)
Deletes the table entry for the provided UID and client ID pair.
psa_status_t ps_utils_check_contained_in(uint32_t superset_size, uint32_t subset_offset, uint32_t subset_size)
Checks if a subset region is fully contained within a superset region.
Definition: ps_utils.c:10
psa_status_t ps_object_table_delete_old_table(void)
Deletes old object table from the persistent area.
#define PSA_ERROR_INVALID_ARGUMENT
psa_status_t psa_its_set(psa_storage_uid_t uid, size_t data_length, const void *p_data, psa_storage_create_flags_t create_flags)
Create a new, or modify an existing, uid/value pair.
#define PS_OBJECT_SIZE(max_size)
#define PSA_ERROR_NOT_PERMITTED
Definition: crypto_values.h:65
psa_status_t ps_req_mngr_read_asset_data(uint8_t *out_data, uint32_t size)
Writes the asset data of a client iovec onto an output buffer.
void ps_req_mngr_write_asset_data(const uint8_t *in_data, uint32_t size)
Takes an input buffer containing asset data and writes its contents to the client iovec...
psa_status_t ps_object_table_get_obj_tbl_info(psa_storage_uid_t uid, int32_t client_id, struct ps_obj_table_info_t *obj_tbl_info)
Gets object table information from the object table for the provided UID and client ID pair...
psa_status_t ps_object_delete(psa_storage_uid_t uid, int32_t client_id)
Deletes the object with the provided UID and client ID.
psa_status_t ps_encrypted_object_write(uint32_t fid, struct ps_object_t *obj)
Creates and writes a new encrypted object based on the given ps_object_t structure data...
psa_status_t ps_object_table_get_free_fid(uint32_t fid_num, uint32_t *p_fid)
Gets a not in use file ID.
struct ps_obj_header_t header
uint64_t psa_storage_uid_t
psa_status_t ps_object_create(psa_storage_uid_t uid, int32_t client_id, psa_storage_create_flags_t create_flags, uint32_t size)
Creates a new object with the provided UID and client ID.
#define PS_OBJECT_START_POSITION
psa_status_t ps_object_read(psa_storage_uid_t uid, int32_t client_id, uint32_t offset, uint32_t size, size_t *p_data_length)
Gets the data of the object with the provided UID and client ID.
psa_status_t ps_object_write(psa_storage_uid_t uid, int32_t client_id, uint32_t offset, uint32_t size)
Writes data into the object with the provided UID and client ID.
psa_storage_create_flags_t flags
psa_storage_create_flags_t create_flags
#define PSA_STORAGE_FLAG_NONE
#define PS_UTILS_MIN(x, y)
Evaluates to the minimum of the two parameters.
Definition: ps_utils.h:41
#define PSA_ERROR_DOES_NOT_EXIST
Definition: crypto_values.h:89
uint32_t psa_storage_create_flags_t
psa_status_t ps_object_table_create(void)
Creates object table.
int32_t psa_status_t
Function return status.
Definition: crypto_types.h:43
#define PSA_ERROR_DATA_CORRUPT
psa_status_t ps_object_table_set_obj_tbl_info(psa_storage_uid_t uid, int32_t client_id, const struct ps_obj_table_info_t *obj_tbl_info)
Sets object table information in the object table and stores it persistently, for the provided UID an...
The object to be written to the file system below. Made up of the object header and the object data...
psa_status_t ps_system_wipe_all(void)
Wipes the protected storage system and all object data.
uint32_t current_size
Object table information structure.
#define PS_DEFAULT_EMPTY_BUFF_VAL
Definition: ps_utils.h:21
psa_status_t ps_system_prepare(void)
Prepares the protected storage system for usage, populating internal structures. It identifies and va...