Skip to content
This repository has been archived by the owner on Mar 24, 2022. It is now read-only.

Fix incorrect globals/sigstack allocation layout #401

Merged
merged 3 commits into from
Jan 24, 2020

Conversation

acfoltzer
Copy link
Contributor

Most of this patch is actually to fix up the tests that were erroneously succeeding because of this bug. The core of the fix is here in mmap.rs:

-        let sigstack = globals + host_page_size();
+        let sigstack = globals + region.limits.globals_size + host_page_size();

This was causing the signal stack to begin one page after the start of the globals section, regardless of how big the globals are. This mostly wasn't causing problems because the default globals size is a page, and we were still adding in a page for the guard, meaning the segments didn't actually overlap with default Limits. However, the guard page for the signal stack was missing, and configurations with larger globals sizes could end up overlapping the signal stack, potentially allowing guests to observe residual signal stack values.

The lack of a signal stack guard page was also making it so that tests running in debug mode would succeed, even though the signal handler was overflowing its stack into the globals page. To make those tests pass with the correct memory layout, the signal stack size is now configurable and set higher by default on debug builds (cfg(debug_assertions)). On release mode, the stack use is fine as the problematic series of stack allocations get optimized into some straightforward copies, so we continue to use SIGSTKSZ as a default in that configuration.

Finally, I added a test that tries to write to the sigstack guard page, improved the "is this a fatal fault address?" method, and made sure that all tests run correctly in release mode.

iximeow
iximeow previously approved these changes Jan 24, 2020
Most of this patch is actually to fix up the tests that were erroneously succeeding because of this
bug. The core of the fix is here in `mmap.rs`:

```
-        let sigstack = globals + host_page_size();
+        let sigstack = globals + region.limits.globals_size + host_page_size();
```

This was causing the signal stack to begin one page after the start of the globals section,
regardless of how big the globals are. This mostly wasn't causing problems because the default
globals size is a page, and we _were_ still adding in a page for the guard, meaning the segments
didn't actually overlap with default `Limits`. However, the guard page for the signal stack was
missing, and configurations with larger globals sizes could end up overlapping the signal stack,
potentially allowing guests to observe residual signal stack values.

The lack of a signal stack guard page was _also_ making it so that tests running in debug mode would
succeed, even though the signal handler was overflowing its stack into the globals page. To make
those tests pass with the correct memory layout, the signal stack size is now configurable and set
higher by default on debug builds (`cfg(debug_assertions)`). On release mode, the stack use is fine
as the problematic series of stack allocations get optimized into some straightforward copies, so we
continue to use SIGSTKSZ as a default in that configuration.

Finally, I discovered some linking errors with the tests on release mode due to overly-aggressive
stripping, so I had to refactor a couple tests.
Also adds a test to ensure that a fault in the sigstack guard page is fatal
Copy link
Contributor

@iximeow iximeow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

approved once more, with feeling!

@acfoltzer acfoltzer merged commit a88bb29 into master Jan 24, 2020
@acfoltzer acfoltzer deleted the acf/alloc-layout-fix branch January 24, 2020 20:06
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants