Skip to content

Improved stack overflow protection on RISC-V targetsΒ #3674

@gibbz00

Description

@gibbz00

esp-hal has supports stack overflow protection using flip-link on esp32c6 and esp32h2, (unsure why it's limited to only two chips). But from what I can tell, this protection only applies when no heap is involved, and only for the "last" thread in a multithreaded SoC. It would be nice to have a more general stack overflow protection that works on a wider array of chips.

Here's what I've gathered so far on a potential solution: Non-embedded systems normally implement stack overflow protection by using a no access-permission guard-page at the end of a thread's stack region. All esp32 riscv chips seem to have Physical Memory Protection unit (PMP). Perhaps the PMP can be used by the rt crate to set up these guard pages? PMP checks in M-mode is mentioned in the RISC-V Vol. II manual, so this might work at the hardware level:

PMP checks are applied to [...] data accesses in M-mode when the MPRV bit in mstatus is set and the MPP field in mstatus contains S or U. ... Optionally, PMP checks may additionally apply to M-mode accesses, in which case the PMP registers themselves are locked, so that even M-mode software cannot change them until the hart is reset. In effect, PMP can grant permissions to S and U modes, which by default have none, and can revoke permissions from M-mode, which by default has full permissions.

Don't think that there's a negligible performance cost to adding guard pages, apart from reductions in available memory. But the feature and page size should probably be made configurable nonetheless. It may also be worth solving #2390 first, and instead add this functionality upstream. (@romancardenas 😊)

Guard pages are useless if the stack allocation is larger than the guard page itself. A.k.a. the stack clash exploitation, whose mitigation is some sort of stack probing. Basically splitting the allocation into page size wide chunks and doing sw zero, 0(sp) before each. This requires target specific LLVM support, and some enabling in Rust.

Luckily, riscv stack probing has been already been added to LLVM, llvm/llvm-project#117612.

Tracking issue for stack probe support on non-tier-1 targets can be found here rust-lang/rust#43241. And here's an example on how it was added to PowerPC and SystemZ; rust-lang/rust#102328. But due to how it both affects performance, and how it will be enabled in a runtime crate, it would probably need to be passed down as an opt-in compiler flag or the like.

So yeah, what do you think about this so far? Something worth pursuing? Seems like a lot of the groundwork has already been put in place :)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions