-
Notifications
You must be signed in to change notification settings - Fork 201
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Stack overflow protection #1764
Conversation
That's great to see! Just wondering, what are the memory limits for the comm cpu (i.e. max size of uploaded binary) and a running kernel (i.e. allocation of a large array on the stack in a kernel)? |
In However, there might be some other factors that might limit the binary size. For example, the size of the memory region mapped to the SPI flash/ROM (IIRC 16MB for Kasli), and the gateware and other binaries (e.g. bootloader) is also included. The actual size of
The stack size of the kernel depends its binary size. First, kernel CPU region is around 175MB large (from 0x45060000 to 0x4FFFFFF0). Then, the page guard is added after every linker section, effectively after the kernel binary (the dynamic library part). The linker for kernel is written as such.
The guard page is also 4096 bytes long, so the size of the kernel stack is whatever remains of it after the stack guard. I think most of these numbers are the same since #1612. This patch only reduces the kernel stack size by no more than 8192 bytes (stack guard & stack alignment). |
ARTIQ Pull Request
Description of Changes
This patch implements stack overflow protection using guard page, with the aid of physical memory protection (PMP) units from RISC-V.
Linker scripts (Except bootloader)
A symbol
_sstack_guard
is added to each of the linker script (except bootloader). It specifies the start of the stack guard.Both stacks and guard pages are 4k aligned. Guard pages of these stacks are always active. PMP region 2 implements these guard pages.
Thread stacks
When spawning a new thread,
Io
now inflates it stack size by 4k to fit the guard page of the thread. Stacks requested by libfringe are 4k aligned, so the guard page will be 4k aligned as well.The guard page of a thread stack is active only if the context is switched to the thread. Both PMP region 0 & 1 implement these guard pages.
Startup Flow
Satman/Kernel
A PMP region will be enabled to initialize their stack guard during their startup.
Runtime
Same as satman/kernel. In addition, runtime will then transfer control from machine privilege to user privilege. It will remain in user privilege unless PMP regions need to be modified.
Context switch
An environment call will be invoked during context switching (see
arch::swap()
implemented in libfringe). The exception handler then adjusts the PMP regions in machine mode. Finally, it resumes context switching with user privilege.Testing
Main stack guard
Adding the following code after initializing the main stack guard will trigger a CPU load fault.
Important serial output:
Thread stack guard
Spawning a task that initializes a large array will cause an access fault. For example,
It resulted in the following serial output:
The PC value corresponds to the following assembly dump.
So the fault was actually triggered during the initialization of thread in libfringe.
Kernel stack guard
Added the following code after initializing the stack guard in kernel.
After a library is loaded to the kernel, it panics with error messages like such.
Related Issue
libfringe PR
Closes #544
Type of Changes
Steps (Choose relevant, delete irrelevant before submitting)
All Pull Requests
git commit --signoff
, see copyright).Code Changes
Git Logistics
git rebase --interactive
). Merge/squash/fixup commits that just fix or amend previous commits. Remove unintended changes & cleanup. See tutorial.git show
). Format:Licensing
See copyright & licensing for more info.
ARTIQ files that do not contain a license header are copyrighted by M-Labs Limited and are licensed under LGPLv3+.