Skip to content

Conversation

@HeatCrab
Copy link
Collaborator

@HeatCrab HeatCrab commented Dec 13, 2025

User mode tasks require kernel stack isolation to prevent malicious or corrupted user stack pointers from compromising kernel memory during interrupt handling. Without this protection, a user task could set its stack pointer to an invalid or controlled address, causing the ISR to write trap frames to arbitrary memory locations.

Stack isolation is implemented by using the mscratch register as a discriminator between machine mode and user mode execution contexts. The ISR entry performs a blind swap with mscratch: for machine mode tasks (mscratch=0), the swap is immediately undone to restore the kernel stack pointer. For user mode tasks, the swap provides the kernel stack while preserving the user stack pointer in mscratch. The interrupt frame structure is extended to 36 words with frame[33] dedicated to stack pointer storage. Task initialization configures mscratch appropriately during the first dispatch by checking the MPP field in mstatus.

[umode] Phase 1: Testing Kernel Stack Isolation

[umode] Test 1a: sys_tid() with normal SP
[umode] PASS: sys_tid() returned 2

[umode] Test 1b: sys_tid() with malicious SP
[umode] PASS: sys_tid() succeeded, ISR correctly used kernel stack

[umode] Test 1c: sys_uptime() with normal SP
[umode] PASS: sys_uptime() returned 4

[umode] Phase 1 Complete: Kernel stack isolation validated

[umode] ========================================

[umode] Phase 2: Testing Security Isolation

[umode] Action: Attempting to read 'mstatus' CSR from U-mode.
[umode] Expect: Kernel Panic with 'Illegal instruction'.

[EXCEPTION] Illegal instruction epc=0x800002F0

Test code and the outputs validates that system calls succeed even when invoked with a malicious stack pointer (0xDEADBEEF), confirming the ISR correctly uses the kernel stack from mscratch rather than the user-controlled stack pointer. All existing tests continue to pass, demonstrating that the isolation mechanism does not affect machine mode task execution.

Related to #53

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 5 files

@HeatCrab HeatCrab marked this pull request as draft December 13, 2025 13:28
@HeatCrab HeatCrab force-pushed the u-mode/basic-support branch 2 times, most recently from 9801050 to afcfd14 Compare December 13, 2025 14:15
@HeatCrab HeatCrab marked this pull request as ready for review December 13, 2025 14:21
Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 7 files

Prompt for AI agents (all 1 issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="arch/riscv/boot.c">

<violation number="1" location="arch/riscv/boot.c:333">
P3: Comment claims `ISR_CONTEXT_SIZE` is &quot;used inline&quot; but the macro is not actually used - the value `144` is hardcoded. Consider either using the macro via extended asm operands (as the original code did) or updating the comment to reflect the actual implementation.</violation>
</file>

Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR

User mode tasks require kernel stack isolation to prevent malicious or
corrupted user stack pointers from compromising kernel memory during
interrupt handling. Without this protection, a user task could set its
stack pointer to an invalid or controlled address, causing the ISR to
write trap frames to arbitrary memory locations.

This commit implements stack isolation using the mscratch register as a
discriminator between machine mode and user mode execution contexts. The
ISR entry performs a blind swap with mscratch: for machine mode tasks
(mscratch=0), the swap is immediately undone to restore the kernel stack
pointer. For user mode tasks (mscratch=kernel_stack), the swap provides
the kernel stack while preserving the user stack pointer in mscratch.

The interrupt frame structure is extended to 36 words with frame[33]
dedicated to stack pointer storage. Task initialization zeroes the
entire extended frame and correctly sets the initial stack pointer in
frame[FRAME_SP] to support the new restoration path. The FRAME_SP
enumeration constant replaces magic number usage for improved code
clarity. Additionally, FRAME_GP and FRAME_TP are used instead of array
indices for consistency.

The ISR implementation now includes separate entry and restoration paths
for each privilege mode. The M-mode path maintains mscratch=0 throughout
execution. The U-mode path saves the user stack pointer from mscratch
immediately after frame allocation and restores mscratch to the kernel
stack address before returning to user mode.

Task initialization was updated to configure mscratch appropriately
during the first dispatch. The dispatcher checks the MPP field in mstatus
and sets mscratch to zero for machine mode tasks or to the kernel stack
base for user mode tasks.

The user mode output system call was modified to bypass the asynchronous
logger queue, which could cause out-of-order output due to race
conditions between the logger task and user tasks. Direct UART output
ensures strict FIFO ordering for test output clarity.

Documentation has been updated to reflect the new 36-word interrupt frame
layout and initialization logic.

Testing validates that system calls succeed even when invoked with a
malicious stack pointer (0xDEADBEEF), confirming the ISR correctly uses
the kernel stack from mscratch rather than the user-controlled stack
pointer.
@HeatCrab HeatCrab force-pushed the u-mode/basic-support branch from afcfd14 to fe3574c Compare December 13, 2025 14:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant