Skip to content

Conversation

@wearyzen
Copy link
Contributor

Initialize the privilege stack and switch PSP to it early in the SVC handler to ensure z_arm_do_syscall does not start on a user-accessible stack frame. Also add a test to validate this behavior.

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 <sudan.landge@arm.com>
@wearyzen wearyzen force-pushed the change_syscall_stack branch from 8a235e3 to db4c1d7 Compare August 28, 2025 09:29
@wearyzen
Copy link
Contributor Author

wearyzen commented Sep 4, 2025

Hi @andyross could you please help with the review of this PR?

ceolin
ceolin previously approved these changes Sep 5, 2025
Copy link
Member

@ceolin ceolin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks right to me.

@wearyzen
Copy link
Contributor Author

wearyzen commented Sep 8, 2025

Hi @andyross, @bbolen, @carlocaione, @galak, @MaureenHelm, @microbuilder, @stephanosio
could you please help with the review of this PR?
Thanks!

@wearyzen
Copy link
Contributor Author

wearyzen commented Sep 8, 2025

Also, requesting @mathieuchopstm for a review since he has been involved with Arm assembly reviews for a while

Copy link
Contributor

@mathieuchopstm mathieuchopstm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll give it a second pass tomorrow. Overall seems OK but I may have missed some details (haven't looked at z_arm_do_syscall either so some things still seem a bit weird to me)

`west build` does not build the `empty_cpu0` application making `west build -b mps2/an521/cpu1 -t run` fail because of the missing empty_cpu0's binary. Signed-off-by: Sudan Landge <sudan.landge@arm.com>
@wearyzen
Copy link
Contributor Author

Hi @mathieuchopstm could you please have another look at this?

Copy link
Contributor

@mathieuchopstm mathieuchopstm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some comments apply to the ARMv7/8-Mainline as well but I did not write them twice.

Additionally, ~L305 of userspace.S says:

 * This function is used to do system calls from unprivileged code. This * function is responsible for the following: * 1) Fixing up bad syscalls * 2) Configuring privileged stack and loading up stack arguments * 3) Dispatching the system call * 4) Restoring stack and calling back to the caller of the SVC

This should be updated to remove (2) since it's now done in SVC handler.

The comment right under also says

 * Note [when using built-in stack limit checking on ARMv8-M]: * At this point PSPLIM is already configured to guard the default (user) * stack, so pushing to the default thread's stack is safe. 

That also needs to be updated.

Initialize the privilege stack and switch PSP to it early in the SVC handler to ensure `z_arm_do_syscall` does not start on a user-accessible stack frame. Signed-off-by: Sudan Landge <sudan.landge@arm.com>
@wearyzen wearyzen force-pushed the change_syscall_stack branch from 86c8de7 to df57f95 Compare September 11, 2025 19:58
@wearyzen
Copy link
Contributor Author

wearyzen commented Sep 12, 2025

@mathieuchopstm I have tried to update the table with more comments, let me know if it looks good.
Also, note that there are some optimizations/redundancies identified in z_arm_do_syscall (e.g. currently it requires return address in both sp[4] and r8) but that will be handled as a follow up PR. This PR is intended only to fix the behavior tested in the 1st commit.
Thanks!

Copy link
Contributor

@mathieuchopstm mathieuchopstm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor non-blockers. LGTM otherwise

* located at *lower* memory area. Since we switch to the top of the
* privileged stack we are safe, as long as the stack can accommodate
* the maximum exception stack frame.
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this whole comment can be removed too since we pivot PSPLIM while in Handler mode?

Suggested change
*/
beq .L_no_padding
/* special handling for padded sf */
bics r1, r3 /* clear the pad bit (priv stack is aligned and doesn't need it) */
adds r2, #4
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd really comment this here, it's not obvious that this is the +4B comment right below talks about

Suggested change
adds r2, #4
adds r2, #4 /* add +4B to compensate padding (see below) */
Comment on lines +648 to +649
/* Calculate original pre-svc user sp with pad */
add r2, #4
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Single line would be sufficient + reword proposal:

Suggested change
/* Calculate original pre-svc user sp with pad */
add r2, #4
add r2, #4 /* take pad into account for pre-svc user sp computation */
@wearyzen wearyzen requested a review from ceolin September 12, 2025 14:13
@nashif nashif merged commit 319c697 into zephyrproject-rtos:main Sep 13, 2025
34 checks passed
@wearyzen wearyzen added backport v3.7-branch Request backport to the v3.7-branch backport v4.1-branch Request backport to the v4.1-branch backport v4.2-branch Request backport to the v4.2-branch labels Sep 15, 2025
{
printf("Call %s from %s\n", __func__, k_is_user_context() ? "user" : "kernel");
while (1) {
attack_sp[-2] = (int)attack_entry;
Copy link
Member

@TaiJuWu TaiJuWu Sep 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain why the index is -2 instead of -3, -1 or 0?
I meet an issue related this, thanks!

The following patch cause this test fail but I have no idea about this issue.

diff --git a/kernel/sched.c b/kernel/sched.c index 37fdbf3bf0b..b119381ef83 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -77,6 +77,7 @@ static ALWAYS_INLINE void *curr_cpu_runq(void) static ALWAYS_INLINE void runq_add(struct k_thread *thread) {	__ASSERT_NO_MSG(!z_is_idle_thread_object(thread)); +	__ASSERT_NO_MSG(!is_thread_dummy(thread));	_priq_run_add(thread_runq(thread), thread); } 
Copy link
Contributor

@mathieuchopstm mathieuchopstm Sep 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

attack_sp is the value of sp upon execution of the svc instruction. The hardware then saves processor context on this stack as follows:
image

Notice that ReturnAddress - the address at which execution should resume upon return from exception - is at offset sp - 0x20 + 0x18 = sp - 8, a.k.a. attack_sp[-2] since attack_sp is a uint32_t* here

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

attack_sp is the value of sp upon execution of the svc instruction. The hardware then saves processor context on this stack as follows: image

Notice that ReturnAddress - the address at which execution should resume upon return from exception - is at offset sp - 0x20 + 0x18 = sp - 8, a.k.a. attack_sp[-2] since attack_sp is a uint32_t* here

Got it, thanks for your detailed explanation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: Architectures area: ARM ARM (32-bit) Architecture backport v3.7-branch Request backport to the v3.7-branch backport v4.1-branch Request backport to the v4.1-branch backport v4.2-branch Request backport to the v4.2-branch platform: ARM Arm Limited

6 participants