tests: mem_protect: add error test case of userspace
Add some error test cases for userspace of memory protection module. This increase the code coverage of testing. Signed-off-by: Enjia Mai <enjiax.mai@intel.com>
This commit is contained in:
parent
1a86820876
commit
3a500dfdfc
4 changed files with 417 additions and 7 deletions
|
@ -2,5 +2,5 @@ CONFIG_STACK_CANARIES=n
|
|||
CONFIG_ZTEST=y
|
||||
CONFIG_ZTEST_STACKSIZE=2048
|
||||
CONFIG_MAX_THREAD_BYTES=4
|
||||
CONFIG_USERSPACE=y
|
||||
CONFIG_TEST_USERSPACE=y
|
||||
CONFIG_APPLICATION_DEFINED_SYSCALL=y
|
||||
|
|
|
@ -52,6 +52,78 @@ void test_kobject_access_grant(void)
|
|||
NULL, NULL, NULL);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test grant access of given NULL kobject
|
||||
*
|
||||
* @details Call function with a NULL parameter in supervisor mode,
|
||||
* nothing happened.
|
||||
*
|
||||
* @ingroup kernel_memprotect_tests
|
||||
*
|
||||
* @see k_thread_access_grant()
|
||||
*/
|
||||
void test_kobject_access_grant_error(void)
|
||||
{
|
||||
k_object_access_grant(NULL, k_current_get());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test grant access of given NULL thread in usermode
|
||||
*
|
||||
* @details Call function with NULL parameter, an expected fault
|
||||
* happened.
|
||||
*
|
||||
* @ingroup kernel_memprotect_tests
|
||||
*
|
||||
* @see k_thread_access_grant()
|
||||
*/
|
||||
void test_kobject_access_grant_error_user(void)
|
||||
{
|
||||
struct k_msgq *m;
|
||||
|
||||
m = k_object_alloc(K_OBJ_MSGQ);
|
||||
k_object_access_grant(m, k_current_get());
|
||||
|
||||
set_fault_valid(true);
|
||||
/* a K_ERR_KERNEL_OOPS expected */
|
||||
k_object_access_grant(m, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test grant access of given NULL kobject in usermode
|
||||
*
|
||||
* @details Call function with a NULL parameter, an expected fault
|
||||
* happened.
|
||||
*
|
||||
* @see k_thread_access_grant()
|
||||
*
|
||||
* @ingroup kernel_memprotect_tests
|
||||
*/
|
||||
void test_kobject_access_grant_error_user_null(void)
|
||||
{
|
||||
set_fault_valid(true);
|
||||
/* a K_ERR_KERNEL_OOPS expected */
|
||||
k_object_access_grant(NULL, k_current_get());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test grant access to all the kobject for thread
|
||||
*
|
||||
* @details Call function with a NULL parameter, an expected fault
|
||||
* happened.
|
||||
*
|
||||
* @see k_thread_access_all_grant()
|
||||
*
|
||||
* @ingroup kernel_memprotect_tests
|
||||
*/
|
||||
void test_kobject_access_all_grant_error(void)
|
||||
{
|
||||
set_fault_valid(true);
|
||||
/* a K_ERR_KERNEL_OOPS expected */
|
||||
k_object_access_all_grant(NULL);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
static void syscall_invalid_kobject_user_part(void *p1, void *p2, void *p3)
|
||||
{
|
||||
|
@ -177,14 +249,11 @@ static void kobject_grant_access_extra_entry(void *p1, void *p2, void *p3)
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Test grant access
|
||||
*
|
||||
* @details Will grant access to another thread for the
|
||||
* semaphore it holds.
|
||||
* @brief Test access revoke
|
||||
*
|
||||
* @ingroup kernel_memprotect_tests
|
||||
*
|
||||
* @see k_thread_access_grant()
|
||||
* @see k_thread_access_grant(), k_object_access_revoke()
|
||||
*/
|
||||
void test_kobject_grant_access_kobj(void)
|
||||
{
|
||||
|
@ -282,6 +351,22 @@ void test_kobject_release_from_user(void)
|
|||
|
||||
k_thread_join(&child_thread, K_FOREVER);
|
||||
}
|
||||
|
||||
/* @brief Test release kernel a invaild kobject
|
||||
*
|
||||
* @details Validate release kernel objects with NULL parameter.
|
||||
*
|
||||
* @see k_object_release()
|
||||
*
|
||||
* @ingroup kernel_memprotect_tests
|
||||
*/
|
||||
void test_kobject_release_null(void)
|
||||
{
|
||||
int dummy;
|
||||
|
||||
k_object_release(&dummy);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
static void access_all_grant_child_give(void *p1, void *p2, void *p3)
|
||||
{
|
||||
|
@ -325,6 +410,7 @@ void test_kobject_access_all_grant(void)
|
|||
|
||||
k_thread_join(&child_thread, K_FOREVER);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
static void residual_permissions_child_success(void *p1, void *p2, void *p3)
|
||||
|
@ -994,3 +1080,289 @@ void test_mark_thread_exit_uninitialized(void)
|
|||
ret = z_object_validate(ko, K_OBJ_ANY, _OBJ_INIT_FALSE);
|
||||
zassert_equal(ret, _OBJ_INIT_FALSE, NULL);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/* object validatoin checks */
|
||||
|
||||
static void tThread_object_free_error(void *p1, void *p2, void *p3)
|
||||
{
|
||||
/* a K_ERR_CPU_EXCEPTION expected */
|
||||
set_fault_valid(true);
|
||||
k_object_free(NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test free an invalid kernel object
|
||||
*
|
||||
* @details Spawn a thread free a NULL, an expected fault happened.
|
||||
*
|
||||
* @see k_object_free()
|
||||
*
|
||||
* @ingroup kernel_memprotect_tests
|
||||
*/
|
||||
void test_kobject_free_error(void)
|
||||
{
|
||||
uint32_t perm = K_INHERIT_PERMS;
|
||||
|
||||
if (_is_user_context()) {
|
||||
perm = perm | K_USER;
|
||||
}
|
||||
|
||||
k_tid_t tid = k_thread_create(&child_thread, child_stack,
|
||||
K_THREAD_STACK_SIZEOF(child_stack),
|
||||
(k_thread_entry_t)&tThread_object_free_error,
|
||||
(void *)&tid, NULL, NULL,
|
||||
K_PRIO_PREEMPT(1), perm, K_NO_WAIT);
|
||||
|
||||
k_thread_join(tid, K_FOREVER);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test alloc an invalid kernel object
|
||||
*
|
||||
* @details Allocate invalid kernel objects, then no alloction
|
||||
* will be returned.
|
||||
*
|
||||
* @ingroup kernel_memprotect_tests
|
||||
*
|
||||
* @see k_object_alloc()
|
||||
*/
|
||||
void test_kobject_init_error(void)
|
||||
{
|
||||
/* invalid kernel object alloction */
|
||||
zassert_is_null(k_object_alloc(K_OBJ_ANY-1),
|
||||
"expected got NULL kobject");
|
||||
zassert_is_null(k_object_alloc(K_OBJ_LAST),
|
||||
"expected got NULL kobject");
|
||||
|
||||
/* futex not support */
|
||||
zassert_is_null(k_object_alloc(K_OBJ_FUTEX),
|
||||
"expected got NULL kobject");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test kernel object until out of memory
|
||||
*
|
||||
* @details Create a dynamic kernel object repeatedly until run out
|
||||
* of all heap memory, an expected out of memory error generated.
|
||||
*
|
||||
* @see k_object_alloc()
|
||||
*
|
||||
* @ingroup kernel_memprotect_tests
|
||||
*/
|
||||
void test_kobj_create_out_of_memory(void)
|
||||
{
|
||||
int ttype;
|
||||
int max_obj = 0;
|
||||
void *create_obj[MAX_OBJ] = {0};
|
||||
|
||||
for (ttype = K_OBJ_MEM_SLAB; ttype < K_OBJ_CONDVAR ; ttype++) {
|
||||
|
||||
for (int i = 0; i < MAX_OBJ; i++) {
|
||||
create_obj[i] = k_object_alloc(ttype);
|
||||
max_obj = i;
|
||||
if (create_obj[i] == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
zassert_is_null(create_obj[max_obj],
|
||||
"excepted alloc failure");
|
||||
printk("==max_obj(%d)\n", max_obj);
|
||||
|
||||
|
||||
for (int i = 0; i < max_obj; i++) {
|
||||
k_object_free((void *)create_obj[i]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DYNAMIC_OBJECTS
|
||||
extern uint8_t _thread_idx_map[CONFIG_MAX_THREAD_BYTES];
|
||||
|
||||
#define MAX_THREAD_BITS (CONFIG_MAX_THREAD_BYTES * 8)
|
||||
#endif
|
||||
|
||||
/* @brief Test alloc thread object until out of idex
|
||||
*
|
||||
* @details Allocate thread object until it out of index, no more
|
||||
* thread can be allocated and report an error.
|
||||
*
|
||||
* @see k_object_alloc()
|
||||
*
|
||||
* @ingroup kernel_memprotect_tests
|
||||
*/
|
||||
void test_thread_alloc_out_of_idx(void)
|
||||
{
|
||||
#ifdef CONFIG_DYNAMIC_OBJECTS
|
||||
struct k_thread *thread[MAX_THREAD_BITS];
|
||||
struct k_thread *fail_thread;
|
||||
int cur_max = 0;
|
||||
|
||||
for (int i = 0; i < MAX_THREAD_BITS; i++) {
|
||||
|
||||
thread[i] = k_object_alloc(K_OBJ_THREAD);
|
||||
|
||||
if (!thread[i]) {
|
||||
cur_max = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** TESTPOINT: all the idx bits set to 1 */
|
||||
for (int i = 0; i < CONFIG_MAX_THREAD_BYTES; i++) {
|
||||
int idx = find_lsb_set(_thread_idx_map[i]);
|
||||
|
||||
zassert_true(idx == 0,
|
||||
"idx shall all set to 1 when all used");
|
||||
}
|
||||
|
||||
fail_thread = k_object_alloc(K_OBJ_THREAD);
|
||||
/** TESTPOINT: thread alloc failed due to out of idx */
|
||||
zassert_is_null(thread[cur_max],
|
||||
"mo more kobj[%d](0x%lx) shall be allocated"
|
||||
, cur_max, (uintptr_t)thread[cur_max]);
|
||||
|
||||
|
||||
for (int i = 0; i < cur_max; i++) {
|
||||
if (thread[i]) {
|
||||
k_object_free(thread[i]);
|
||||
}
|
||||
}
|
||||
#else
|
||||
ztest_test_skip();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test kernel object allocation
|
||||
*
|
||||
* @details Allocate all kinds of kernel object and do permission
|
||||
* operation functions.
|
||||
*
|
||||
* @see k_object_alloc()
|
||||
*
|
||||
* @ingroup kernel_memprotect_tests
|
||||
*/
|
||||
void test_alloc_kobjects(void)
|
||||
{
|
||||
struct k_thread *t;
|
||||
struct k_msgq *m;
|
||||
struct k_stack *s;
|
||||
struct k_pipe *p;
|
||||
struct k_queue *q;
|
||||
struct k_mem_slab *mslab;
|
||||
struct k_poll_signal *polls;
|
||||
struct k_timer *timer;
|
||||
struct k_mutex *mutex;
|
||||
void *ko;
|
||||
|
||||
/* allocate kernel object */
|
||||
|
||||
t = k_object_alloc(K_OBJ_THREAD);
|
||||
zassert_not_null(t, "alloc obj (0x%lx)\n", (uintptr_t)t);
|
||||
p = k_object_alloc(K_OBJ_PIPE);
|
||||
zassert_not_null(p, "alloc obj (0x%lx)\n", (uintptr_t)p);
|
||||
s = k_object_alloc(K_OBJ_STACK);
|
||||
zassert_not_null(s, "alloc obj (0x%lx)\n", (uintptr_t)s);
|
||||
m = k_object_alloc(K_OBJ_MSGQ);
|
||||
zassert_not_null(m, "alloc obj (0x%lx)\n", (uintptr_t)m);
|
||||
q = k_object_alloc(K_OBJ_QUEUE);
|
||||
zassert_not_null(q, "alloc obj (0x%lx)\n", (uintptr_t)q);
|
||||
|
||||
/* release operations */
|
||||
k_object_release((void *)t);
|
||||
k_object_release((void *)p);
|
||||
k_object_release((void *)s);
|
||||
k_object_release((void *)m);
|
||||
k_object_release((void *)q);
|
||||
|
||||
mslab = k_object_alloc(K_OBJ_MEM_SLAB);
|
||||
zassert_not_null(mslab, "alloc obj (0x%lx)\n", (uintptr_t)mslab);
|
||||
polls = k_object_alloc(K_OBJ_POLL_SIGNAL);
|
||||
zassert_not_null(polls, "alloc obj (0x%lx)\n", (uintptr_t)polls);
|
||||
timer = k_object_alloc(K_OBJ_TIMER);
|
||||
zassert_not_null(timer, "alloc obj (0x%lx)\n", (uintptr_t)timer);
|
||||
mutex = k_object_alloc(K_OBJ_MUTEX);
|
||||
zassert_not_null(mutex, "alloc obj (0x%lx)\n", (uintptr_t)mutex);
|
||||
|
||||
k_object_release((void *)mslab);
|
||||
k_object_release((void *)polls);
|
||||
k_object_release((void *)timer);
|
||||
k_object_release((void *)mutex);
|
||||
|
||||
/* no real object will be allocated */
|
||||
ko = k_object_alloc(K_OBJ_ANY);
|
||||
zassert_is_null(ko, "alloc obj (0x%lx)\n", (uintptr_t)ko);
|
||||
ko = k_object_alloc(K_OBJ_LAST);
|
||||
zassert_is_null(ko, "alloc obj (0x%lx)\n", (uintptr_t)ko);
|
||||
|
||||
/* alloc possible device driver */
|
||||
ko = k_object_alloc(K_OBJ_LAST-1);
|
||||
zassert_not_null(ko, "alloc obj (0x%lx)\n", (uintptr_t)ko);
|
||||
k_object_release((void *)ko);
|
||||
}
|
||||
|
||||
/* static kobject for permission testing */
|
||||
struct k_mem_slab ms;
|
||||
struct k_msgq mq;
|
||||
struct k_mutex mutex;
|
||||
struct k_pipe p;
|
||||
struct k_queue q;
|
||||
struct k_poll_signal ps;
|
||||
struct k_sem sem;
|
||||
struct k_stack s;
|
||||
struct k_thread t;
|
||||
struct k_timer timer;
|
||||
struct z_thread_stack_element zs;
|
||||
struct k_futex f;
|
||||
struct k_condvar c;
|
||||
|
||||
static void entry_error_perm(void *p1, void *p2, void *p3)
|
||||
{
|
||||
set_fault_valid(true);
|
||||
k_object_access_grant(p2, k_current_get());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test grant access failed in user mode
|
||||
*
|
||||
* @details Before grant access of static kobject to user thread, any
|
||||
* grant access to this thread, will trigger an expected thread
|
||||
* permission error.
|
||||
*
|
||||
* @see k_thread_access_grant()
|
||||
*
|
||||
* @ingroup kernel_memprotect_tests
|
||||
*/
|
||||
void test_kobject_perm_error(void)
|
||||
{
|
||||
void *kobj[16];
|
||||
|
||||
kobj[0] = &ms;
|
||||
kobj[1] = &mq;
|
||||
kobj[2] = &mutex;
|
||||
kobj[3] = &p;
|
||||
kobj[4] = &q;
|
||||
kobj[5] = &ps;
|
||||
kobj[6] = &sem;
|
||||
kobj[7] = &s;
|
||||
kobj[8] = &t;
|
||||
kobj[9] = &timer;
|
||||
kobj[10] = &zs;
|
||||
kobj[11] = &f;
|
||||
kobj[12] = &c;
|
||||
|
||||
for (int i = 0; i < 12 ; i++) {
|
||||
|
||||
k_tid_t tid = k_thread_create(&child_thread, child_stack,
|
||||
K_THREAD_STACK_SIZEOF(child_stack),
|
||||
(k_thread_entry_t)entry_error_perm,
|
||||
(void *)&tid, kobj[i], NULL,
|
||||
1, K_USER, K_NO_WAIT);
|
||||
|
||||
k_thread_join(tid, K_FOREVER);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,11 +14,16 @@
|
|||
#include <stdlib.h>
|
||||
#include "mem_protect.h"
|
||||
|
||||
K_HEAP_DEFINE(test_mem_heap, TEST_HEAP_SIZE);
|
||||
|
||||
K_THREAD_STACK_DEFINE(test_stack, KOBJECT_STACK_SIZE);
|
||||
|
||||
void test_main(void)
|
||||
{
|
||||
k_thread_priority_set(k_current_get(), -1);
|
||||
|
||||
k_thread_heap_assign(k_current_get(), &test_mem_heap);
|
||||
|
||||
ztest_test_suite(memory_protection_test_suite,
|
||||
/* inherit.c */
|
||||
ztest_unit_test(test_permission_inheritance),
|
||||
|
@ -43,12 +48,17 @@ void test_main(void)
|
|||
|
||||
/* kobject.c */
|
||||
ztest_unit_test(test_kobject_access_grant),
|
||||
ztest_unit_test(test_kobject_access_grant_error),
|
||||
ztest_user_unit_test(test_kobject_access_grant_error_user_null),
|
||||
ztest_user_unit_test(test_kobject_access_grant_error_user),
|
||||
ztest_user_unit_test(test_kobject_access_all_grant_error),
|
||||
ztest_unit_test(test_syscall_invalid_kobject),
|
||||
ztest_unit_test(test_thread_without_kobject_permission),
|
||||
ztest_unit_test(test_kobject_revoke_access),
|
||||
ztest_unit_test(test_kobject_grant_access_kobj),
|
||||
ztest_unit_test(test_kobject_grant_access_kobj_invalid),
|
||||
ztest_unit_test(test_kobject_release_from_user),
|
||||
ztest_unit_test(test_kobject_release_null),
|
||||
ztest_unit_test(test_kobject_access_all_grant),
|
||||
ztest_unit_test(test_thread_has_residual_permissions),
|
||||
ztest_unit_test(test_kobject_access_grant_to_invalid_thread),
|
||||
|
@ -65,7 +75,13 @@ void test_main(void)
|
|||
ztest_unit_test(test_create_new_essential_thread_from_user),
|
||||
ztest_unit_test(test_create_new_higher_prio_thread_from_user),
|
||||
ztest_unit_test(test_create_new_invalid_prio_thread_from_user),
|
||||
ztest_unit_test(test_mark_thread_exit_uninitialized)
|
||||
ztest_unit_test(test_mark_thread_exit_uninitialized),
|
||||
ztest_user_unit_test(test_kobject_init_error),
|
||||
ztest_unit_test(test_alloc_kobjects),
|
||||
ztest_unit_test(test_thread_alloc_out_of_idx),
|
||||
ztest_unit_test(test_kobj_create_out_of_memory),
|
||||
ztest_unit_test(test_kobject_perm_error),
|
||||
ztest_unit_test(test_kobject_free_error)
|
||||
);
|
||||
|
||||
ztest_run_test_suite(memory_protection_test_suite);
|
||||
|
|
|
@ -53,6 +53,18 @@ extern void test_create_new_higher_prio_thread_from_user(void);
|
|||
extern void test_create_new_invalid_prio_thread_from_user(void);
|
||||
extern void test_mark_thread_exit_uninitialized(void);
|
||||
extern void test_mem_part_overlap(void);
|
||||
extern void test_kobject_access_grant_error(void);
|
||||
extern void test_kobject_access_grant_error_user(void);
|
||||
extern void test_kobject_access_grant_error_user_null(void);
|
||||
extern void test_kobject_access_all_grant_error(void);
|
||||
extern void test_kobject_release_null(void);
|
||||
extern void test_kobject_free_error(void);
|
||||
extern void test_kobject_init_error(void);
|
||||
extern void test_kobj_create_out_of_memory(void);
|
||||
extern void test_thread_alloc_out_of_idx(void);
|
||||
extern void test_alloc_kobjects(void);
|
||||
extern void test_kobject_perm_error(void);
|
||||
|
||||
|
||||
/* Flag needed to figure out if the fault was expected or not. */
|
||||
extern volatile bool valid_fault;
|
||||
|
@ -115,6 +127,16 @@ static inline void set_fault_valid(bool valid)
|
|||
/* for kobject.c */
|
||||
#define KOBJECT_STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACKSIZE)
|
||||
|
||||
|
||||
|
||||
#if defined(CONFIG_X86_64)
|
||||
#define TEST_HEAP_SIZE (2 << CONFIG_MAX_THREAD_BYTES) * 1024
|
||||
#define MAX_OBJ 512
|
||||
#else
|
||||
#define TEST_HEAP_SIZE (2 << CONFIG_MAX_THREAD_BYTES) * 256
|
||||
#define MAX_OBJ 256
|
||||
#endif
|
||||
|
||||
#ifndef _TEST_SYSCALLS_H_
|
||||
#define _TEST_SYSCALLS_H_
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue