Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/trusty/trusty/kernel/app/userscstest/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 8 kB image not shown  

Quelle  userscstest.c

  Sprache: C
 

/*
 * Copyright (c) 2021, Google Inc. All rights reserved
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files
 * (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */


#include <err.h>
#include <kernel/thread.h>
#include <kernel/vm.h>
#include <lib/mmutest/mmutest.h>
#include <lib/trusty/trusty_app.h>
#include <lib/unittest/unittest.h>

#if USER_SCS_ENABLED
#define FEATURE_GATED_TEST_NAME(name) name

/**
 * translate_uspace_ptr() - Translate userspace pointer to shadow stack
 * @uspace:         An address space of a trust app
 * @uspace_ptr:     Pointer into above user space.
 * @kspace_ptr_out: Pointer translated into the kernel's address space. The
 *                  value of this output parameter should not be consumed
 *                  if this function returned a negative error code.
 *
 * Attempt to translate userspace pointer into its kernel equivalent. We
 * cannot simply dereference a userspace pointer because the TLB isn't
 * loaded with the correct page table. Instead, we translate the pointer
 * to physical memory and then into the kernel virtual address space.
 * Translation can fail the userspace address is not backed by physical
 * memory; this is the case for guard pages.
 *
 * Return:
 * * NO_ERROR         - if translation succeeded
 * * ERR_OUT_OF_RANGE - if address translation failed
 * * ERR_NOT_FOUND    - if pointer is not backed by physical memory
 * * ERR_INVALID_ARGS - if kspace_ptr_out is NULL
 */

static int translate_uspace_ptr(struct vmm_aspace* uspace,
                                vaddr_t uspace_ptr,
                                vaddr_t* kspace_ptr_out) {
    paddr_t phys_ptr;
    uint flags;

    if (kspace_ptr_out == NULL) {
        return ERR_INVALID_ARGS;
    }
    *kspace_ptr_out = 0;

    /* translate userspace virtual address to physical address */
    status_t res =
            arch_mmu_query(&uspace->arch_aspace, uspace_ptr, &phys_ptr, &flags);
    /*
     * failures can happen if the pointer is invalid or points to a guard page
     * not backed by physical memory (in which case res is ERR_NOT_FOUND).
     */

    if (res) {
        return res;
    }

    EXPECT_EQ(flags, ARCH_MMU_FLAG_PERM_NO_EXECUTE | ARCH_MMU_FLAG_PERM_USER,
              "Shadow call stack must point to non-executable user memory");

    /* translate physical address to kernel virtual address */
    *kspace_ptr_out = (vaddr_t)paddr_to_kvaddr(phys_ptr);
    ASSERT_NE(0, *kspace_ptr_out,
              "Failed to map phys addr to kernel virtual addr");

    return NO_ERROR;
test_abort:
    return ERR_OUT_OF_RANGE;
}

struct scs_test_status {
    uint32_t running_apps;
    uint32_t invalid_apps;
};

/**
 * trusty_app_callback() - Test that app has a valid user shadow call stack
 *
 * @ta: Application to test
 * @status: Pointer to a structure tracking the current test status.
 */

