Skip to content

Commit cbb43be

Browse files
wearyzendkalowsk
authored andcommitted
tests: overwrite return address of stack frame
Introduce a test to overwrite the return address in the exception stack frame of a lower-priority thread performing an SVC call. Signed-off-by: Sudan Landge <[email protected]> (cherry picked from commit f80bef3)
1 parent 989499c commit cbb43be

File tree

6 files changed

+129
-0
lines changed

6 files changed

+129
-0
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
cmake_minimum_required(VERSION 3.20.0)
4+
5+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
6+
project(arm_user_stack_test)
7+
8+
target_sources(app PRIVATE src/main.c)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
CONFIG_ARM_MPU=y
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
CONFIG_ARM_MPU=y
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
CONFIG_ZTEST=y
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
* Copyright The Zephyr Project Contributors
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifdef CONFIG_FPU_SHARING
8+
#include <math.h>
9+
#endif
10+
#include <zephyr/ztest.h>
11+
#include <zephyr/ztest_error_hook.h>
12+
#include <zephyr/syscall_list.h>
13+
14+
struct k_thread th0, th1;
15+
K_THREAD_STACK_DEFINE(stk0, 2048);
16+
K_THREAD_STACK_DEFINE(stk1, 2048);
17+
18+
ZTEST_BMEM int attack_stack[128];
19+
ZTEST_BMEM uint64_t sys_ret; /* 64 syscalls take result address in r0 */
20+
21+
volatile int kernel_secret;
22+
volatile int *const attack_sp = &attack_stack[128];
23+
const int sysno = K_SYSCALL_K_UPTIME_TICKS;
24+
k_tid_t low_tid, hi_tid;
25+
26+
void k_sys_fatal_error_handler(unsigned int reason, const struct arch_esf *pEsf)
27+
{
28+
ztest_test_pass();
29+
k_thread_abort(low_tid);
30+
31+
/* This check is to handle a case where low prio thread has started and
32+
* resulted in a fault while changing the sp but
33+
* the high prio thread is not created yet
34+
*/
35+
if (hi_tid) {
36+
k_thread_abort(hi_tid);
37+
}
38+
}
39+
40+
void attack_entry(void)
41+
{
42+
printf("Call %s from %s\n", __func__, k_is_user_context() ? "user" : "kernel");
43+
/* kernel_secret can only be updated in privilege mode so updating it here should result in
44+
* a fault. If it doesn't we fail the test.
45+
*/
46+
kernel_secret = 1;
47+
48+
printf("Changed the kernel_secret so marking test as failed\n");
49+
ztest_test_fail();
50+
51+
k_thread_abort(low_tid);
52+
k_thread_abort(hi_tid);
53+
}
54+
55+
void low_fn(void *arg1, void *arg2, void *arg3)
56+
{
57+
#ifdef CONFIG_FPU_SHARING
58+
double x = 1.2345;
59+
double y = 6.789;
60+
61+
/* some random fp stuff so that an extended stack frame is saved on svc */
62+
zassert_equal(x, 1.2345);
63+
zassert_equal(y, 6.789);
64+
#endif
65+
printf("Call %s from %s\n", __func__, k_is_user_context() ? "user" : "kernel");
66+
attack_stack[0] = 1;
67+
__asm__ volatile("mov sp, %0;"
68+
"1:;"
69+
"ldr r0, =sys_ret;"
70+
"ldr r6, =sysno;"
71+
"ldr r6, [r6];"
72+
"svc 3;"
73+
"b 1b;" ::"r"(attack_sp));
74+
}
75+
76+
void hi_fn(void *arg1, void *arg2, void *arg3)
77+
{
78+
printf("Call %s from %s\n", __func__, k_is_user_context() ? "user" : "kernel");
79+
while (1) {
80+
attack_sp[-2] = (int)attack_entry;
81+
k_msleep(1);
82+
}
83+
}
84+
85+
ZTEST(arm_user_stack_test, test_arm_user_stack_corruption)
86+
{
87+
low_tid = k_thread_create(&th0, stk0, K_THREAD_STACK_SIZEOF(stk0), low_fn, NULL, NULL, NULL,
88+
2,
89+
#ifdef CONFIG_FPU_SHARING
90+
K_INHERIT_PERMS | K_USER | K_FP_REGS,
91+
#else
92+
K_INHERIT_PERMS | K_USER,
93+
#endif
94+
K_NO_WAIT);
95+
96+
k_msleep(6); /* let low_fn start looping */
97+
hi_tid = k_thread_create(&th1, stk1, K_THREAD_STACK_SIZEOF(stk1), hi_fn, NULL, NULL, NULL,
98+
1, K_INHERIT_PERMS | K_USER, K_NO_WAIT);
99+
100+
k_thread_join(&th0, K_FOREVER);
101+
k_thread_join(&th1, K_FOREVER);
102+
}
103+
104+
ZTEST_SUITE(arm_user_stack_test, NULL, NULL, NULL, NULL, NULL);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
common:
2+
tags:
3+
- arm
4+
tests:
5+
arch.arm.user.stack:
6+
filter: CONFIG_CPU_CORTEX_M
7+
extra_configs:
8+
- CONFIG_USERSPACE=y
9+
arch.arm.user.stack.float:
10+
filter: CONFIG_CPU_CORTEX_M and CONFIG_CPU_HAS_FPU
11+
extra_configs:
12+
- CONFIG_USERSPACE=y
13+
- CONFIG_FPU=y
14+
- CONFIG_FPU_SHARING=y

0 commit comments

Comments
 (0)