Esempio n. 1
0
/* Return true iff gateway is valid. */
static int is_valid_rpc_gateway(const TRPCGateway * const gateway)
{
    /* Gateway needs to be entirely in flash. */
    uint32_t gateway_start = (uint32_t) gateway;
    uint32_t gateway_end = gateway_start + sizeof(*gateway);
    if (!(vmpu_public_flash_addr(gateway_start) && vmpu_public_flash_addr(gateway_end))) {
        return 0;
    }

    /* Gateway needs to have good magic. */
    if (!(gateway->magic == UVISOR_RPC_GATEWAY_MAGIC_ASYNC || gateway->magic == UVISOR_RPC_GATEWAY_MAGIC_SYNC)) {
        return 0;
    }

    /* Gateway needs good ldr_pc instruction. */
    if (gateway->ldr_pc != LDR_PC_PC_IMM_OPCODE(__UVISOR_OFFSETOF(TRPCGateway, ldr_pc),
                                                __UVISOR_OFFSETOF(TRPCGateway, caller))) {
        return 0;
    }

    /* The callee box ID associated with the gateway must be valid. */
    int box_id = callee_box_id(gateway);
    if (box_id < 0) {
        return 0;
    }

    /* Gateway needs to point to functions in flash (caller and target) */
    if (!(vmpu_public_flash_addr(gateway->caller) && vmpu_public_flash_addr(gateway->target))) {
        return 0;
    }

    /* All checks passed. */
    return 1;
}
Esempio n. 2
0
/** Perform the validation of a register gateway.
 * @internal
 * @warning This function does not verify that the operation, value and mask
 * make sense together. The code that performs the operation should check for
 * this and return an error accordingly.
 * @param register_gateway[in]  Pointer to the register gateway structure in
 *                              flash.
 * @returns the status of the check. A negative number indicates an error.
 */
static int register_gateway_check(TRegisterGateway const * const register_gateway)
{
    /* Verify that the register gateway is in public flash. */
    /* Note: We only check that the start and end addresses of the gateway are
     * in public flash. Since the gateway is fairly small, we can safely assume
     * that all of it is in public flash. */
    if (!vmpu_public_flash_addr((uint32_t) register_gateway) ||
        !vmpu_public_flash_addr((uint32_t) ((void *) register_gateway + sizeof(TRegisterGateway) - 1))) {
        DPRINTF("Register gateway 0x%08X is not in public flash.\n", (uint32_t) register_gateway);
        return REGISTER_GATEWAY_STATUS_ERROR_FLASH;
    }

    /* Verify that the register gateway magic is present. */
    if (register_gateway->magic != UVISOR_REGISTER_GATEWAY_MAGIC) {
        DPRINTF("Register gateway 0x%08X does not contain a valid magic (0x%08X).\n",
                (uint32_t) register_gateway, register_gateway->magic);
        return REGISTER_GATEWAY_STATUS_ERROR_MAGIC;
    }

    /* Verify that the box configuration pointer is in the dedicated flash
     * region. */
    /* Note: We only check that the box pointer is larger than the start of the
     * pointer region. The subsequent substraction that we do to calculate the
     * box ID is then guaranteed to be sane. */
    if (register_gateway->box_ptr < (uint32_t) __uvisor_config.cfgtbl_ptr_start) {
        DPRINTF("The pointer (0x%08X) in the register gateway 0x%08X is not a valid box configuration pointer.\n",
                register_gateway->box_ptr, (uint32_t) register_gateway);
        return REGISTER_GATEWAY_STATUS_ERROR_BOX_PTR;
    }

    /* Verify that the gateway is being performed by the currently active box.
     * The check does not apply if the gateway has been explicitly marked as
     * shared. */
    uint8_t box_id = (uint8_t) ((uint32_t *) register_gateway->box_ptr - __uvisor_config.cfgtbl_ptr_start);
    if (!(register_gateway->operation & __UVISOR_RGW_OP_SHARED_MASK) && (box_id != g_active_box)) {
        DPRINTF("Register gateway is owned by box %d, while the active box is %d.\n", box_id, g_active_box);
        return REGISTER_GATEWAY_STATUS_ERROR_BOX_ID;
    }

    /* Verify that the address is in one of the allowed memory sections:
     *   0x40000000 - 0x43FFFFFF: Peripheral + Peripheral alias
     *   0xE00FF000 - 0xE00FFFFF: Custom ROM Table */
    uint32_t address = register_gateway->address;
    if (((address & VMPU_PERIPH_FULL_MASK) != VMPU_PERIPH_START) &&
        ((address & VMPU_ROMTABLE_MASK) != VMPU_ROMTABLE_START)) {
        DPRINTF("Register gateways can only target the peripheral or ROM Table memory regions. "
                "Address 0x%08X not allowed.\n", address);
        return REGISTER_GATEWAY_STATUS_ERROR_ADDRESS;
    }

    /* If the code got here, then everything is fine. */
    return REGISTER_GATEWAY_STATUS_OK;
}
Esempio n. 3
0
File: vmpu.c Progetto: kedars/uvisor
static void vmpu_sanity_check_box_namespace(int box_id, const char *const box_namespace)
{
    /* Verify that all characters of the box_namespace (including the trailing
     * NUL) are within flash and that the box_namespace is not too long. It is
     * also okay for the box namespace to be NULL. */
    size_t length = 0;

    if (box_namespace == NULL) {
        return;
    }

    do {
        /* Check that the address of the character is within public flash before
         * reading the character. */
        /* Note: The public flash section is assumed to be monolithic, so if
         * both the start and end address of an array are inside the public
         * flash, then the whole array is inside the public flash. */
        if (!vmpu_public_flash_addr((uint32_t) &box_namespace[0]) ||
            !vmpu_public_flash_addr((uint32_t) &box_namespace[length])) {
            HALT_ERROR(SANITY_CHECK_FAILED, "box[%i] @0x%08X - namespace not entirely in public flash\n",
                box_id, box_namespace, UVISOR_MAX_BOX_NAMESPACE_LENGTH);
        }

        if (box_namespace[length] == '\0') {
            /* If we reached the end of the string, which we now know is stored
             * in flash, then we are done. */
            break;
        }

        ++length;

        if (length >= UVISOR_MAX_BOX_NAMESPACE_LENGTH) {
            HALT_ERROR(SANITY_CHECK_FAILED,
                "box[%i] @0x%08X - namespace too long (length >= %u)\n",
                box_id, box_namespace, UVISOR_MAX_BOX_NAMESPACE_LENGTH);
        }
    } while (box_namespace[length]);
}
Esempio n. 4
0
File: vmpu.c Progetto: kedars/uvisor
static int vmpu_sanity_checks(void)
{
    /* Verify the uVisor configuration structure. */
    if (__uvisor_config.magic != UVISOR_MAGIC) {
        HALT_ERROR(SANITY_CHECK_FAILED,
            "config magic mismatch: &0x%08X = 0x%08X - exptected 0x%08X\n",
            &__uvisor_config, __uvisor_config.magic, UVISOR_MAGIC);
    }

    /* Verify basic assumptions about vmpu_bits/__builtin_clz. */
    assert(__builtin_clz(0) == 32);
    assert(__builtin_clz(1UL << 31) == 0);
    assert(vmpu_bits(0) == 0);
    assert(vmpu_bits(1UL << 31) == 32);
    assert(vmpu_bits(0x8000UL) == 16);
    assert(vmpu_bits(0x8001UL) == 16);
    assert(vmpu_bits(1) == 1);

    /* Verify that the core version is the same as expected. */
    if (!CORE_VERSION_CHECK() || !CORE_REVISION_CHECK()) {
        HALT_ERROR(SANITY_CHECK_FAILED, "This core is unsupported or there is a mismatch between the uVisor "
                                        "configuration you are using and the core this configuration supports.\n\r");
    }

    /* Verify that the known hard-coded symbols are equal to the ones taken from
     * the host linker script. */
    assert((uint32_t) __uvisor_config.flash_start == FLASH_ORIGIN);
    assert((uint32_t) __uvisor_config.sram_start == SRAM_ORIGIN);

    /* Verify that the uVisor binary blob is positioned at the flash offset. */
    assert(((uint32_t) __uvisor_config.flash_start + FLASH_OFFSET) == (uint32_t) __uvisor_config.main_start);

    /* Verify that the uVisor mode configuration is inside the public flash. */
    assert(vmpu_public_flash_addr((uint32_t) __uvisor_config.mode));
    assert(*(__uvisor_config.mode) <= 2);
    DPRINTF("uVisor mode: %u\n", *(__uvisor_config.mode));

    /* Verify the SRAM relocation. */
    /* Note: SRAM_ORIGIN + SRAM_OFFSET is assumed to be aligned to 32 bytes. */
    assert((uint32_t) __uvisor_config.bss_start == (SRAM_ORIGIN + SRAM_OFFSET));

    DPRINTF("uvisor_ram : @0x%08X (%u bytes) [config]\n",
        __uvisor_config.bss_main_start,
        VMPU_REGION_SIZE(__uvisor_config.bss_main_start, __uvisor_config.bss_main_end));
    DPRINTF("             @0x%08X (%u bytes) [linker]\n",
        SRAM_ORIGIN + SRAM_OFFSET,
        UVISOR_SRAM_LENGTH_USED);

    /* Verify that the sections inside the BSS region are disjoint. */
    DPRINTF("bss_boxes  : @0x%08X (%u bytes) [config]\n",
        __uvisor_config.bss_boxes_start,
        VMPU_REGION_SIZE(__uvisor_config.bss_boxes_start, __uvisor_config.bss_boxes_end));
    assert(__uvisor_config.bss_end > __uvisor_config.bss_start);
    assert(__uvisor_config.bss_main_end > __uvisor_config.bss_main_start);
    assert(__uvisor_config.bss_boxes_end > __uvisor_config.bss_boxes_start);
    assert((__uvisor_config.bss_main_start >= __uvisor_config.bss_boxes_end) ||
           (__uvisor_config.bss_main_end <= __uvisor_config.bss_boxes_start));

    /* Verify the uVisor expectations regarding its own memories. */
    assert(VMPU_REGION_SIZE(__uvisor_config.bss_main_start, __uvisor_config.bss_main_end) == UVISOR_SRAM_LENGTH_USED);
    assert((uint32_t) __uvisor_config.bss_main_end == (SRAM_ORIGIN + SRAM_OFFSET + UVISOR_SRAM_LENGTH_USED));
    assert((uint32_t) __uvisor_config.bss_main_end == (SRAM_ORIGIN + UVISOR_SRAM_LENGTH_PROTECTED));

    /* Verify SRAM sections are within uVisor's own SRAM. */
    assert(&__bss_start__ >= __uvisor_config.bss_main_start);
    assert(&__bss_end__ <= __uvisor_config.bss_main_end);
    assert(&__data_start__ >= __uvisor_config.bss_main_start);
    assert(&__data_end__ <= __uvisor_config.bss_main_end);
    assert(&__stack_start__ >= __uvisor_config.bss_main_start);
    assert(&__stack_end__ <= __uvisor_config.bss_main_end);

    /* Verify that the secure flash area is accessible and after public code. */
    assert(!vmpu_public_flash_addr((uint32_t) __uvisor_config.secure_start));
    assert(!vmpu_public_flash_addr((uint32_t) __uvisor_config.secure_end));
    assert(vmpu_flash_addr((uint32_t) __uvisor_config.secure_start));
    assert(vmpu_flash_addr((uint32_t) __uvisor_config.secure_end));
    assert(__uvisor_config.secure_start <= __uvisor_config.secure_end);
    assert(__uvisor_config.secure_start >= __uvisor_config.main_end);

    /* Verify the configuration table. */
    assert(__uvisor_config.cfgtbl_ptr_start <= __uvisor_config.cfgtbl_ptr_end);
    assert(__uvisor_config.cfgtbl_ptr_start >= __uvisor_config.secure_start);
    assert(__uvisor_config.cfgtbl_ptr_end <= __uvisor_config.secure_end);
    assert(!vmpu_public_flash_addr((uint32_t) __uvisor_config.cfgtbl_ptr_start));
    assert(!vmpu_public_flash_addr((uint32_t) __uvisor_config.cfgtbl_ptr_end));
    assert(vmpu_flash_addr((uint32_t) __uvisor_config.cfgtbl_ptr_start));
    assert(vmpu_flash_addr((uint32_t) __uvisor_config.cfgtbl_ptr_end));

    /* Verify the register gateway pointers section. */
    assert(__uvisor_config.register_gateway_ptr_start <= __uvisor_config.register_gateway_ptr_end);
    assert(__uvisor_config.register_gateway_ptr_start >= __uvisor_config.secure_start);
    assert(__uvisor_config.register_gateway_ptr_end <= __uvisor_config.secure_end);
    assert(!vmpu_public_flash_addr((uint32_t) __uvisor_config.register_gateway_ptr_start));
    assert(!vmpu_public_flash_addr((uint32_t) __uvisor_config.register_gateway_ptr_end));
    assert(vmpu_flash_addr((uint32_t) __uvisor_config.register_gateway_ptr_start));
    assert(vmpu_flash_addr((uint32_t) __uvisor_config.register_gateway_ptr_end));

    /* Verify that every register gateway in memory is aligned to 4 bytes. */
    uint32_t * register_gateway = __uvisor_config.register_gateway_ptr_start;
    for (; register_gateway < __uvisor_config.register_gateway_ptr_end; register_gateway++) {
        if (*register_gateway & 0x3) {
            HALT_ERROR(SANITY_CHECK_FAILED, "Register gateway 0x%08X is not aligned to 4 bytes",
                (uint32_t) register_gateway);
        }
    }

    /* Return an error if uVisor is disabled. */
    if (!__uvisor_config.mode || (*__uvisor_config.mode == 0)) {
        return -1;
    } else {
        return 0;
    }
}
Esempio n. 5
0
File: vmpu.c Progetto: kedars/uvisor
int vmpu_fault_recovery_bus(uint32_t pc, uint32_t sp, uint32_t fault_addr, uint32_t fault_status)
{
    uint16_t opcode;
    uint32_t r0, r1;
    uint32_t cnt_max, cnt;
    int found;

    /* Check for attacks. */
    if (!vmpu_public_flash_addr(pc)) {
       HALT_ERROR(NOT_ALLOWED, "This is not the PC (0x%08X) your were searching for", pc);
    }

    /* Check fault register; the following two configurations are allowed:
     *   0x04 - imprecise data bus fault, no stacking/unstacking errors.
     *   0x82 - precise data bus fault, no stacking/unstacking errors. */
    /* Note: Currently the faulting address argument is not used, since it
     * is saved in r0 for managed bus faults. */
    switch (fault_status) {
        case 0x82:
            cnt_max = 0;
            break;
        case 0x04:
            cnt_max = UVISOR_NOP_CNT;
            break;
        default:
            return -1;
    }

    /* Parse the instruction opcode. */
    cnt = 0;
    do {
        /* Fetch the opcode from memory. */
        opcode = vmpu_unpriv_uint16_read(pc - (cnt << 1));

        /* Test the lower 8 bits for imm5 = 0, Rn = 0, Rt = 1. */
        found = TRUE;
        switch(opcode & 0xFF) {
            /* If using r0 and r1, we expect a strX instruction. */
            case VMPU_OPCODE16_LOWER_R0_R1_MASK:
                /* Fetch r0 and r1. */
                r0 = vmpu_unpriv_uint32_read(sp);
                r1 = vmpu_unpriv_uint32_read(sp+4);

                /* Check if there is an ACL mapping this access. */
                if ((vmpu_fault_find_acl(r0, sizeof(uint32_t)) & UVISOR_TACL_UWRITE) == 0) {
                    return -1;
                };

                /* Test the upper 8 bits for the desired opcode and imm5 = 0. */
                switch (opcode >> 8) {
                    case VMPU_OPCODE16_UPPER_STR_MASK:
                        *((uint32_t *) r0) = (uint32_t) r1;
                        break;
                    case VMPU_OPCODE16_UPPER_STRH_MASK:
                        *((uint16_t *) r0) = (uint16_t) r1;
                        break;
                    case VMPU_OPCODE16_UPPER_STRB_MASK:
                        *((uint8_t *) r0) = (uint8_t) r1;
                        break;
                    default:
                        found = FALSE;
                        break;
                }
                if (found) {
                    /* DPRINTF("Executed privileged access: 0x%08X written to 0x%08X\n\r", r1, r0); */
                }
                break;

            /* If using r0 only, we expect a ldrX instruction. */
            case VMPU_OPCODE16_LOWER_R0_R0_MASK:
                /* Fetch r0. */
                r0 = vmpu_unpriv_uint32_read(sp);

                /* Check if there is an ACL mapping this access. */
                if ((vmpu_fault_find_acl(r0, sizeof(uint32_t)) & UVISOR_TACL_UREAD) == 0) {
                    return -1;
                };

                /* Test the upper 8 bits for the desired opcode and imm5 = 0. */
                switch (opcode >> 8) {
                    case VMPU_OPCODE16_UPPER_LDR_MASK:
                        r1 = (uint32_t) *((uint32_t *) r0);
                        break;
                    case VMPU_OPCODE16_UPPER_LDRH_MASK:
                        r1 = (uint16_t) *((uint16_t *) r0);
                        break;
                    case VMPU_OPCODE16_UPPER_LDRB_MASK:
                        r1 = (uint8_t) *((uint8_t *) r0);
                        break;
                    default:
                        found = FALSE;
                        break;
                }
                if (found) {
                    /* The result is stored back to the stack (r0). */
                    vmpu_unpriv_uint32_write(sp, r1);
                    /* DPRINTF("Executed privileged access: read 0x%08X from 0x%08X\n\r", r1, r0); */
                }
                break;

            default:
                found = FALSE;
                break;
        }

        /* Parse the next opcode. */
        cnt++;
    } while (!found && cnt < cnt_max);

    /* Return an error if the opcode was not found. */
    if (!found) {
        return -1;
    }

    /* Otherwise execution continues from the instruction following the fault. */
    /* Note: We assume the instruction is 16 bits wide and skip possible NOPs. */
    vmpu_unpriv_uint32_write(sp + (6 << 2), pc + ((UVISOR_NOP_CNT + 2 - cnt) << 1));

    /* Success. */
    return 0;
}
Esempio n. 6
0
File: vmpu.c Progetto: kedars/uvisor
static void vmpu_load_boxes(void)
{
    int i, count;
    const UvisorBoxAclItem *region;
    const UvisorBoxConfig **box_cfgtbl;
    uint8_t box_id;

    /* Check heap start and end addresses. */
    if (!__uvisor_config.heap_start || !vmpu_sram_addr((uint32_t) __uvisor_config.heap_start)) {
        HALT_ERROR(SANITY_CHECK_FAILED, "Heap start pointer (0x%08x) is not in SRAM memory.\n",
            (uint32_t) __uvisor_config.heap_start);
    }
    if (!__uvisor_config.heap_end || !vmpu_sram_addr((uint32_t) __uvisor_config.heap_end)) {
        HALT_ERROR(SANITY_CHECK_FAILED, "Heap end pointer (0x%08x) is not in SRAM memory.\n",
            (uint32_t) __uvisor_config.heap_end);
    }
    if (__uvisor_config.heap_end < __uvisor_config.heap_start) {
        HALT_ERROR(SANITY_CHECK_FAILED, "Heap end pointer (0x%08x) is smaller than heap start pointer (0x%08x).\n",
            (uint32_t) __uvisor_config.heap_end, (uint32_t) __uvisor_config.heap_start);
    }

    /* Enumerate boxes. */
    g_vmpu_box_count = (uint32_t) (__uvisor_config.cfgtbl_ptr_end - __uvisor_config.cfgtbl_ptr_start);
    if (g_vmpu_box_count >= UVISOR_MAX_BOXES) {
        HALT_ERROR(SANITY_CHECK_FAILED, "box number overflow\n");
    }
    g_vmpu_boxes_counted = TRUE;

    /* Initialize boxes. */
    box_id = 0;
    for (box_cfgtbl = (const UvisorBoxConfig * *) __uvisor_config.cfgtbl_ptr_start;
         box_cfgtbl < (const UvisorBoxConfig * *) __uvisor_config.cfgtbl_ptr_end;
         box_cfgtbl++) {
        /* Ensure that the configuration table resides in flash. */
        if (!(vmpu_flash_addr((uint32_t) *box_cfgtbl) &&
            vmpu_flash_addr((uint32_t) ((uint8_t *) (*box_cfgtbl)) + (sizeof(**box_cfgtbl) - 1)))) {
            HALT_ERROR(SANITY_CHECK_FAILED, "invalid address - *box_cfgtbl must point to flash (0x%08X)\n",
                *box_cfgtbl);
        }

        /* Check the magic value in the box configuration table. */
        if (((*box_cfgtbl)->magic) != UVISOR_BOX_MAGIC) {
            HALT_ERROR(SANITY_CHECK_FAILED, "box[%i] @0x%08X - invalid magic\n",
                box_id, (uint32_t)(*box_cfgtbl));
        }

        /* Check the box configuration table version. */
        if (((*box_cfgtbl)->version) != UVISOR_BOX_VERSION) {
            HALT_ERROR(SANITY_CHECK_FAILED, "box[%i] @0x%08X - invalid version (0x%04X!-0x%04X)\n",
                box_id, *box_cfgtbl, (*box_cfgtbl)->version, UVISOR_BOX_VERSION);
        }

        /* Confirm the minimal size of the box index size. */
        if ((*box_cfgtbl)->index_size < sizeof(UvisorBoxIndex)) {
            HALT_ERROR(SANITY_CHECK_FAILED, "Box index size (%uB) must be large enough to hold UvisorBoxIndex (%uB).\n",
                (*box_cfgtbl)->index_size, sizeof(UvisorBoxIndex));
        }

        /* Check that the box namespace is not too long. */
        vmpu_sanity_check_box_namespace(box_id, (*box_cfgtbl)->box_namespace);

        /* Load the box ACLs. */
        DPRINTF("box[%i] ACL list:\n", box_id);

        /* Add ACL's for all box stacks. */
        vmpu_acl_stack(
            box_id,
            (*box_cfgtbl)->index_size + (*box_cfgtbl)->context_size + (*box_cfgtbl)->heap_size,
            (*box_cfgtbl)->stack_size
        );

        /* Initialize box index. */
        vmpu_box_index_init(
            box_id,
            *box_cfgtbl
        );

        /* Enumerate the box ACLs. */
        region = (*box_cfgtbl)->acl_list;
        if (region != NULL) {
            count = (*box_cfgtbl)->acl_count;
            for (i = 0; i < count; i++) {
                /* Ensure that the ACL resides in public flash. */
                if (!vmpu_public_flash_addr((uint32_t) region)) {
                    HALT_ERROR(SANITY_CHECK_FAILED, "box[%i]:acl[%i] must be in code section (@0x%08X)\n",
                        box_id, i, *box_cfgtbl);
                }

                /* Add the ACL and force the entry as user-provided. */
                if (region->acl & UVISOR_TACL_IRQ) {
                    vmpu_acl_irq(box_id, region->param1, region->param2);
                } else {
                    vmpu_acl_add(
                        box_id,
                        region->param1,
                        region->param2,
                        region->acl | UVISOR_TACL_USER
                    );
                }

                /* Proceed to the next ACL. */
                region++;
            }
        }

        /* Proceed to the next box. */
        box_id++;
    }

    /* Load box 0. */
    vmpu_load_box(0);
    *(__uvisor_config.uvisor_box_context) = (uint32_t *) g_context_current_states[0].bss;

    DPRINTF("vmpu_load_boxes [DONE]\n");
}