Compiler / switcher does not validate non-software-visible pointers
davidchisnall opened this issue · comments
There are two important pointers held in registers that may introduce attack vectors:
- If a function takes more arguments than fit in 6 registers,
ct0
contains a pointer to stack space. - If a function returns a structure that does not fit in registers,
ca0
contains caller stack space to store the result.
Both of these should have RWlgm permissions and be sufficiently large that they can hold the values that the compiler expects. None of the code in the RTOS currently uses this part of the ABI, but before we can the compiler should be fixed so that it checks these on entry and returns -1 if the checks fail. The checks should be:
- The address equals the base.
- The bounds are at least the compiler expected size.
- The base is greater than the address of
csp
[1] on entry. - The permissions are at least the set listed above. This includes a check for store-local, which guarantees that this is part of our stack.
The sequence is likely to look something like:
# Check that address equals base
cgetaddr t1, ca0
cgetbase t2, ca0
bne t1, t2, fail
# Check that base is greater than or equal to stack pointer on entry
blt t2, sp, fail
cgetlen t1, ca0
li t2, {expected size}
blt t1, t2, fail
cgetperm t1, ca0
li t2, 0x7a
bne t1, t2, fail
# Rest of prolog
...
fail:
li a0, -1
li a1, -1
cret
This is quite a long sequence (and will be effectively double this length for functions that both return structures and take on-stack arguments), so we might consider outlining it if it proves to increase code size.
[1] This is a bit fun because compartment entry points may be called from within the compartment and so we don't want to check that it's out of range of CSP.