Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  usercopytest.c

  Sprache: C
 

/*
 * Copyright (c) 2015, 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 <assert.h>
#include <err.h>
#include <kernel/usercopy.h>
#include <lib/unittest/unittest.h>
#include <lk/init.h>
#include <stdio.h>
#include <string.h>
#include <trusty/string.h>
#ifdef ARCH_ARM64
#include <arch/safecopy.h>
#endif

#define PORT_NAME "com.android.kernel.usercopy-unittest"

#define TEST_BUF_SIZE (16)
#define TEST_BUF1_SIZE (TEST_BUF_SIZE / 2)
#define TEST_BUF2_SIZE (TEST_BUF_SIZE - TEST_BUF1_SIZE)
#define TEST_BUF_COPY_START (1)
#define TEST_BUF_COPY_SIZE (TEST_BUF_SIZE - TEST_BUF_COPY_START - 1)
#define TEST_BUF1_COPY_SIZE (TEST_BUF1_SIZE - TEST_BUF_COPY_START)
#define TEST_BUF2_COPY_SIZE (TEST_BUF_COPY_SIZE - TEST_BUF1_COPY_SIZE)
#define TEST_BUF_COPY_LAST (TEST_BUF_SIZE - 1 - 1)
#define TEST_BUF2_COPY_LAST (TEST_BUF_COPY_LAST - TEST_BUF1_SIZE)

#define SRC_DATA (0x22)
#define DEST_DATA (0x11)

#define FLAGS_NO_PAGE (ARCH_MMU_FLAG_INVALID)
#define FLAGS_NO_USER (0u)
#define FLAGS_RO_USER (ARCH_MMU_FLAG_PERM_USER | ARCH_MMU_FLAG_PERM_RO)
#define FLAGS_RW_USER (ARCH_MMU_FLAG_PERM_USER)

#define STACK_ADDR_IDX (0)
#define HEAP_ADDR_IDX (1)
#define GLOBAL_ADDR_IDX (2)

#define START_PAGE_ADDR ((void*)(PAGE_SIZE * 0x10))
#define TEST_BUF_ADDR \
    ((user_addr_t)((uintptr_t)(START_PAGE_ADDR + PAGE_SIZE - TEST_BUF1_SIZE)))

static inline user_addr_t get_addr_param(void) {
    const voidconst* param_arr = GetParam();
    const user_addr_t* addr = param_arr[0];
    return *addr;
}

static inline uint32_t get_start_flags_param(void) {
    const voidconst* param_arr = GetParam();
    const uint32_t* start_flags = param_arr[1];
    return *start_flags;
}

static inline uint32_t get_end_flags_param(void) {
    const voidconst* param_arr = GetParam();
    const uint32_t* end_flags = param_arr[2];
    return *end_flags;
}

static int checkbuf(const char* buf, char c, size_t size) {
    int error_count = 0;
    for (size_t i = 0; i < size; i++) {
        if (buf[i] != c) {
            error_count++;
        }
    }
    return error_count;
}

static void usercopy_test_init_buf(char* kbuf1,
                                   char* kbuf2,
                                   uint8_t val,
                                   int null_offset) {
    if (kbuf1) {
        memset(kbuf1, val, TEST_BUF1_SIZE);
        if (null_offset >= 0 && null_offset < TEST_BUF1_SIZE) {
            kbuf1[null_offset] = '\0';
        }
    }
    if (kbuf2) {
        memset(kbuf2, val, TEST_BUF2_SIZE);
        if (null_offset >= TEST_BUF1_SIZE && null_offset < TEST_BUF_SIZE) {
            kbuf2[null_offset - TEST_BUF1_SIZE] = '\0';
        }
    }
}

typedef struct {
    struct vmm_aspace* aspace;
} usercopytest_t;

TEST_F_SETUP(usercopytest) {
    int ret;
    void* addr = START_PAGE_ADDR;
    uint32_t start_flags = get_start_flags_param();
    uint32_t end_flags = get_end_flags_param();

    _state->aspace = NULL;

    ret = vmm_create_aspace(&_state->aspace, "usercopy_test"0);
    ASSERT_EQ(NO_ERROR, ret);

    if (start_flags != FLAGS_NO_PAGE) {
        ret = vmm_alloc(_state->aspace, "start-page", PAGE_SIZE, &addr, 0,
                        VMM_FLAG_VALLOC_SPECIFIC | VMM_FLAG_NO_END_GUARD,
                        start_flags | ARCH_MMU_FLAG_PERM_NO_EXECUTE);
        ASSERT_EQ(NO_ERROR, ret);
        ASSERT_EQ(START_PAGE_ADDR, addr);
    }

    addr += PAGE_SIZE;

    if (end_flags != FLAGS_NO_PAGE) {
        ret = vmm_alloc(_state->aspace, "end-page", PAGE_SIZE, &addr, 0,
                        VMM_FLAG_VALLOC_SPECIFIC | VMM_FLAG_NO_START_GUARD,
                        end_flags | ARCH_MMU_FLAG_PERM_NO_EXECUTE);
        ASSERT_EQ(NO_ERROR, ret);
        ASSERT_EQ(START_PAGE_ADDR + PAGE_SIZE, addr);
    }

    vmm_set_active_aspace(_state->aspace);

test_abort:
    return;
}

TEST_F_TEARDOWN(usercopytest) {
    vmm_set_active_aspace(NULL);

    if (_state->aspace) {
        vmm_free_aspace(_state->aspace);
    }
}

TEST_P(usercopytest, copy_to_user) {
    user_addr_t addr = get_addr_param();
    uint32_t arch_mmu_flags_start = get_start_flags_param();
    uint32_t arch_mmu_flags_end = get_end_flags_param();
    int ret;
    char src_buf[TEST_BUF_SIZE];
    char* dest_kbuf1;
    char* dest_kbuf2;
    char expect1;
    char expect2;

    dest_kbuf1 = paddr_to_kvaddr(vaddr_to_paddr((void*)(uintptr_t)addr));
    dest_kbuf2 = paddr_to_kvaddr(
            vaddr_to_paddr((void*)(uintptr_t)addr + TEST_BUF1_SIZE));

    /* dest buffs should be NULL iff their flags are FLAGS_NO_PAGE */
    EXPECT_EQ((dest_kbuf1 == NULL), (arch_mmu_flags_start == FLAGS_NO_PAGE));
    EXPECT_EQ((dest_kbuf2 == NULL), (arch_mmu_flags_end == FLAGS_NO_PAGE));

    usercopy_test_init_buf(dest_kbuf1, dest_kbuf2, DEST_DATA, -1);
    memset(src_buf, SRC_DATA, sizeof(src_buf));

    /* Zero-length copy should always succeed */
    ret = copy_to_user(addr + TEST_BUF_COPY_START, NULL, 0);
    EXPECT_EQ(0, ret);

    /* Dest buffer should be untouched after zero-length copy */
    if (dest_kbuf1) {
        EXPECT_EQ(0, checkbuf(dest_kbuf1, DEST_DATA, TEST_BUF1_SIZE));
    }
    if (dest_kbuf2) {
        EXPECT_EQ(0, checkbuf(dest_kbuf2, DEST_DATA, TEST_BUF2_SIZE));
    }

    /* Perform non-zero length copy */
    ret = copy_to_user(addr + TEST_BUF_COPY_START,
                       src_buf + TEST_BUF_COPY_START, TEST_BUF_COPY_SIZE);

    /*
     * If both pages are writeable copy_to_user should succeed otherwise it
     * should return ERR_FAULT.
     */

    if (arch_mmu_flags_start == ARCH_MMU_FLAG_PERM_USER &&
        arch_mmu_flags_end == ARCH_MMU_FLAG_PERM_USER) {
        /*
         * If both pages are writeable from user-space copy_to_user should
         * return success and every byte should be copied to dest_buf.
         */

        EXPECT_EQ(0, ret);
        expect1 = SRC_DATA;
        expect2 = SRC_DATA;
    } else {
        /*
         * If one of the pages is not writeable from user-space copy_to_user
         * should return ERR_FAULT. If only the first page is writeable everying
         * should be copied in the first page or nothing should be copied in the
         * first page. If the first page is not writeable, nothing should be
         * copied to either page. If the second page is not writeable, no data
         * should be copied to it, even if the first page was written to.
         */

        EXPECT_EQ(ERR_FAULT, ret);
        if (arch_mmu_flags_start == ARCH_MMU_FLAG_PERM_USER &&
            dest_kbuf1[TEST_BUF_COPY_START] == SRC_DATA) {
            expect1 = SRC_DATA;
        } else {
            expect1 = DEST_DATA;
        }
        expect2 = DEST_DATA;
    }

    /* copy_to_user should not modify src_buf at all */
    EXPECT_EQ(0, checkbuf(src_buf, SRC_DATA, TEST_BUF_SIZE));

    if (dest_kbuf1) {
        /* Dest byte before copied region should be untouched */
        EXPECT_EQ(DEST_DATA, dest_kbuf1[0]);

        /* Check that copied region match expected value we selected above */
        EXPECT_EQ(0, checkbuf(dest_kbuf1 + TEST_BUF_COPY_START, expect1,
                              TEST_BUF1_COPY_SIZE));
    }

    if (dest_kbuf2) {
        /* Check that copied region match expected value we selected above */
        EXPECT_EQ(0, checkbuf(dest_kbuf2, expect2, TEST_BUF2_COPY_SIZE));

        /* Dest byte after copied region should be untouched */
        EXPECT_EQ(DEST_DATA, dest_kbuf2[TEST_BUF2_SIZE - 1]);
    }
}

TEST_P(usercopytest, copy_from_user) {
    user_addr_t addr = get_addr_param();
    uint32_t arch_mmu_flags_start = get_start_flags_param();
    uint32_t arch_mmu_flags_end = get_end_flags_param();
    int ret;
    char dest_buf[TEST_BUF_SIZE];
    char* src_kbuf1;
    char* src_kbuf2;
    char expect1;
    char expect2;

    memset(dest_buf, DEST_DATA, sizeof(dest_buf));
    src_kbuf1 = paddr_to_kvaddr(vaddr_to_paddr((void*)(uintptr_t)addr));
    src_kbuf2 = paddr_to_kvaddr(
            vaddr_to_paddr((void*)(uintptr_t)addr + TEST_BUF1_SIZE));

    /* src buffs should be NULL iff their flags are FLAGS_NO_PAGE */
    EXPECT_EQ((src_kbuf1 == NULL), (arch_mmu_flags_start == FLAGS_NO_PAGE));
    EXPECT_EQ((src_kbuf2 == NULL), (arch_mmu_flags_end == FLAGS_NO_PAGE));

    usercopy_test_init_buf(src_kbuf1, src_kbuf2, SRC_DATA, -1);

    /* Zero-length copy should always succeed */
    ret = copy_from_user(NULL, addr + TEST_BUF_COPY_START, 0);
    EXPECT_EQ(0, ret);

    /* Dest buffer should be untouched after zero-length copy */
    EXPECT_EQ(0, checkbuf(dest_buf, DEST_DATA, TEST_BUF_SIZE));

    /* Perform non-zero length copy */
    ret = copy_from_user(dest_buf + TEST_BUF_COPY_START,
                         addr + TEST_BUF_COPY_START, TEST_BUF_COPY_SIZE);
    if (arch_mmu_flags_start & arch_mmu_flags_end & ARCH_MMU_FLAG_PERM_USER) {
        /*
         * If both pages are readable from user-space copy_from_user should
         * return success and every byte should be copied to dest_buf.
         */

        EXPECT_EQ(0, ret);
        expect1 = SRC_DATA;
        expect2 = SRC_DATA;
    } else {
        /*
         * If one of the pages is not readable from user-space copy_from_user
         * should return ERR_FAULT, and the parts of dest_buf that could not be
         * copied into should be set to 0.
         * The destination kernel buffer should always be written so
         * potentially uninitialized kernel data does not leak.
         */

        EXPECT_EQ(ERR_FAULT, ret);
        if (!(arch_mmu_flags_start & ARCH_MMU_FLAG_PERM_USER) ||
            !dest_buf[TEST_BUF_COPY_START]) {
            expect1 = 0;
        } else {
            expect1 = SRC_DATA;
        }
        expect2 = 0;
    }

    EXPECT_EQ(0, checkbuf(dest_buf + TEST_BUF_COPY_START, expect1,
                          TEST_BUF1_COPY_SIZE));
    EXPECT_EQ(0, checkbuf(dest_buf + TEST_BUF1_SIZE, expect2,
                          TEST_BUF2_COPY_SIZE));

    /* Dest bytes before and after copied region should be untouched */
    EXPECT_EQ(DEST_DATA, dest_buf[0]);
    EXPECT_EQ(DEST_DATA, dest_buf[TEST_BUF_SIZE - 1]);

    /* Src buffer should not be modified */
    if (src_kbuf1) {
        EXPECT_EQ(0, checkbuf(src_kbuf1, SRC_DATA, TEST_BUF1_SIZE));
    }
    if (src_kbuf2) {
        EXPECT_EQ(0, checkbuf(src_kbuf2, SRC_DATA, TEST_BUF2_SIZE));
    }
}

#if ARCH_ARM64
#define ENABLED_ON_ARM64_NAME(name) name
#else
#define ENABLED_ON_ARM64_NAME(name) DISABLED_##name
#define copy_from_anywhere(dst, src, len) -1
#endif

TEST_P(usercopytest, ENABLED_ON_ARM64_NAME(copy_from_anywhere)) {
    user_addr_t addr = get_addr_param();
    uint32_t arch_mmu_flags_start = get_start_flags_param();
    uint32_t arch_mmu_flags_end = get_end_flags_param();
    int ret;
    char dest_buf[TEST_BUF_SIZE];
    char* src_kbuf1;
    char* src_kbuf2;
    char expect1;
    char expect2;

    memset(dest_buf, DEST_DATA, sizeof(dest_buf));
    src_kbuf1 = paddr_to_kvaddr(vaddr_to_paddr((void*)(uintptr_t)addr));
    src_kbuf2 = paddr_to_kvaddr(
            vaddr_to_paddr((void*)(uintptr_t)addr + TEST_BUF1_SIZE));

    /* src buffs should be NULL iff their flags are FLAGS_NO_PAGE */
    EXPECT_EQ((src_kbuf1 == NULL), (arch_mmu_flags_start == FLAGS_NO_PAGE));
    EXPECT_EQ((src_kbuf2 == NULL), (arch_mmu_flags_end == FLAGS_NO_PAGE));

    usercopy_test_init_buf(src_kbuf1, src_kbuf2, SRC_DATA, -1);

    /* Zero-length copy should always succeed */
    ret = copy_from_anywhere(NULL, addr + TEST_BUF_COPY_START, 0);
    EXPECT_EQ(0, ret);

    /* Dest buffer should be untouched after zero-length copy */
    EXPECT_EQ(0, checkbuf(dest_buf, DEST_DATA, TEST_BUF_SIZE));

    /* Perform non-zero length copy */
    ret = copy_from_anywhere(dest_buf + TEST_BUF_COPY_START,
                             addr + TEST_BUF_COPY_START, TEST_BUF_COPY_SIZE);
    if (arch_mmu_flags_start != FLAGS_NO_PAGE &&
        arch_mmu_flags_end != FLAGS_NO_PAGE) {
        /*
         * If both pages are readable, copy_from_anywhere should return
         * success and every byte should be copied to dest_buf.
         */

        EXPECT_EQ(0, ret);
        expect1 = SRC_DATA;
        expect2 = SRC_DATA;
    } else {
        /*
         * If one of the pages is not readable copy_from_anywhere should
         * return ERR_FAULT, and the parts of dest_buf that could not be
         * copied into should be set to 0.
         * The destination kernel buffer should always be written so
         * potentially uninitialized kernel data does not leak.
         */

        EXPECT_EQ(ERR_FAULT, ret);
        if (arch_mmu_flags_start == FLAGS_NO_PAGE) {
            expect1 = 0;
        } else {
            expect1 = SRC_DATA;
        }
        expect2 = 0;
    }

    EXPECT_EQ(0, checkbuf(dest_buf + TEST_BUF_COPY_START, expect1,
                          TEST_BUF1_COPY_SIZE));
    EXPECT_EQ(0, checkbuf(dest_buf + TEST_BUF1_SIZE, expect2,
                          TEST_BUF2_COPY_SIZE));

    /* Dest bytes before and after copied region should be untouched */
    EXPECT_EQ(DEST_DATA, dest_buf[0]);
    EXPECT_EQ(DEST_DATA, dest_buf[TEST_BUF_SIZE - 1]);

    /* Src buffer should not be modified */
    if (src_kbuf1) {
        EXPECT_EQ(0, checkbuf(src_kbuf1, SRC_DATA, TEST_BUF1_SIZE));
    }
    if (src_kbuf2) {
        EXPECT_EQ(0, checkbuf(src_kbuf2, SRC_DATA, TEST_BUF2_SIZE));
    }
}

static void usercopy_test_strlcpy_from_user_inner(user_addr_t addr,
                                                  uint arch_mmu_flags_start,
                                                  uint arch_mmu_flags_end,
                                                  int copy_size,
                                                  int null_off) {
    int ret;
    char dest_buf[TEST_BUF_SIZE];
    char* src_kbuf1;
    char* src_kbuf2;
    size_t dest_len;
    int copy_len = copy_size ? copy_size - 1 : 0;

    memset(dest_buf, DEST_DATA, sizeof(dest_buf));
    src_kbuf1 = paddr_to_kvaddr(vaddr_to_paddr((void*)(uintptr_t)addr));
    src_kbuf2 = paddr_to_kvaddr(
            vaddr_to_paddr((void*)(uintptr_t)addr + TEST_BUF1_SIZE));

    /* src buffs should be NULL iff their flags are FLAGS_NO_PAGE */
    EXPECT_EQ((src_kbuf1 == NULL), (arch_mmu_flags_start == FLAGS_NO_PAGE));
    EXPECT_EQ((src_kbuf2 == NULL), (arch_mmu_flags_end == FLAGS_NO_PAGE));

    usercopy_test_init_buf(src_kbuf1, src_kbuf2, SRC_DATA, null_off);

    ret = strlcpy_from_user(dest_buf + TEST_BUF_COPY_START,
                            addr + TEST_BUF_COPY_START, copy_size);

    dest_len = strnlen(dest_buf + TEST_BUF_COPY_START, TEST_BUF_COPY_SIZE);
    if (copy_size) {
        /*
         * Kernel buffer should always be null terminated.
         */

        EXPECT_NE(TEST_BUF_COPY_SIZE, dest_len, "  null_off=%d, copy_size=%d\n",
                  null_off, copy_size);
    } else {
        /*
         * If copy_size is 0, then kernel buffer will not be null terminated.
         */

        EXPECT_EQ(TEST_BUF_COPY_SIZE, dest_len, "  null_off=%d, copy_size=%d\n",
                  null_off, copy_size);
        dest_len = 0;
    }

    /*
     * If the string in dest_buf is not empty it should only contain data from
     * the source string.
     */

    EXPECT_EQ(0, checkbuf(dest_buf + TEST_BUF_COPY_START, SRC_DATA, dest_len),
              "  null_off=%d, copy_size=%d\n", null_off, copy_size);

    if ((arch_mmu_flags_start & ARCH_MMU_FLAG_PERM_USER) &&
        ((arch_mmu_flags_end & ARCH_MMU_FLAG_PERM_USER) ||
         null_off < TEST_BUF1_SIZE)) {
        /*
         * If the pages readable from user-space contain a 0 terminated string,
         * strlcpy_from_user should return the length of that string and every
         * byte up to the 0 terminator that fits in dest_buf should be copied
         * there. dest_buf should always be 0 terminated.
         */

        EXPECT_EQ(null_off - TEST_BUF_COPY_START, ret,
                  "  wrong strlen returned, null_off=%d, copy_size=%d\n",
                  null_off, copy_size);
        EXPECT_EQ(MIN(null_off - TEST_BUF_COPY_START, copy_len), dest_len,
                  "  null_off=%d, copy_size=%d\n", null_off, copy_size);
    } else {
        /*
         * If one of the pages is not readable from user-space strlcpy_from_user
         * should return ERR_FAULT, and dest_buf should have a null terminator
         * at the start of the faulting page or at the start of the string.
         */

        EXPECT_EQ(ERR_FAULT, ret, "  null_off=%d, copy_size=%d\n", null_off,
                  copy_size);
        if (!(arch_mmu_flags_start & ARCH_MMU_FLAG_PERM_USER)) {
            EXPECT_EQ(0, dest_len, "  null_off=%d, copy_size=%d\n", null_off,
                      copy_size);
        } else if (dest_len) {
            EXPECT_EQ(MIN(TEST_BUF1_COPY_SIZE, copy_len), dest_len,
                      "  null_off=%d, copy_size=%d\n", null_off, copy_size);
        }
    }

    /* Src buffer should not be modified */
    if (src_kbuf1) {
        if (null_off < TEST_BUF1_SIZE) {
            EXPECT_EQ(0, checkbuf(src_kbuf1, SRC_DATA, null_off));
            EXPECT_EQ('\0', src_kbuf1[null_off]);
            EXPECT_EQ(0, checkbuf(src_kbuf1 + null_off + 1, SRC_DATA,
                                  TEST_BUF1_SIZE - null_off - 1));
        } else {
            EXPECT_EQ(0, checkbuf(src_kbuf1, SRC_DATA, TEST_BUF1_SIZE));
        }
    }
    if (src_kbuf2) {
        if (null_off >= TEST_BUF1_SIZE) {
            size_t null_off2 = null_off - TEST_BUF1_SIZE;
            EXPECT_EQ(0, checkbuf(src_kbuf2, SRC_DATA, null_off2));
            EXPECT_EQ('\0', src_kbuf2[null_off2]);
            EXPECT_EQ(0, checkbuf(src_kbuf2 + null_off2 + 1, SRC_DATA,
                                  TEST_BUF2_SIZE - null_off2 - 1));
        } else {
            EXPECT_EQ(0, checkbuf(src_kbuf2, SRC_DATA, TEST_BUF2_SIZE));
        }
    }

    /* Dest bytes before and after copied region should be untouched */
    EXPECT_EQ(DEST_DATA, dest_buf[0]);
    EXPECT_EQ(DEST_DATA, dest_buf[TEST_BUF_COPY_START + copy_size]);
    EXPECT_EQ(DEST_DATA, dest_buf[TEST_BUF_SIZE - 1]);
}

