Skip to content

Commit 42fa3ee

Browse files
committed
Use stack high water mark to optimise zeroing.
This is implemented in Sail but not yet merged: CHERIoT-Platform/cheriot-sail#8 It can be enabled by setting a board config option 'stack_high_water_mark' to true. We need to think more about potential attacks based on unexpected stack pointer bounds or passing pointers to stack. Includes a fix for #62: don't rely on zero_stack setting \base to \top. The zero_stack macro in the switcher did not meet the claim in the comment that the base register would end up pointing to the top (it was not true if the top was not 32-byte aligned). Rather than fix this I've removed the claim in the comment and adjusted the places that call it not rely on this property.
1 parent f615565 commit 42fa3ee

File tree

5 files changed

+110
-30
lines changed

5 files changed

+110
-30
lines changed

sdk/core/loader/boot.cc

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -811,13 +811,18 @@ namespace
811811
Debug::log("New thread's trusted stack is {}", threadTStack);
812812
threadTStack->mepcc = pcc;
813813
threadTStack->cgp = cgp;
814-
threadTStack->csp = allocateStack(config.stackSize);
815-
Debug::log("New thread's stack is {}", threadTStack->csp);
814+
auto stack = allocateStack(config.stackSize);
815+
threadTStack->csp = stack;
816+
Debug::log("New thread's stack is {}", stack);
816817
// Enable previous level interrupts and set the previous exception
817818
// level to M mode.
818819
threadTStack->mstatus =
819820
(priv::MSTATUS_MPIE |
820821
(priv::MSTATUS_PRV_M << priv::MSTATUS_MPP_SHIFT));
822+
#ifdef CONFIG_MSHWM
823+
threadTStack->mshwm = stack.top();
824+
threadTStack->mshwmb = stack.base();
825+
#endif
821826
threadTStack->frameoffset = offsetof(TrustedStack, frames[1]);
822827
threadTStack->frames[0].calleeExportTable =
823828
build(compartment.exportTable);

sdk/core/switcher/entry.S

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,18 @@
66

77
.include "assembly-helpers.s"
88

9+
# Symbolic names for the satck high water mark registers until
10+
# the assembler knows about them.
11+
12+
/**
13+
* Machine-mode stack high water mark CSR
14+
*/
15+
#define CSR_MSHWM 0xbc1
16+
/**
17+
* Machine mode stack high water mark stack base CSR
18+
*/
19+
#define CSR_MSHWMB 0xbc2
20+
921
#define MAX_FAULTS_PER_COMPARTMENT_CALL 1024
1022

1123
# Global for the sealing key. Stored in the switcher's code section.
@@ -105,11 +117,10 @@ switcher_scheduler_entry_csp:
105117
.endm
106118

107119
/**
108-
* Zero the stack. The three operands are the base address (modified during
109-
* this call, will point at the top at the end), the top address, and a scratch
110-
* register to use. The base must be a capability but it must be provided
111-
* without the c prefix because it is used as both a capability and integer
112-
* register. Top and scratch are both clobbered.
120+
* Zero the stack. The three operands are the base address, the top address,
121+
* and a scratch register to use. The base must be a capability but it must
122+
* be provided without the c prefix because it is used as both a capability
123+
* and integer register. All three registers are clobbered.
113124
*/
114125
.macro zero_stack base top scratch
115126
addi \scratch, \top, -32
@@ -181,8 +192,24 @@ compartment_switcher_entry:
181192
cgetbase s1, csp
182193
csetaddr csp, csp, s1
183194
sub s1, s0, s1
184-
csetboundsexact csp, csp, s1
185-
zero_stack sp, s0, gp
195+
csetboundsexact ct2, csp, s1
196+
csetaddr csp, ct2, s0
197+
#ifdef CONFIG_MSHWM
198+
// read and align the stack high water mark
199+
csrr gp, CSR_MSHWM
200+
and gp, gp, ~0xf
201+
// skip zeroing if high water mark >= stack poitner
202+
bge t2, sp, after_zero
203+
// use stack high water mark as base address for zeroing
204+
// XXX could be out of bounds / unrepresentable if bad csp?
205+
csetaddr ct2, csp, gp
206+
#endif
207+
zero_stack t2, s0, gp
208+
after_zero:
209+
#ifdef CONFIG_MSHWM
210+
// store new stack top as stack high water mark
211+
csrw CSR_MSHWM, sp
212+
#endif
186213
#endif // CONFIG_NO_SWITCHER_SAFETY
187214
.Lout:
188215
// Fetch the sealing key
@@ -315,6 +342,12 @@ exception_entry_asm:
315342
csc ct0, TrustedStack_offset_mepcc(csp)
316343
csrr t1, mstatus
317344
csw t1, TrustedStack_offset_mstatus(csp)
345+
#ifdef CONFIG_MSHWM
346+
csrr t1, CSR_MSHWM
347+
csw t1, TrustedStack_offset_mshwm(csp)
348+
csrr t1, CSR_MSHWMB
349+
csw t1, TrustedStack_offset_mshwmb(csp)
350+
#endif
318351
csrr t1, mcause
319352
csw t1, TrustedStack_offset_mcause(csp)
320353

