TF-M Reference Manual  1.2.0
TrustedFirmware-M
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
audit_core.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include <stdint.h>
9 #include <string.h>
10 #include <stddef.h>
11 #include "audit_core.h"
12 #include "psa_audit_defs.h"
13 #include "tfm_secure_api.h"
14 
21 #ifndef AUDIT_UART_REDIRECTION
22 #define AUDIT_UART_REDIRECTION (0U)
23 #endif
24 
25 #if (AUDIT_UART_REDIRECTION == 1U)
26 /* CMSIS Driver for UART */
27 #include "Driver_USART.h"
28 
29 #ifndef LOG_UART_NAME
30 /* Default secure UART name */
31 #define LOG_UART_NAME Driver_USART1
32 #endif
33 extern ARM_DRIVER_USART LOG_UART_NAME;
34 
41 #ifndef LOG_UART_BAUD_RATE
42 #define LOG_UART_BAUD_RATE (DEFAULT_UART_BAUDRATE)
43 #endif
44 
51 static uint8_t log_uart_init_success = 0U;
52 
59 static const char hex_values[] = "0123456789ABCDEF";
60 #endif
61 
67 #define MEMBER_SIZE(type,member) sizeof(((type *)0)->member)
68 
76 #define LOG_FIXED_FIELD_SIZE (MEMBER_SIZE(struct log_hdr, timestamp) + \
77  MEMBER_SIZE(struct log_hdr, iv_counter) + \
78  MEMBER_SIZE(struct log_hdr, partition_id) + \
79  MEMBER_SIZE(struct log_hdr, size))
80 
87 #define LOG_SIZE (1024)
88 
96 __attribute__ ((aligned(4)))
97 static uint8_t log_buffer[LOG_SIZE] = {0};
98 
105 static uint64_t scratch_buffer[(LOG_SIZE)/8] = {0};
106 
113 struct log_vars {
114  uint32_t first_el_idx;
116  uint32_t last_el_idx;
118  uint32_t num_records;
121  uint32_t stored_size;
123 };
124 
130 static struct log_vars log_state = {0};
131 
142 static uint64_t global_timestamp = 0;
143 
151 __attribute__ ((always_inline)) __STATIC_INLINE
152 struct log_hdr *GET_LOG_POINTER(const uint32_t idx)
153 {
154  return (struct log_hdr *)( &log_buffer[idx] );
155 }
156 
164 __attribute__ ((always_inline)) __STATIC_INLINE
165 uint32_t *GET_SIZE_FIELD_POINTER(const uint32_t idx)
166 {
167  return (uint32_t *) GET_LOG_POINTER( (idx+offsetof(struct log_hdr, size))
168  % LOG_SIZE );
169 }
170 
180 __attribute__ ((always_inline)) __STATIC_INLINE
181 uint32_t COMPUTE_LOG_ENTRY_SIZE(const uint32_t size)
182 {
183  return (LOG_FIXED_FIELD_SIZE + size + LOG_MAC_SIZE);
184 }
185 
194 __attribute__ ((always_inline)) __STATIC_INLINE
195 uint32_t GET_NEXT_LOG_INDEX(const uint32_t idx)
196 {
197  return (uint32_t) ( (idx + COMPUTE_LOG_ENTRY_SIZE(
198  *GET_SIZE_FIELD_POINTER(idx)) ) % LOG_SIZE );
199 }
200 
211 static void audit_update_state(const uint32_t first_el_idx,
212  const uint32_t last_el_idx,
213  const uint32_t stored_size,
214  const uint32_t num_records)
215 {
216  /* Update the indexes */
217  log_state.first_el_idx = first_el_idx;
218  log_state.last_el_idx = last_el_idx;
219 
220  /* Update the number of records stored */
221  log_state.num_records = num_records;
222 
223  /* Update the size of the stored records */
224  log_state.stored_size = stored_size;
225 }
226 
237 static void audit_replace_record(const uint32_t size,
238  uint32_t *begin,
239  uint32_t *end)
240 {
241  uint32_t first_el_idx = 0, last_el_idx = 0;
242  uint32_t num_items = 0, stored_size = 0;
243  uint32_t start_pos = 0, stop_pos = 0;
244 
245  /* Retrieve the current state variables of the log */
246  first_el_idx = log_state.first_el_idx;
247  last_el_idx = log_state.last_el_idx;
248  num_items = log_state.num_records;
249  stored_size = log_state.stored_size;
250 
251  /* If there is not enough size, remove older entries */
252  while (size > (LOG_SIZE - stored_size)) {
253 
254  /* In case we did a full loop without finding space, reset */
255  if (num_items == 0) {
256  first_el_idx = 0;
257  last_el_idx = 0;
258  num_items = 0;
259  stored_size = 0;
260  break;
261  }
262 
263  /* Remove the oldest */
265  *GET_SIZE_FIELD_POINTER(first_el_idx) );
266  num_items--;
267  first_el_idx = GET_NEXT_LOG_INDEX(first_el_idx);
268  }
269 
270  /* Get the start and stop positions */
271  if (num_items == 0) {
272  start_pos = first_el_idx;
273  } else {
274  start_pos = GET_NEXT_LOG_INDEX(last_el_idx);
275  }
276  stop_pos = ((start_pos + COMPUTE_LOG_ENTRY_SIZE(size)) % LOG_SIZE);
277 
278  /* Return begin and end positions */
279  *begin = start_pos;
280  *end = stop_pos;
281 
282  /* Update the state with the new values of variables */
283  audit_update_state(first_el_idx, last_el_idx, stored_size, num_items);
284 }
285 
295 static psa_status_t audit_buffer_copy(const uint8_t *src,
296  const uint32_t size,
297  uint8_t *dest)
298 {
299  uint32_t idx = 0;
300  uint32_t dest_idx = (uint32_t)dest - (uint32_t)&log_buffer[0];
301 
302  if ((dest_idx >= LOG_SIZE) || (size > LOG_SIZE)) {
304  }
305 
306  /* TODO: This can be an optimized copy using uint32_t
307  * and enforcing the condition that wrapping
308  * happens only on 4-byte boundaries
309  */
310 
311  for (idx = 0; idx < size; idx++) {
312  log_buffer[(dest_idx + idx) % LOG_SIZE] = src[idx];
313  }
314 
315  return PSA_SUCCESS;
316 }
317 
326 static psa_status_t audit_memcpy(const uint8_t *src,
327  const uint32_t size,
328  uint8_t *dest)
329 {
330  uint32_t idx = 0;
331 
332  for (idx = 0; idx < size; idx++) {
333  dest[idx] = src[idx];
334  }
335 
336  return PSA_SUCCESS;
337 }
338 
348 static psa_status_t audit_format_buffer(const struct psa_audit_record *record,
349  const int32_t partition_id,
350  uint64_t *buffer)
351 {
352  struct log_hdr *hdr = NULL;
353  struct log_tlr *tlr = NULL;
354  uint32_t size;
355  uint8_t idx;
356  psa_status_t status;
357 
358  /* Get the size from the record */
359  size = record->size;
360 
361  /* Format the scratch buffer with the complete log item */
362  hdr = (struct log_hdr *) buffer;
363 
364  /* FIXME: Timestamping needs to be obtained through Secure Time service, not
365  * yet available. Use a global timestamp for the time being, without
366  * the need to increase the value of iv_counter. In the final
367  * implementation, iv_counter is concatenated to timestamp to get a
368  * 12 byte unique IV to be used by the encryption module, and needs
369  * to be increased every time the timestamp didn't change between
370  * consecutive invocations.
371  */
372  hdr->timestamp = global_timestamp++;
373  hdr->iv_counter = 0;
374  hdr->partition_id = partition_id;
375 
376  /* Copy the record into the scratch buffer */
377  status = audit_memcpy((const uint8_t *) record,
378  size+4,
379  (uint8_t *) &(hdr->size));
380  if (status != PSA_SUCCESS) {
381  return status;
382  }
383 
384  /* FIXME: The MAC here is just a dummy value for prototyping. It will be
385  * filled by a call to the crypto interface directly when available.
386  */
387  tlr = (struct log_tlr *) ((uint8_t *)hdr + LOG_FIXED_FIELD_SIZE + size);
388  for (idx=0; idx<LOG_MAC_SIZE; idx++) {
389  tlr->mac[idx] = idx;
390  }
391 
392  return PSA_SUCCESS;
393 }
394 
405 static void audit_uart_redirection(const uint32_t start_idx)
406 {
407 #if (AUDIT_UART_REDIRECTION == 1U)
408  uint32_t size = *GET_SIZE_FIELD_POINTER(start_idx);
409  uint8_t end_of_line[] = {'\r', '\n'};
410  uint32_t idx = 0;
411  uint8_t read_byte;
412 
413  if (log_uart_init_success == 1U) {
414  for (idx=0; idx<COMPUTE_LOG_ENTRY_SIZE(size); idx++) {
415  read_byte = log_buffer[(start_idx+idx) % LOG_SIZE];
416  (void)LOG_UART_NAME.Send(&hex_values[(read_byte >> 4) & 0xF],1);
417  (void)LOG_UART_NAME.Send(&hex_values[read_byte & 0xF], 1);
418  (void)LOG_UART_NAME.Send(" ", 1);
419  }
420  (void)LOG_UART_NAME.Send(&end_of_line, 2);
421  }
422 #endif
423 }
424 
425 static psa_status_t _audit_core_get_info(uint32_t *num_records, uint32_t *size)
426 {
427  /* Return the number of records that are currently stored */
428  *num_records = log_state.num_records;
429 
430  /* Return the size of the records currently stored */
431  *size = log_state.stored_size;
432 
433  return PSA_SUCCESS;
434 }
435 
436 static psa_status_t _audit_core_get_record_info(const uint32_t record_index,
437  uint32_t *size)
438 {
439  uint32_t start_idx, idx;
440 
441  if (record_index >= log_state.num_records) {
443  }
444 
445  /* First element to read from the log */
446  start_idx = log_state.first_el_idx;
447 
448  /* Move the start_idx index to the desired element */
449  for (idx = 0; idx < record_index; idx++) {
450  start_idx = GET_NEXT_LOG_INDEX(start_idx);
451  }
452 
453  /* Get the size of the requested record */
454  *size = COMPUTE_LOG_ENTRY_SIZE(*GET_SIZE_FIELD_POINTER(start_idx));
455 
456  return PSA_SUCCESS;
457 }
458 
466 {
467 #if (AUDIT_UART_REDIRECTION == 1U)
468  int32_t ret = ARM_DRIVER_OK;
469 
470  ret = LOG_UART_NAME.Initialize(NULL);
471  if (ret != ARM_DRIVER_OK) {
473  }
474 
475  ret = LOG_UART_NAME.Control(ARM_USART_MODE_ASYNCHRONOUS,
476  LOG_UART_BAUD_RATE);
477  if (ret != ARM_DRIVER_OK) {
479  }
480 
481  /* If we get to this point, UART init is successful */
482  log_uart_init_success = 1U;
483 #endif
484 
485  /* Clear the log state variables */
486  audit_update_state(0,0,0,0);
487 
488  return PSA_SUCCESS;
489 }
490 
492  size_t in_len,
493  psa_outvec out_vec[],
494  size_t out_len)
495 {
496  uint32_t first_el_idx, size_removed;
497 
498  if ((in_len != 2) || (out_len != 0)) {
500  }
501 
502  if (in_vec[0].len != sizeof(uint32_t)) {
504  }
505 
506  const uint32_t record_index = *((uint32_t *)in_vec[0].base);
507  const uint8_t *token = in_vec[1].base;
508  const uint32_t token_size = in_vec[1].len;
509 
510  /* FixMe: Currently only the removal of the oldest entry, i.e.
511  * record_index 0, is supported. This has to be extended
512  * to support removal of random records
513  */
514  if (record_index > 0) {
516  }
517 
518  /* FixMe: Currently token and token_size parameters are not evaluated
519  * to check if the removal of the desired record_index is
520  * authorised
521  */
522  if ((token != NULL) || (token_size != 0)) {
524  }
525 
526  /* Check that the record index to be removed is contained in the log */
527  if (record_index >= log_state.num_records) {
529  }
530 
531  /* If the log contains just one element, reset the state and return */
532  if (log_state.num_records == 1) {
533 
534  /* Clear the log state variables */
535  audit_update_state(0,0,0,0);
536 
537  return PSA_SUCCESS;
538  }
539 
540  /* Get the index to the element to be removed */
541  first_el_idx = log_state.first_el_idx;
542 
543  /* Get the size of the element that is being removed */
544  size_removed = COMPUTE_LOG_ENTRY_SIZE(
545  *GET_SIZE_FIELD_POINTER(first_el_idx));
546 
547  /* Remove the oldest entry, it means moving the first element to the
548  * next log index */
549  first_el_idx = GET_NEXT_LOG_INDEX(first_el_idx);
550 
551  /* Update the state with the new head and decrease the number of records
552  * currently stored and the new size of the stored records */
553  log_state.first_el_idx = first_el_idx;
554  log_state.num_records--;
555  log_state.stored_size -= size_removed;
556 
557  return PSA_SUCCESS;
558 }
559 
561  size_t in_len,
562  psa_outvec out_vec[],
563  size_t out_len)
564 {
565  if ((in_len != 0) || (out_len != 2)) {
567  }
568 
569  if ((out_vec[0].len != sizeof(uint32_t)) ||
570  (out_vec[1].len != sizeof(uint32_t))) {
572  }
573 
574  uint32_t *num_records = out_vec[0].base;
575  uint32_t *size = out_vec[1].base;
576 
577  /* Return the number of records that are currently stored */
578  *num_records = log_state.num_records;
579 
580  /* Return the size of the records currently stored */
581  *size = log_state.stored_size;
582 
583  return PSA_SUCCESS;
584 }
585 
587  size_t in_len,
588  psa_outvec out_vec[],
589  size_t out_len)
590 {
591  uint32_t start_idx, idx;
592 
593  if ((in_len != 1) || (out_len != 1)) {
595  }
596 
597  if ((in_vec[0].len != sizeof(uint32_t)) ||
598  (out_vec[0].len != sizeof(uint32_t))) {
600  }
601 
602  const uint32_t record_index = *((uint32_t *)in_vec[0].base);
603  uint32_t *size = out_vec[0].base;
604 
605  if (record_index >= log_state.num_records) {
607  }
608 
609  /* First element to read from the log */
610  start_idx = log_state.first_el_idx;
611 
612  /* Move the start_idx index to the desired element */
613  for (idx = 0; idx < record_index; idx++) {
614  start_idx = GET_NEXT_LOG_INDEX(start_idx);
615  }
616 
617  /* Get the size of the requested record */
618  *size = COMPUTE_LOG_ENTRY_SIZE(*GET_SIZE_FIELD_POINTER(start_idx));
619 
620  return PSA_SUCCESS;
621 }
622 
624  size_t in_len,
625  psa_outvec out_vec[],
626  size_t out_len)
627 {
628  uint32_t start_pos = 0, stop_pos = 0;
629  uint32_t first_el_idx = 0, last_el_idx = 0, size = 0;
630  uint32_t num_items = 0, stored_size = 0;
631  int32_t partition_id;
632  psa_status_t status;
633 
634  if ((in_len != 1) || (out_len != 0)) {
636  }
637 
638  if (in_vec[0].len != sizeof(struct psa_audit_record)) {
640  }
641 
642  const struct psa_audit_record *record = in_vec[0].base;
643 
644  /* Get the value of the partition ID of the caller through TFM secure API */
645  if (tfm_core_get_caller_client_id(&partition_id) != (int32_t)TFM_SUCCESS) {
647  }
648 
649  /* Check if the partition ID of the caller is from NS world */
650  if (TFM_CLIENT_ID_IS_NS(partition_id)) {
652  }
653 
654  /* Read the size from the input record */
655  size = record->size;
656 
657  /* Check that size is a 4-byte multiple as expected */
658  if (size % 4) {
660  }
661 
662  /* Check that the entry to be added is not greater than the
663  * maximum space available
664  */
665  if (size > (LOG_SIZE - (LOG_FIXED_FIELD_SIZE+LOG_MAC_SIZE))) {
667  }
668 
669  /* Get the size in bytes and num of elements present in the log */
670  status = _audit_core_get_info(&num_items, &stored_size);
671  if (status != PSA_SUCCESS) {
672  return status;
673  }
674 
675  if (num_items == 0) {
676 
677  start_pos = 0;
678 
679  } else {
680 
681  /* The log is not empty, need to decide the candidate position
682  * and invalidate older entries in case there is not enough space
683  */
684  audit_replace_record(COMPUTE_LOG_ENTRY_SIZE(size),
685  &start_pos,
686  &stop_pos);
687  }
688 
689  /* Format the scratch buffer with the complete log item */
690  status = audit_format_buffer(record, partition_id, &scratch_buffer[0]);
691  if (status != PSA_SUCCESS) {
692  return status;
693  }
694 
695  /* TODO: At this point, encryption should be called if supported */
696 
697  /* Do the copy of the log item to be added in the log */
698  status = audit_buffer_copy((const uint8_t *) &scratch_buffer[0],
700  (uint8_t *) &log_buffer[start_pos]);
701  if (status != PSA_SUCCESS) {
702  return status;
703  }
704 
705  /* Retrieve current log state */
706  first_el_idx = log_state.first_el_idx;
707  num_items = log_state.num_records;
708  stored_size = log_state.stored_size;
709 
710  /* The last element is the one we just added */
711  last_el_idx = start_pos;
712 
713  /* Update the number of items and stored size */
714  num_items++;
715  stored_size += COMPUTE_LOG_ENTRY_SIZE(size);
716 
717  /* Update the log state */
718  audit_update_state(first_el_idx, last_el_idx, stored_size, num_items);
719 
720  /* TODO: At this point, we would need to update the stored copy in
721  * persistent storage. Need to define a strategy for this
722  */
723 
724  /* Stream to a secure UART if available for the platform and built */
725  audit_uart_redirection(last_el_idx);
726 
727  return PSA_SUCCESS;
728 }
729 
731  size_t in_len,
732  psa_outvec out_vec[],
733  size_t out_len)
734 {
735  uint32_t idx, start_idx, record_size_tmp;
736  psa_status_t status;
737 
738  if ((in_len != 2) || (out_len != 1)) {
740  }
741 
742  if (in_vec[0].len != sizeof(uint32_t)) {
744  }
745  const uint32_t record_index = *((uint32_t *)in_vec[0].base);
746  const uint8_t *token = in_vec[1].base;
747  const uint32_t token_size = in_vec[1].len;
748  uint8_t *buffer = out_vec[0].base;
749  uint32_t buffer_size = out_vec[0].len;
750 
751  /* FixMe: Currently token and token_size parameters are not evaluated
752  * to be used as a challenge for encryption as encryption support
753  * is still not yet available
754  */
755  if ((token != NULL) || (token_size != 0)) {
756  out_vec[0].len = 0;
758  }
759 
760  /* Get the size of the record we want to retrieve */
761  status = _audit_core_get_record_info(record_index, &record_size_tmp);
762 
763  /* Propagate the error to the caller in case of failure */
764  if (status != PSA_SUCCESS) {
765  out_vec[0].len = 0;
766  return status;
767  }
768 
769  /* buffer_size must be enough to hold the requested record */
770  if (buffer_size < record_size_tmp) {
771  out_vec[0].len = 0;
773  }
774 
775  /* First element to read from the log */
776  start_idx = log_state.first_el_idx;
777 
778  /* Move the start_idx index to the desired element */
779  for (idx=0; idx<record_index; idx++) {
780  start_idx = GET_NEXT_LOG_INDEX(start_idx);
781  }
782 
783  /* Do the copy */
784  for (idx=0; idx<record_size_tmp; idx++) {
785  buffer[idx] = log_buffer[(start_idx + idx) % LOG_SIZE];
786  }
787 
788  /* Update the retrieved size */
789  out_vec[0].len = record_size_tmp;
790 
791  return PSA_SUCCESS;
792 }
uint32_t stored_size
Definition: audit_core.c:121
void * base
Definition: client.h:75
uint32_t size
Definition: audit_core.h:103
__STATIC_INLINE uint32_t COMPUTE_LOG_ENTRY_SIZE(const uint32_t size)
Static inline function to compute the full log entry size starting from the value of the size field...
Definition: audit_core.c:181
#define PSA_SUCCESS
Definition: crypto_values.h:35
#define PSA_ERROR_BUFFER_TOO_SMALL
Definition: crypto_values.h:77
psa_status_t audit_core_delete_record(psa_invec in_vec[], size_t in_len, psa_outvec out_vec[], size_t out_len)
Definition: audit_core.c:491
size_t len
Definition: client.h:68
uint32_t iv_counter
Definition: audit_core.h:101
psa_status_t audit_core_add_record(psa_invec in_vec[], size_t in_len, psa_outvec out_vec[], size_t out_len)
Definition: audit_core.c:623
Fixed size header for a log record.
Definition: audit_core.h:99
#define LOG_MAC_SIZE
Size in bytes of the MAC for each entry.
Definition: audit_core.h:92
#define PSA_ERROR_INSUFFICIENT_MEMORY
uint32_t num_records
Definition: audit_core.c:118
#define PSA_ERROR_GENERIC_ERROR
Definition: crypto_values.h:43
This structure contains the record that is added to the audit log by the requesting secure service...
#define PSA_ERROR_NOT_PERMITTED
Definition: crypto_values.h:65
uint8_t mac[(4)]
Definition: audit_core.h:113
Contains the state variables associated to the current state of the audit log.
Definition: audit_core.c:113
__STATIC_INLINE uint32_t GET_NEXT_LOG_INDEX(const uint32_t idx)
Static inline function to get the index to the base of the log buffer for the next item with respect ...
Definition: audit_core.c:195
#define PSA_ERROR_PROGRAMMER_ERROR
Definition: error.h:32
int32_t tfm_core_get_caller_client_id(int32_t *caller_client_id)
Definition: arch.c:28
#define PSA_ERROR_NOT_SUPPORTED
Definition: crypto_values.h:52
#define LOG_SIZE
Size of the allocated space for the log, in bytes.
Definition: audit_core.c:87
psa_status_t audit_core_init(void)
Initializes the Audit logging service during the TFM boot up process.
Definition: audit_core.c:465
uint32_t first_el_idx
Definition: audit_core.c:114
#define PSA_ERROR_CONNECTION_REFUSED
Definition: error.h:33
size_t len
Definition: client.h:76
Fixed size logging entry trailer.
Definition: audit_core.h:112
#define LOG_FIXED_FIELD_SIZE
Size of the mandatory header fields that are before the info received from the client partition...
Definition: audit_core.c:76
psa_status_t audit_core_get_info(psa_invec in_vec[], size_t in_len, psa_outvec out_vec[], size_t out_len)
Definition: audit_core.c:560
int32_t partition_id
Definition: audit_core.h:102
#define TFM_CLIENT_ID_IS_NS(client_id)
Checks if the provided client ID is a non-secure client ID.
Definition: tfm_api.h:38
uint32_t last_el_idx
Definition: audit_core.c:116
psa_status_t audit_core_retrieve_record(psa_invec in_vec[], size_t in_len, psa_outvec out_vec[], size_t out_len)
Definition: audit_core.c:730
const void * base
Definition: client.h:67
int32_t psa_status_t
Function return status.
Definition: crypto_types.h:43
__STATIC_INLINE uint32_t * GET_SIZE_FIELD_POINTER(const uint32_t idx)
Static inline function to get the pointer to the SIZE field.
Definition: audit_core.c:165
uint64_t timestamp
Definition: audit_core.h:100
psa_status_t audit_core_get_record_info(psa_invec in_vec[], size_t in_len, psa_outvec out_vec[], size_t out_len)
Definition: audit_core.c:586
__STATIC_INLINE struct log_hdr * GET_LOG_POINTER(const uint32_t idx)
Static inline function to get the log buffer ptr from index.
Definition: audit_core.c:152