TEST_P(usercopytest, strlcpy_from_user) {
    user_addr_t addr = get_addr_param();
    uint32_t arch_mmu_flags_start = get_start_flags_param();
    uint32_t arch_mmu_flags_end = get_end_flags_param();
    size_t copy_sizes[] = {0, TEST_BUF1_COPY_SIZE, TEST_BUF_COPY_SIZE};
    size_t copy_sizes_index;
    int null_off;
    int copy_size;

    for (copy_sizes_index = 0; copy_sizes_index < countof(copy_sizes);
         copy_sizes_index++) {
        copy_size = copy_sizes[copy_sizes_index];
        for (null_off = TEST_BUF_COPY_START; null_off < TEST_BUF_SIZE;
             null_off++) {
            usercopy_test_strlcpy_from_user_inner(addr, arch_mmu_flags_start,
                                                  arch_mmu_flags_end, copy_size,
                                                  null_off);
        }
    }
}

static const char* flags_to_str(uint32_t flags) {
    switch (flags) {
    case FLAGS_NO_PAGE:
        return "--";
    case FLAGS_NO_USER:
        return "ko";
    case FLAGS_RO_USER:
        return "ro";
    case FLAGS_RW_USER:
        return "rw";
    default:
        return "??";
    }
}

static void user_param_to_string(const void* param,
                                 char* buf,
                                 size_t buf_size) {
    uint32_t start_flags = get_start_flags_param();
    uint32_t end_flags = get_end_flags_param();
    size_t count = 0;

    count = scnprintf(buf + count, buf_size - count, "%s",
                      flags_to_str(start_flags));
    scnprintf(buf + count, buf_size - count, "%s", flags_to_str(end_flags));
}

INSTANTIATE_TEST_SUITE_P(UserCopyTestParams,
                         usercopytest,
                         testing_Combine(testing_Values(TEST_BUF_ADDR),
                                         testing_Values(FLAGS_NO_PAGE,
                                                        FLAGS_NO_USER,
                                                        FLAGS_RO_USER,
                                                        FLAGS_RW_USER),
                                         testing_Values(FLAGS_NO_PAGE,
                                                        FLAGS_NO_USER,
                                                        FLAGS_RO_USER,
                                                        FLAGS_RW_USER)),
                         user_param_to_string);

#if IS_64BIT && USER_32BIT
/*
 * Tests with Kernel addresses are not applicable to arm64u32 since kernel
 * addresses do not fit in a user_addr_t.
 */

static_assert(KERNEL_BASE > UINT32_MAX);

PORT_TEST(usercopy_tests, PORT_NAME)

#else
/* These are filled in before the tests are run */
static user_addr_t kernel_addrs[3];

static void kernel_param_to_string(const void* param,
                                   char* buf,
                                   size_t buf_size) {
    const voidconst* kernel_param = param;
    size_t idx = ((user_addr_t*)kernel_param[0] - kernel_addrs);
    const char* str;

    switch (idx) {
    case STACK_ADDR_IDX:
        str = "kernel-stack";
        break;
    case HEAP_ADDR_IDX:
        str = "kernel-heap";
        break;
    case GLOBAL_ADDR_IDX:
        str = "kernel-global";
        break;
    default:
        str = "unknown-address-type";
    }

    scnprintf(buf, buf_size, "%s", str);
}

