tests/arch/x86: Add tests for shadow stack
Ensure they behave as expected. Signed-off-by: Ederson de Souza <ederson.desouza@intel.com>
This commit is contained in:
committed by
Benjamin Cabé
parent
948c884054
commit
eb6da2ec20
@@ -1,2 +1,3 @@
|
||||
CONFIG_ZTEST=y
|
||||
CONFIG_X86_CET=y
|
||||
CONFIG_IRQ_OFFLOAD=y
|
||||
|
||||
@@ -5,32 +5,38 @@
|
||||
*/
|
||||
|
||||
#include <zephyr/ztest.h>
|
||||
#include <zephyr/arch/exception.h>
|
||||
#include <zephyr/irq_offload.h>
|
||||
|
||||
#include <zephyr/kernel/thread_stack.h>
|
||||
|
||||
#define IV_CTRL_PROTECTION_EXCEPTION 21
|
||||
|
||||
#define CTRL_PROTECTION_ERRORCODE_NEAR_RET 1
|
||||
#define CTRL_PROTECTION_ERRORCODE_ENDBRANCH 3
|
||||
|
||||
extern int should_work(int a);
|
||||
extern int should_not_work(int a);
|
||||
#define STACKSIZE 1024
|
||||
#define THREAD_PRIORITY 5
|
||||
|
||||
static bool expect_fault;
|
||||
static int expect_code;
|
||||
K_SEM_DEFINE(error_handler_sem, 0, 1);
|
||||
|
||||
volatile bool expect_fault;
|
||||
volatile int expect_code;
|
||||
volatile int expect_reason;
|
||||
|
||||
void k_sys_fatal_error_handler(unsigned int reason, const struct arch_esf *pEsf)
|
||||
{
|
||||
if (expect_fault) {
|
||||
#ifdef CONFIG_X86_64
|
||||
zassert_equal(pEsf->vector, IV_CTRL_PROTECTION_EXCEPTION,
|
||||
"unexpected exception");
|
||||
zassert_equal(pEsf->vector, expect_reason, "unexpected exception");
|
||||
zassert_equal(pEsf->code, expect_code, "unexpected error code");
|
||||
#else
|
||||
zassert_equal(z_x86_exception_vector, IV_CTRL_PROTECTION_EXCEPTION,
|
||||
"unexpected exception");
|
||||
zassert_equal(z_x86_exception_vector, expect_reason, "unexpected exception");
|
||||
zassert_equal(pEsf->errorCode, expect_code, "unexpected error code");
|
||||
#endif
|
||||
printk("fatal error expected as part of test case\n");
|
||||
expect_fault = false;
|
||||
|
||||
k_sem_give(&error_handler_sem);
|
||||
} else {
|
||||
printk("fatal error was unexpected, aborting\n");
|
||||
TC_END_REPORT(TC_FAIL);
|
||||
@@ -38,6 +44,123 @@ void k_sys_fatal_error_handler(unsigned int reason, const struct arch_esf *pEsf)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HW_SHADOW_STACK
|
||||
void thread_a_entry(void *p1, void *p2, void *p3);
|
||||
K_SEM_DEFINE(thread_a_sem, 0, 1);
|
||||
K_THREAD_DEFINE(thread_a, STACKSIZE, thread_a_entry, NULL, NULL, NULL,
|
||||
THREAD_PRIORITY, 0, -1);
|
||||
|
||||
void thread_b_entry(void *p1, void *p2, void *p3);
|
||||
K_SEM_DEFINE(thread_b_sem, 0, 1);
|
||||
K_SEM_DEFINE(thread_b_irq_sem, 0, 1);
|
||||
K_THREAD_DEFINE(thread_b, STACKSIZE, thread_b_entry, NULL, NULL, NULL,
|
||||
THREAD_PRIORITY, 0, -1);
|
||||
|
||||
static bool is_shstk_enabled(void)
|
||||
{
|
||||
long cur;
|
||||
|
||||
cur = z_x86_msr_read(X86_S_CET_MSR);
|
||||
return (cur & X86_S_CET_MSR_SHSTK_EN) == X86_S_CET_MSR_SHSTK_EN;
|
||||
}
|
||||
|
||||
void thread_c_entry(void *p1, void *p2, void *p3)
|
||||
{
|
||||
zassert_true(is_shstk_enabled(), "shadow stack not enabled on static thread");
|
||||
}
|
||||
|
||||
K_THREAD_DEFINE(thread_c, STACKSIZE, thread_c_entry, NULL, NULL, NULL,
|
||||
THREAD_PRIORITY, 0, 0);
|
||||
|
||||
void __attribute__((optimize("O0"))) foo(void)
|
||||
{
|
||||
printk("foo called\n");
|
||||
}
|
||||
|
||||
void __attribute__((optimize("O0"))) fail(void)
|
||||
{
|
||||
long a[] = {0};
|
||||
|
||||
printk("should fail after this\n");
|
||||
|
||||
*(a + 2) = (long)&foo;
|
||||
}
|
||||
|
||||
struct k_work work;
|
||||
|
||||
void work_handler(struct k_work *wrk)
|
||||
{
|
||||
printk("work handler\n");
|
||||
|
||||
zassert_true(is_shstk_enabled(), "shadow stack not enabled");
|
||||
}
|
||||
|
||||
ZTEST(cet, test_shstk_work_q)
|
||||
{
|
||||
k_work_init(&work, work_handler);
|
||||
k_work_submit(&work);
|
||||
}
|
||||
|
||||
void intr_handler(const void *p)
|
||||
{
|
||||
printk("interrupt handler\n");
|
||||
|
||||
if (p != NULL) {
|
||||
/* Test one nested level. It should just work. */
|
||||
printk("trying interrupt handler\n");
|
||||
irq_offload(intr_handler, NULL);
|
||||
|
||||
k_sem_give((struct k_sem *)p);
|
||||
} else {
|
||||
printk("interrupt handler nested\n");
|
||||
}
|
||||
}
|
||||
|
||||
void thread_b_entry(void *p1, void *p2, void *p3)
|
||||
{
|
||||
k_sem_take(&thread_b_sem, K_FOREVER);
|
||||
|
||||
irq_offload(intr_handler, &thread_b_irq_sem);
|
||||
|
||||
k_sem_take(&thread_b_irq_sem, K_FOREVER);
|
||||
}
|
||||
|
||||
ZTEST(cet, test_shstk_irq)
|
||||
{
|
||||
k_thread_start(thread_b);
|
||||
|
||||
k_sem_give(&thread_b_sem);
|
||||
|
||||
k_thread_join(thread_b, K_FOREVER);
|
||||
}
|
||||
|
||||
void thread_a_entry(void *p1, void *p2, void *p3)
|
||||
{
|
||||
k_sem_take(&thread_a_sem, K_FOREVER);
|
||||
|
||||
fail();
|
||||
|
||||
zassert_unreachable("should not reach here");
|
||||
}
|
||||
|
||||
ZTEST(cet, test_shstk)
|
||||
{
|
||||
k_thread_start(thread_a);
|
||||
|
||||
expect_fault = true;
|
||||
expect_code = CTRL_PROTECTION_ERRORCODE_NEAR_RET;
|
||||
expect_reason = IV_CTRL_PROTECTION_EXCEPTION;
|
||||
k_sem_give(&thread_a_sem);
|
||||
|
||||
k_sem_take(&error_handler_sem, K_FOREVER);
|
||||
k_thread_abort(thread_a);
|
||||
}
|
||||
#endif /* CONFIG_HW_SHADOW_STACK */
|
||||
|
||||
#ifdef CONFIG_X86_CET_IBT
|
||||
extern int should_work(int a);
|
||||
extern int should_not_work(int a);
|
||||
|
||||
/* Round trip to trick optimisations and ensure the calls are indirect */
|
||||
int do_call(int (*func)(int), int a)
|
||||
{
|
||||
@@ -50,8 +173,10 @@ ZTEST(cet, test_ibt)
|
||||
|
||||
expect_fault = true;
|
||||
expect_code = CTRL_PROTECTION_ERRORCODE_ENDBRANCH;
|
||||
expect_reason = IV_CTRL_PROTECTION_EXCEPTION;
|
||||
do_call(should_not_work, 1);
|
||||
zassert_unreachable("should_not_work did not fault");
|
||||
}
|
||||
#endif /* CONFIG_X86_CET_IBT */
|
||||
|
||||
ZTEST_SUITE(cet, NULL, NULL, NULL, NULL, NULL);
|
||||
|
||||
@@ -17,3 +17,14 @@ tests:
|
||||
filter: CONFIG_X86_64
|
||||
extra_configs:
|
||||
- CONFIG_X86_CET_IBT=y
|
||||
arch.x86.cet.kernel.shstk64:
|
||||
arch_allow: x86
|
||||
filter: CONFIG_X86_64
|
||||
extra_configs:
|
||||
- CONFIG_HW_SHADOW_STACK=y
|
||||
arch.x86.cet.kernel.shstk32:
|
||||
arch_allow: x86
|
||||
filter: not CONFIG_X86_64
|
||||
extra_configs:
|
||||
- CONFIG_DEBUG_COREDUMP=y
|
||||
- CONFIG_HW_SHADOW_STACK=y
|
||||
|
||||
Reference in New Issue
Block a user