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