INSTANTIATE_TEST_SUITE_P(KernelUserCopyTestParams,
                         usercopytest,
                         testing_Combine(testing_ValuesIn(kernel_addrs),
                                         testing_Values(FLAGS_NO_USER),
                                         testing_Values(FLAGS_NO_USER)),
                         kernel_param_to_string);

static bool run_usercopy_test(struct unittest* test) {
    bool tests_passed;
    static uint8_t global_buf[TEST_BUF_SIZE];
    uint8_t stack_buf[TEST_BUF_SIZE];
    uint8_t* heap_buf = malloc(TEST_BUF_SIZE);

    ASSERT(heap_buf);

    kernel_addrs[STACK_ADDR_IDX] = (user_addr_t)stack_buf;
    kernel_addrs[HEAP_ADDR_IDX] = (user_addr_t)heap_buf;
    kernel_addrs[GLOBAL_ADDR_IDX] = (user_addr_t)global_buf;

    tests_passed = RUN_ALL_TESTS();

    free(heap_buf);

    return tests_passed;
}

static void usercopy_test_init(uint level) {
    static struct unittest usercopy_unittest = {
            .port_name = PORT_NAME,
            .run_test = run_usercopy_test,
    };

    unittest_add(&usercopy_unittest);
}

LK_INIT_HOOK(usercopy_test, usercopy_test_init, LK_INIT_LEVEL_APPS);
#endif  // !(IS_64BIT && USER_32BIT)

Messung V0.5 in Prozent
C=91 H=97 G=93

¤ Dauer der Verarbeitung: 0.13 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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik