Exemplo n.º 1
0
/**
\brief Test case: TC_CoreFunc_PSPLIM
\details
- Check if __get_PSPLIM and __set_PSPLIM intrinsic can be used to manipulate process stack pointer limit.
*/
void TC_CoreFunc_PSPLIM (void) {
  // don't use stack for this variables
  static uint32_t orig;
  static uint32_t psplim;
  static uint32_t result;

  orig = __get_PSPLIM();

  psplim = orig + 0x12345678U;
  __set_PSPLIM(psplim);

  result = __get_PSPLIM();

  __set_PSPLIM(orig);

#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \
     (!defined (__ARM_FEATURE_CMSE  ) || (__ARM_FEATURE_CMSE   < 3)))
  // without main extensions, the non-secure PSPLIM is RAZ/WI
  ASSERT_TRUE(result == 0U);
#else
  ASSERT_TRUE(result == psplim);
#endif
}
Exemplo n.º 2
0
static int32_t tfm_return_from_partition(uint32_t *excReturn)
{
    uint32_t current_partition_idx =
            tfm_spm_partition_get_running_partition_idx();
    const struct spm_partition_runtime_data_t *curr_part_data, *ret_part_data;
    uint32_t current_partition_flags;
    uint32_t return_partition_idx;
    uint32_t return_partition_flags;
    uint32_t psp = __get_PSP();
    size_t i;
    struct tfm_exc_stack_t *svc_ctx = (struct tfm_exc_stack_t *)psp;
    struct iovec_args_t *iovec_args;

    if (current_partition_idx == SPM_INVALID_PARTITION_IDX) {
        return TFM_SECURE_UNLOCK_FAILED;
    }

    curr_part_data = tfm_spm_partition_get_runtime_data(current_partition_idx);
    return_partition_idx = curr_part_data->caller_partition_idx;

    if (return_partition_idx == SPM_INVALID_PARTITION_IDX) {
        return TFM_SECURE_UNLOCK_FAILED;
    }

    ret_part_data = tfm_spm_partition_get_runtime_data(return_partition_idx);

    return_partition_flags = tfm_spm_partition_get_flags(return_partition_idx);
    current_partition_flags = tfm_spm_partition_get_flags(
            current_partition_idx);

    tfm_secure_lock--;

    if((return_partition_flags & SPM_PART_FLAG_APP_ROT) == 0) {
        /* Re-enable NS exceptions when secure service returns to NS client.
         * FixMe:
         * To be removed when pre-emption and context management issues have
         * been analysed and resolved.
         */
        TFM_NS_EXC_ENABLE();
    }

#if (TFM_LVL != 1) && (TFM_LVL != 2)
    /* Deconfigure completed partition environment */
    tfm_spm_partition_sandbox_deconfig(current_partition_idx);
    if (tfm_secure_api_initializing) {
        /* Restore privilege for thread mode during TF-M init. This is only
         * have to be done if the partition is not trusted.
         */
        if ((current_partition_flags & SPM_PART_FLAG_PSA_ROT) == 0) {
            CONTROL_Type ctrl;

            ctrl.w = __get_CONTROL();
            ctrl.b.nPRIV = 0;
            __set_CONTROL(ctrl.w);
            __DSB();
            __ISB();
        }
    } else {
        /* Configure the caller partition environment in case this was a
         * partition to partition call and returning to untrusted partition
         */
        if (tfm_spm_partition_sandbox_config(return_partition_idx)
            != SPM_ERR_OK) {
            ERROR_MSG("Failed to configure sandbox for partition!");
            tfm_secure_api_error_handler();
        }
        if (return_partition_flags & SPM_PART_FLAG_APP_ROT) {
            /* Restore share status */
            tfm_spm_partition_set_share(
                return_partition_idx,
                tfm_spm_partition_get_runtime_data(
                    return_partition_idx)->share);
        }
    }
#endif

#if TFM_LVL == 1
    if (!(return_partition_flags & SPM_PART_FLAG_APP_ROT) ||
        (tfm_secure_api_initializing)) {
        /* In TFM level 1 context restore is only done when
         * returning to NS or after initialization
         */
        /* Restore caller context */
        restore_caller_ctx(svc_ctx,
            (struct tfm_exc_stack_t *)ret_part_data->stack_ptr);
        *excReturn = ret_part_data->lr;
        __set_PSP(ret_part_data->stack_ptr);
        extern uint32_t Image$$ARM_LIB_STACK$$ZI$$Base[];
        uint32_t psp_stack_bottom = (uint32_t)Image$$ARM_LIB_STACK$$ZI$$Base;
       __set_PSPLIM(psp_stack_bottom);

        /* FIXME: The condition should be removed once all the secure service
         *        calls are done via the iovec veneers */
        if (curr_part_data->iovec_api) {
            iovec_args = (struct iovec_args_t *)
                         ((uint32_t)&REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit)-
                         sizeof(struct iovec_args_t));

            for (i = 0; i < curr_part_data->iovec_args.out_len; ++i) {
                curr_part_data->orig_outvec[i].len = iovec_args->out_vec[i].len;
            }
            tfm_clear_iovec_parameters(iovec_args);
        }
    }
#else
    /* Restore caller context */
    restore_caller_ctx(svc_ctx,
        (struct tfm_exc_stack_t *)ret_part_data->stack_ptr);
    *excReturn = ret_part_data->lr;
    __set_PSP(ret_part_data->stack_ptr);
    __set_PSPLIM(tfm_spm_partition_get_stack_bottom(return_partition_idx));
    /* Clear the context entry before returning */
    tfm_spm_partition_set_stack(
                current_partition_idx, psp + sizeof(struct tfm_exc_stack_t));

    /* FIXME: The condition should be removed once all the secure service
     *        calls are done via the iovec veneers */
    if (curr_part_data->iovec_api) {
        iovec_args = (struct iovec_args_t *)
                     (tfm_spm_partition_get_stack_top(current_partition_idx) -
                     sizeof(struct iovec_args_t));

        for (i = 0; i < curr_part_data->iovec_args.out_len; ++i) {
            curr_part_data->orig_outvec[i].len = iovec_args->out_vec[i].len;
        }
        tfm_clear_iovec_parameters(iovec_args);
    }
#endif

    tfm_spm_partition_cleanup_context(current_partition_idx);

    tfm_spm_partition_set_state(current_partition_idx,
                                SPM_PARTITION_STATE_IDLE);
    tfm_spm_partition_set_state(return_partition_idx,
                                SPM_PARTITION_STATE_RUNNING);

    return TFM_SUCCESS;
}
Exemplo n.º 3
0
static int32_t tfm_start_partition(const struct tfm_sfn_req_s *desc_ptr,
                                                             uint32_t excReturn)
{
    uint32_t caller_partition_idx = desc_ptr->caller_part_idx;
    const struct spm_partition_runtime_data_t *curr_part_data;
    uint32_t caller_flags;
    register uint32_t partition_idx;
    uint32_t psp = __get_PSP();
    uint32_t partition_psp, partition_psplim;
    uint32_t partition_state;
    uint32_t partition_flags;
    struct tfm_exc_stack_t *svc_ctx = (struct tfm_exc_stack_t *)psp;
    uint32_t caller_partition_id;
    int32_t client_id;
    struct iovec_args_t *iovec_args;

    caller_flags = tfm_spm_partition_get_flags(caller_partition_idx);

    /* Check partition state consistency */
    if (((caller_flags & SPM_PART_FLAG_APP_ROT) != 0)
        != (!desc_ptr->ns_caller)) {
        /* Partition state inconsistency detected */
        return TFM_SECURE_LOCK_FAILED;
    }

    if((caller_flags & SPM_PART_FLAG_APP_ROT) == 0) {
        /* Disable NS exception handling while secure service is running.
         * FixMe:
         * This restriction is applied to limit the number of possible attack
         * vectors.
         * To be removed when pre-emption and context management issues have
         * been analysed and resolved.
         */
        TFM_NS_EXC_DISABLE();
    }

    partition_idx = get_partition_idx(desc_ptr->sp_id);

    curr_part_data = tfm_spm_partition_get_runtime_data(partition_idx);
    partition_state = curr_part_data->partition_state;
    partition_flags = tfm_spm_partition_get_flags(partition_idx);
    caller_partition_id = tfm_spm_partition_get_partition_id(
                                                          caller_partition_idx);

    if (tfm_secure_api_initializing) {
#if TFM_LVL != 1
        /* Make thread mode unprivileged while untrusted partition init is
         * executed
         */
        if ((partition_flags & SPM_PART_FLAG_PSA_ROT) == 0) {
            CONTROL_Type ctrl;

            ctrl.w = __get_CONTROL();
            ctrl.b.nPRIV = 1;
            __set_CONTROL(ctrl.w);
            __DSB();
            __ISB();
        }
#endif
    } else if (partition_state == SPM_PARTITION_STATE_RUNNING ||
        partition_state == SPM_PARTITION_STATE_SUSPENDED ||
        partition_state == SPM_PARTITION_STATE_BLOCKED) {
        /* Recursion is not permitted! */
        return TFM_ERROR_PARTITION_NON_REENTRANT;
    } else if (partition_state != SPM_PARTITION_STATE_IDLE) {
        /* The partition to be called is not in a proper state */
        return TFM_SECURE_LOCK_FAILED;
    }

#if TFM_LVL == 1
    /* Prepare switch to shared secure partition stack */
    /* In case the call is coming from the non-secure world, we save the iovecs
     * on the stop of the stack. So the memory area, that can actually be used
     * as stack by the partitions starts at a lower address
     */
    partition_psp =
        (uint32_t)&REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit)-
        sizeof(struct iovec_args_t);
    partition_psplim =
        (uint32_t)&REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Base);
