-
Notifications
You must be signed in to change notification settings - Fork 678
shadow stack: restore x86 shstk VMA earlier during premapped VMAs remap loop #2782
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
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
* shstk_restorer_stack_size() – restorer shadow stack size * shstk_set_restorer_stack() – set restorer shadow stack start Signed-off-by: Igor Svilenkov Bozic <svilenkov@gmail.com> Co-Authored-By: Andrei Vagin <avagin@gmail.com> Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
* shstk_restorer_stack_size(): PAGE_SIZE * shstk_set_restorer_stack(): set restorer temporary shadow stack start Signed-off-by: Igor Svilenkov Bozic <svilenkov@gmail.com> Co-Authored-By: Andrei Vagin <avagin@gmail.com> Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
61e8a76 to
4e0013b
Compare
Member
|
LGTM. Thanks a lot for taking this. |
rppt
reviewed
Oct 17, 2025
rppt
approved these changes
Oct 17, 2025
Member
rppt
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Acked-by: Mike Rapoport rppt@kernel.org
Member
Author
Thank you! ;) |
* default: return whatever passed in
eg. to be used as
shtk_min_mmap_addr(kdat.mmap_min_addr)
* x86: ignore def and return 4G
On x86, CET shadow stack is required to be mapped above 4GiB
On the other hand forcing 4GiB globally would break 32-bit restores.
Co-Authored-By: Andrei Vagin <avagin@gmail.com>
Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
* reserve space for restorer shadow stack * set tmp_shstk at mem, advance mem by PAGE_SIZE * forget the extra PAGE_SIZE (shstk) for premapped VMAs Signed-off-by: Igor Svilenkov Bozic <svilenkov@gmail.com> Co-Authored-By: Andrei Vagin <avagin@gmail.com> [ alex: small code cleanups ] Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
1. create shadow stack vma during vma_remap cycle 2. copy contents from a premapped non-shstk VMA into it 3. unmap premapped non-shstk VMA 4. Mark shstk VMA for remap into the final destination Signed-off-by: Igor Svilenkov Bozic <svilenkov@gmail.com> Co-Authored-By: Andrei Vagin <avagin@gmail.com> Co-Authored-By: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com> [ alex: debugging, rework together with Andrei and code cleanup ] Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
* call shstk_vma_restore() for VMA_AREA_SHSTK in vma_remap() * delete map/copy/unmap from shstk_restore() and keep token setup + finalize * before the loop naturally stopped at cet->ssp-8, so a -8 nudge is required here Signed-off-by: Igor Svilenkov Bozic <svilenkov@gmail.com> Co-Authored-By: Andrei Vagin <avagin@gmail.com> [ alex: small code cleanups ] Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
* add SHSTK_ENABLE=1 toggle
* passes -mshstk to compiler and -z shstk to linker
Example:
$ make -C test/zdtm/static clean
$ make -C test/zdtm/static V=1 SHSTK_ENABLE=1 env00
$ readelf --notes test/zdtm/static/env00 | grep SHSTK
Properties: x86 feature: SHSTK
Signed-off-by: Igor Svilenkov Bozic <svilenkov@gmail.com>
Co-Authored-By: Andrei Vagin <avagin@gmail.com>
Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
Member
|
LGTM. Thanks! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
During our work on arm64 GCS (aka shadow stack) we found (thanks to
sysctl -w kernel.randomize_va_space=0) that the way how we restore x86 shadow stack is not quite correct. I need to dive into details to explain why.During shadow stack restore we abusing so called "premapped" VMAs. It is purely CRIU concept, and we use it to ensure proper CoW restoration for anonymous VMAs. Idea is simple, early on restore we prepare VMAs and fill them with a data from page images. Then, when we start forking processes they can naturally inherit those VMAs and CoW flags will be properly set in the kernel. Of course, this has nothing to do with shadow stack that's why I said "abusing" instead of using. :)
So, basically, for shadow stack we were "premapping" (and, important, NON-shadow stack, but regular anon) VMA with the size
original_shadow_stack_size + 1 page. And intention was simple, we were putting original shadow stack contents to it and one extra page was basically a place holder for a temporary shadow stack we need for restorer PIE to function properly. Then, once we reachvma_remap(vma_entry, args->uffd)loops, we were just skipping those premapped VMAs because at that time we still need them as we restore shadow stack after that loop, but this is the problem. We can't just skip mappings in that loops (criu/criu/pie/restorer.c
Line 1821 in c14c2ae
criu/criu/pie/restorer.c
Line 1845 in c14c2ae
Igor (@svilenkov) noticed, that something fails there on his testing system all the time. This was a hint for us to recheck x86 shadow stack too, but it wasn't failing. Missing piece of puzzle was
sysctl -w kernel.randomize_va_space=0which Igor was using on his testing VM. Enabling this on my x86 machine immediately made x86 shadow stack to fail too. Like this:or like this:
The idea of the right fix belongs to Andrei. We have to restore shadow stack VMA right in vma remap loop. Once it is our turn, we do:
vma_remapfunction to do its job to properlymremapit to the final destinationFixes: #2306