@@ -394,6 +427,12 @@ exception_entry_asm:
394427
.Linstall_context:
395428
clw x1, TrustedStack_offset_mstatus(csp)
396429
csrw mstatus, x1
430+
#ifdef CONFIG_MSHWM
431+
clw x1, TrustedStack_offset_mshwm(csp)
432+
csrw CSR_MSHWM, x1
433+
clw x1, TrustedStack_offset_mshwmb(csp)
434+
csrw CSR_MSHWMB, x1
435+
#endif
397436
cspecialw mepcc, ct2
398437
csb zero, TrustedStack_offset_inForcedUnwind(csp)
399438
// c2 is csp, which will be loaded last and will overwrite the trusted
@@ -694,9 +733,21 @@ exception_entry_asm:
694733
// Update the current frame offset.
695734
csw t2, TrustedStack_offset_frameoffset(ctp)
696735
#ifndef CONFIG_NO_SWITCHER_SAFETY
736+
#ifdef CONFIG_MSHWM
737+
// read and align the stack high water mark
738+
// we will use this as base address for stack clearing
739+
// note that it cannot be greater than stack top as we
740+
// we set it to stack top when we pushed to trusted stack frame
741+
csrr tp, CSR_MSHWM
742+
and tp, tp, ~0xf
743+
#else
697744
cgetbase tp, csp
745+
#endif
698746
cgetaddr t1, csp
699747
csetaddr ct2, csp, tp
700748
zero_stack t2, t1, tp
749+
#ifdef CONFIG_MSHWM
750+
csrw CSR_MSHWM, sp
751+
#endif
701752
#endif // CONFIG_NO_SWITCHER_SAFETY
702753
cret

sdk/core/switcher/trusted-stack-assembly.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,20 @@ EXPORT_ASSEMBLY_OFFSET(TrustedStack, c14, 14 * 8)
2121
EXPORT_ASSEMBLY_OFFSET(TrustedStack, c15, 15 * 8)
2222
EXPORT_ASSEMBLY_OFFSET(TrustedStack, mstatus, 16 * 8)
2323
EXPORT_ASSEMBLY_OFFSET(TrustedStack, mcause, (16 * 8) + 4)
24+
#ifdef CONFIG_MSHWM
25+
EXPORT_ASSEMBLY_OFFSET(TrustedStack, mshwm, 17 * 8)
26+
EXPORT_ASSEMBLY_OFFSET(TrustedStack, mshwmb, (17 * 8) + 4)
27+
28+
// Size of everything up to this point
29+
#define TSTACK_REGFRAME_SZ (18 * 8)
30+
// frameoffset, inForcedUnwind and padding
31+
#define TSTACK_HEADER_SZ 16
32+
#else
2433
// Size of everything up to this point
25-
#define TSTACK_REGFRAME_SZ ((16 * 8) + (2 * 4))
34+
#define TSTACK_REGFRAME_SZ ((16 * 8) + (2* 4))
2635
// frameoffset, inForcedUnwind and padding
2736
#define TSTACK_HEADER_SZ 8
37+
#endif
2838
// The basic trusted stack is the size of the save area, 8 bytes of state for
2939
// unwinding information, and then a single trusted stack frame used for the
3040
// unwind state of the initial thread. (7 * 8) is the size of TrustedStackFrame

sdk/core/switcher/tstack.h

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -44,33 +44,42 @@ struct TrustedStackFrame
4444
template<size_t NFrames>
4545
struct TrustedStackGeneric
4646
{
47-
void *mepcc;
48-
void *c1;
49-
void *csp;
50-
void *cgp;
51-
void *c4;
52-
void *c5;
53-
void *c6;
54-
void *c7;
55-
void *c8;
56-
void *c9;
57-
void *c10;
58-
void *c11;
59-
void *c12;
60-
void *c13;
61-
void *c14;
62-
void *c15;
63-
size_t mstatus;
64-
size_t mcause;
47+
void *mepcc;
48+
void *c1;
49+
void *csp;
50+
void *cgp;
51+
void *c4;
52+
void *c5;
53+
void *c6;
54+
void *c7;
55+
void *c8;
56+
void *c9;
57+
void *c10;
58+
void *c11;
59+
void *c12;
60+
void *c13;
61+
void *c14;
62+
void *c15;
63+
size_t mstatus;
64+
size_t mcause;
65+
#ifdef CONFIG_MSHWM
66+
uint32_t mshwm;
67+
uint32_t mshwmb;
68+
#endif
6569
uint16_t frameoffset;
6670
/**
6771
* Flag indicating whether this thread is in the process of a forced
6872
* unwind. If so, this is one, otherwise it is zero.
6973
*/
7074
uint8_t inForcedUnwind;
7175
// Padding up to multiple of 16-bytes.
72-
uint8_t pad0;
73-
uint16_t padding[2];
76+
uint8_t padding[
77+
#ifdef CONFIG_MSHWM
78+
13
79+
#else
80+
5
81+
#endif
82+
];
7483
/**
7584
* The trusted stack. There is always one frame, describing the entry
7685
* point. If this is popped then we have run off the stack and the thread

sdk/xmake.lua

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,11 @@ rule("firmware")
232232
add_defines("SIMULATION")
233233
end
234234

235+
if board.stack_high_water_mark then
236+
print("using stack high water mark")
237+
add_defines("CONFIG_MSHWM")
238+
end
239+
235240
-- Build the MMIO space for the board
236241
local mmio = ""
237242
local mmio_start = 0xffffffff

0 commit comments

Comments
 (0)