#else
    partition_psp = curr_part_data->stack_ptr;
    partition_psplim = tfm_spm_partition_get_stack_bottom(partition_idx);
#endif
    /* Store the context for the partition call */
    tfm_spm_partition_set_caller_partition_idx(partition_idx,
                                               caller_partition_idx);
    tfm_spm_partition_store_context(caller_partition_idx, psp, excReturn);

    if ((caller_flags & SPM_PART_FLAG_APP_ROT)) {
        tfm_spm_partition_set_caller_client_id(partition_idx,
                                               caller_partition_id);
    } else {
        client_id = tfm_nspm_get_current_client_id();
        if (client_id >= 0)
        {
            return TFM_SECURE_LOCK_FAILED;
        }
        tfm_spm_partition_set_caller_client_id(partition_idx, client_id);
    }

#if (TFM_LVL != 1) && (TFM_LVL != 2)
    /* Dynamic partitioning is only done is TFM level 3 */
    tfm_spm_partition_sandbox_deconfig(caller_partition_idx);

    /* Configure partition execution environment */
    if (tfm_spm_partition_sandbox_config(partition_idx) != SPM_ERR_OK) {
        ERROR_MSG("Failed to configure sandbox for partition!");
        tfm_secure_api_error_handler();
    }
#endif

    /* Default share to scratch area in case of partition to partition calls
     * this way partitions always get default access to input buffers
     */
    /* FixMe: return value/error handling TBD */
    tfm_spm_partition_set_share(partition_idx, desc_ptr->ns_caller ?
        TFM_BUFFER_SHARE_NS_CODE : TFM_BUFFER_SHARE_SCRATCH);

#if TFM_LVL == 1
    /* In level one, only switch context and return from exception if in
     * handler mode
     */
    if ((desc_ptr->ns_caller) || (tfm_secure_api_initializing)) {
        if (desc_ptr->iovec_api == TFM_SFN_API_IOVEC) {
            /* Save the iovecs on the common stack. The vectors had been sanity
             * checked already, and since then the interrupts have been kept
             * disabled. So we can be sure that the vectors haven't been
             * tampered with since the check.
             */
            iovec_args = (struct iovec_args_t *)
                    ((uint32_t)&REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit)-
                     sizeof(struct iovec_args_t));
            if (tfm_spm_partition_set_iovec(partition_idx, desc_ptr->args) !=
                SPM_ERR_OK) {
                return TFM_ERROR_GENERIC;
            }
            tfm_copy_iovec_parameters(iovec_args,
                                      &(curr_part_data->iovec_args));

            /* Prepare the partition context, update stack ptr */
            psp = (uint32_t)prepare_partition_iovec_ctx(svc_ctx, desc_ptr,
                                                        iovec_args,
                                                     (uint32_t *)partition_psp);
        } else {
            /* Prepare the partition context, update stack ptr */
            psp = (uint32_t)prepare_partition_ctx(svc_ctx, desc_ptr,
                                                  (uint32_t *)partition_psp);
        }
        __set_PSP(psp);
        __set_PSPLIM(partition_psplim);
    }
#else
    if (desc_ptr->iovec_api == TFM_SFN_API_IOVEC) {
        /* Save the iovecs on the stack of the partition. The vectors had been
         * sanity checked already, and since then the interrupts have been kept
         * disabled. So we can be sure that the vectors haven't been tampered
         * with since the check.
         */
        iovec_args =
        (struct iovec_args_t *)(tfm_spm_partition_get_stack_top(partition_idx) -
        sizeof(struct iovec_args_t));
        if (tfm_spm_partition_set_iovec(partition_idx, desc_ptr->args) !=
            SPM_ERR_OK) {
            return TFM_ERROR_GENERIC;
        }
        tfm_copy_iovec_parameters(iovec_args, &(curr_part_data->iovec_args));

        /* Prepare the partition context, update stack ptr */
        psp = (uint32_t)prepare_partition_iovec_ctx(svc_ctx, desc_ptr,
                                                    iovec_args,
                                                    (uint32_t *)partition_psp);
    } else {
        /* Prepare the partition context, update stack ptr */
        psp = (uint32_t)prepare_partition_ctx(svc_ctx, desc_ptr,
                                              (uint32_t *)partition_psp);
    }
    __set_PSP(psp);
    __set_PSPLIM(partition_psplim);
#endif

    tfm_spm_partition_set_state(caller_partition_idx,
                                SPM_PARTITION_STATE_BLOCKED);
    tfm_spm_partition_set_state(partition_idx, SPM_PARTITION_STATE_RUNNING);
    tfm_secure_lock++;

    return TFM_SUCCESS;
}