static void trusty_app_callback(struct trusty_app* ta, void* status) {
    struct scs_test_status* status_ptr = (struct scs_test_status*)status;
    if (strcmp(ta->props.app_name, "userscs-custom") == 0) {
        /* were we able to request a custom shadow stack size? */
        ASSERT_EQ(ta->props.min_shadow_stack_size, 128);
    } else if (strcmp(ta->props.app_name, "userscs-disabled") == 0) {
        /* were we able to opt out of shadow stacks? */
        ASSERT_EQ(ta->props.min_shadow_stack_size, 0);
        /* userscs-* apps loop infinitely so they'll always have a thread */
        ASSERT_NE((void*)ta->thread, NULL, "App has thread");
        ASSERT_EQ((void*)ta->thread->shadow_stack_base, NULL,
                  "Shadow call stack was disabled");
        return;
    } else if (strcmp(ta->props.app_name, "userscs-default") == 0) {
        /* did default scs app get the default shadow stack size? */
        ASSERT_EQ(ta->props.min_shadow_stack_size, DEFAULT_SHADOW_STACK_SIZE,
                  "Expected shadow call stack to have the default size");
    }

    /* size must be a multiple of the pointer size */
    ASSERT_EQ(0, ta->props.min_shadow_stack_size % sizeof(vaddr_t),
              "Shadow call stack size is not a multiple of the pointer size");

    /*
     * Apps that aren't running may not have a thread allocated. Moreover,
     * apps that opt out of shadow call stacks need no further inspection.
     */

    if (ta->state != APP_RUNNING || ta->props.min_shadow_stack_size == 0) {
        return;
    }
    status_ptr->running_apps++;

    struct trusty_thread* tt = ta->thread;
    ASSERT_NE((void*)tt, NULL, "Running trusty app must have a valid thread");
    ASSERT_NE((void*)tt->shadow_stack_base, NULL,
              "Shadow call stack must point to allocation");

    ASSERT_EQ(false, is_kernel_address(tt->shadow_stack_base),
              "Shadow stack on user thread points to kernel memory");

    ASSERT_NE(tt->stack_start, tt->shadow_stack_base,
              "Shadow stack on user thread aliases the regular stack");

    /*
     * Check the shadow stack size by examining the last element and one past
     * the last element. Note that these pointers are valid in the address
     * space of the trusty app, not in the current address space of a kernel
     * app. Therefore, we translate from the app's address space to the kernel
     * addres space before dereferencing lest we generate an access violation.
     */


    vaddr_t past_last = (vaddr_t)tt->shadow_stack_base + tt->shadow_stack_size;
    vaddr_t last_elem = past_last - sizeof(vaddr_t);
    /* a whole number of pages is allocated no matter the shadow stack size */
    vaddr_t pre_first = last_elem - round_up(tt->shadow_stack_size, PAGE_SIZE);
    vaddr_t elem_translated, ignored;

    struct vmm_aspace* uspace = ta->aspace;

    ASSERT_EQ(NO_ERROR,
              translate_uspace_ptr(uspace, last_elem, &elem_translated),
              "Actual size of shadow stack differs from recorded size");
    /*
     * Check that test app uses its shadow stack as expected. The shadow call
     * stack is zero-initialized and once a stack slot is used it can never
     * become zero again.
     */

    if (strcmp(ta->props.app_name, "userscs-default") == 0) {
        EXPECT_EQ(0, *(vaddr_t*)elem_translated,
                  "Expected last element of shadow stack to be zero "
                  "(unused)");

        ASSERT_EQ(NO_ERROR, translate_uspace_ptr(uspace, tt->shadow_stack_base,
                                                 &elem_translated));
        /*
         * The link register is initially zero so when shadow call stacks are
         * enabled for libc, the second element holds the first non-zero entry
         */

        EXPECT_NE(0, *(vaddr_t*)elem_translated + sizeof(vaddr_t),
                  "Expected second element of shadow stack to be non-zero "
                  "(used)");
    }

    ASSERT_EQ(ERR_NOT_FOUND, translate_uspace_ptr(uspace, past_last, &ignored),
              "Expected guard page after shadow stack on user thread");

    ASSERT_EQ(ERR_NOT_FOUND, translate_uspace_ptr(uspace, pre_first, &ignored),
              "Expected guard page before shadow stack on user thread");

    return;
test_abort:
    status_ptr->invalid_apps++;
}

static int inspect_trusty_threads(void) {
    struct scs_test_status status = {0};
    trusty_app_forall(trusty_app_callback, &status);
    ASSERT_NE(0, status.running_apps);
    return status.invalid_apps;
test_abort:
    return -1;
}
#else
#define FEATURE_GATED_TEST_NAME(name) DISABLED_##name

static int inspect_trusty_threads(void) {
    return 0;
}

#endif

TEST(userscstest, FEATURE_GATED_TEST_NAME(user_threads_have_scs)) {
    int res = inspect_trusty_threads();
    EXPECT_NE(-1, res, "There were no running apps with threads to inspect");
    EXPECT_EQ(0, res,
              "One or more apps did not have the expected shadow call stack");
}

PORT_TEST(userscstest, "com.android.kernel.userscstest");

Messung V0.5 in Prozent
C=70 H=83 G=76

¤ Dauer der Verarbeitung: 0.11 Sekunden  (vorverarbeitet am  2026-06-27) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.