Skip to content
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

Update the stack protection document #17

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 39 additions & 9 deletions Kernel configurations for stack memory protection.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
**SUMMARY**

Various stack memory protection mechanisms in Linux are provided to support data integrity of both kernel and user space memory (prevention), as well as traceability of stack memory usage during execution (detection).

These mechanisms include the following:
Expand All @@ -16,20 +18,48 @@ Examples of kernel features supporting user space stack memory protection:
* CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL
* GCC plugin to initialize variables sent by reference to zero, leaving no assumptions on the calling function

2. Kernel space stack protection – Examples of kernel features supporting kernel space stack memory protection:

* CONFIG_STACKPROTECTOR
* CONFIG_STACKPROTECTOR_STRONG
* CONFIG_STACKPROTECTOR_STRONG
* Stack protection in gcc compiler must be enabled

2. Kernel space stack protection – Examples of kernel features supporting kernel space stack memory protection:

* CONFIG_SCHED_STACK_END_CHECK
* CONFIG_SCHED_STACK_END_CHECK
* Detects stack corruption on calls to schedule()
* In case end-of-stack corruption is detected, always panic

* CONFIG_VMAP_STACK
* CONFIG_VMAP_STACK
* Add guard pages to virtually mapped kernel stacks, allowing earlier detection of kernel stack overflows
* Unlike CONFIG_SCHED_STACK_END_CHECK, this option prevents writes beyond the allocated stack
* The offending thread can be terminated without need to panic

* CONFIG_GCC_PLUGIN_STACKLEAK
* Poison kernel stack before returning from syscalls; it's mainly intended for security, however in safety context it can help in detecting uninitialized stack variables.

* CONFIG_GCC_PLUGIN_STACKLEAK
* Poison kernel stack before returning from syscalls
* CONFIG_TREAD_INFO_IN_TASK
* Moves thread information off the stack and into the task struct for protection of task info, particularly during context switch.

* CONFIG_TREAD_INFO_IN_STACK
* Moves thread information off the stack and into the task struct for protection of task info, particularly during context switch
**ANALYSIS**
* A process/thread will always have a kernel-siede component and optionally a user-space side part, which is the typical case of applications.
* Each side has its own call stack
* The user-side call stack is managed according to how the application/library binary has been compiled
* The kernel-side stack is managed according to how the kernel has been compiled
* The userspace-side stack is exposed to corruption primarily coming from:
* application
* libraries linked in by the application
* memory interference coming from low level kernel mechanisms (this is relatively less likely to happen undetected)
* The kernel-space side is exposed to corruption from anything that runs with kernel privilege
* Adding stackprotection does generate overhead
* The available kernel options (STACKPROTECTOR and STACKPROTECTOR_STRONG) rely on heuristics to decide which functions should receive canaries hardening and which shouldn't.
* The compiler, however, supports also a third option (e.g., gcc's -fstack-protector-all) which allows adding protection to all of them.


**CONSIDERATIONS**
* Assuming that a userspace program has been designed and implemented correctly, and that the same can be said for the libraries it uses, stack protection is less useful as a runtime error detection tool, for an end product, and more as a debugging tool during development and testing.
* Other applications that might not have been designed with the same quality criteria are prevented from interfering by the way userspace memory is mapped: a program can only see (and interfere with) the memory it has been assigned.
* In kernel space, on the other hand, different modules with different level of trust are exposed to each other.
* Even if a module was developed and implemented correctly, it is exposed to the interference from another module that doesn't meet the same quality criteria.
* Here monitoring for stack corruption at runtime is more critical and has a higher ROI, in terms of improved confidence vs. overhead introduced.
* In particular, by enabling VMAP_STACK, it is possible to make the system more resilient to failures, and to increase the confidence that it can be trusted to take some corrective actions (for example terminating the offending task and entering safe mode).
* Enabling full function coverage for stack canaries reduces further the chances of having undetected stack corruption. This option is not currently available in the kernel, however it can be added easily. When activated, though, it can cause (at least on on ARM64) stack overflow, because of the additional space required. This can be avoided by increasing the stack size (doubled).
* Whether adding full stack canraries support is feasible or not needs to be investigated [ongoing] and results might differ from platform to platform, however it is normally expected that a userspace program will spend most of its time executing its own code, rather than waiting for syscalls to complete. Perhaps the best way to judge the feasibility of the solution is to gauge the increase in execution time and latency for each desired use-case.
35 changes: 0 additions & 35 deletions kernel-configurations-for-stack-memory-protection.md

This file was deleted.