-
Notifications
You must be signed in to change notification settings - Fork 41
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
implement shadow stacks #455
Conversation
9ce23d9
to
f1d358a
Compare
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.
This is impressive, thanks for implementing this feature!
There are some open questions, one around the task-switch handling. I left a comment there. The other question is, whether there is a way to enable/disable this feature at boot-time, instead of compile time.
Finally, I found that it uses the old PageRef interface. Since the new one is merged now, this can be re-based on top of latest HEAD.
8a88f3b
to
cc5c763
Compare
I added a patch that tries to detect CET support at runtime by enabling
Done. |
It doesn't look like this change is compatible with the existing #HV handling code. For example, there is code in |
Interesting, thanks for pointing that out, I'll take a look at that. Do you know if there are KVM patches implementing restricted injection that I can test with? |
Unfortunately, there are none that I am aware of. However, I'm happy to review and test any changes you have in our environment which does support restricted injection. Let me know if you want a more thorough description of how the existing #HV handler works and interacts with the IRET flow. |
That's not actually true. The Zen3 architecture supports SEV-SNP but not shadow stacks. |
EPYC Milan (based on Zen 3) supports shadow stacks. I used an EPYC Milan based machine to test these patches. |
You are correct; I was misinformed. |
cc5c763
to
df9dcf0
Compare
I added a patch to adjust the shadow stack in the #HV.
Could you please test my patches on your environment? I tried testing by manually adding |
Other than the specific stack adjustment problem I commented on (the one that's missing), everything appears to work. The other two shadow stack adjustments are correct. And I found another problem with the #HV handler that's not addressed by your other PR so I'll submit a fix for that too. Thanks for prompting me to review this code again! |
Not very relevant yet, but this is not true for TDX case. The CET/shadow stack related MSRs are handled natively for the guest (given that the feature is enabled for the guest during its creation via config) with no host involvement (wont be secure otherwise). TDX module ensures this. So you should be able to enable this for TDX without any host/kvm support (but enabling TD_PARAMS.XFAM[11] || TD_PARAMS.XFAM[12] - matching XSAVE[11],XSAVE[12] for a given guest). |
df9dcf0
to
933f877
Compare
There's still one issue. You changed the size of the exception frame, and you've adjusted most of the places that refer to the stack frame accordingly. However, the reference at line 151 was never updated, and it is now inaccurate. So this sequence:
needs to become
If I make that change locally, then everything works as expected (or would work, if all of the other #HV-related PRs were included). |
933f877
to
b160f27
Compare
Good catch, should be fixed now! Thank you very much for your review! |
2a80d26
to
f1839e7
Compare
@joergroedel I think this PR is ready. |
I just found one additional serious problem. There are functions that generate page table flags to represent different page permissions. However, some of these functions will make the PTE dirty without also marking it writable, and these functions will effectively generate shadow stack permissions, which is not correct for those permission types. Specifically, all methods of |
f1839e7
to
6acf7d7
Compare
Good catch! Should be fixed now. |
6acf7d7
to
3384a09
Compare
When CET is enabled, pages marked as DIRTY but not WRITABLE are treated as special pages used for storing shadow stacks. We must not use this combination of flags for pages not meant to be used for shadow stacks. Signed-off-by: Tom Dohrmann <[email protected]>
The initialization and pt_flags are a bit special for shadow stack pages, so this warrants a new `VirtualMapping` implementations. Signed-off-by: Tom Dohrmann <[email protected]>
This shadow stack is used when not using a task's shadow stack. Signed-off-by: Tom Dohrmann <[email protected]>
The interrupt shadow stack table (ISST) is very similar to the interrupt stack table (IST) except that it contains shadow stack addresses instead of normal stack addresses. Signed-off-by: Tom Dohrmann <[email protected]>
Each task needs to a normal shadow stack and shadow stack used for exception handling. Signed-off-by: Tom Dohrmann <[email protected]>
Some exception handlers will need to update the shadow stack, so they need to know the shadow stack pointer at the time of the exception. Signed-off-by: Tom Dohrmann <[email protected]>
Whenever we update the return address on the shadow stack, we'll also need to update the return address on the shadow stack. Signed-off-by: Tom Dohrmann <[email protected]>
The #HV handler messes with the stack frame and shadow stack needs to be adjusted accordingly. Signed-off-by: Tom Dohrmann <[email protected]>
Unlike the various From and Into implementations, this method can be called in const contexts. Signed-off-by: Tom Dohrmann <[email protected]>
We need to guard against IRQs coming in after switching to the new page tables and before switching to the new stack. Signed-off-by: Tom Dohrmann <[email protected]>
Each task has separate shadow stacks, so we need to switch them when switching tasks. Signed-off-by: Tom Dohrmann <[email protected]>
This enables shadow stacks for the BSP. Signed-off-by: Tom Dohrmann <[email protected]>
This enables shadow stacks on the secondary APs. Signed-off-by: Tom Dohrmann <[email protected]>
This exception handler will be executed when the CPU detects a mismatch between the return address on the stack and the return address on the shadow stack. Signed-off-by: Tom Dohrmann <[email protected]>
Trusted CPUID values are hard to come by, so let's just try to enable CET in CR4 and handle failure gracefully. Signed-off-by: Tom Dohrmann <[email protected]>
3384a09
to
9de01ca
Compare
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.
LGTM.
This PR implements shadow stacks.
Shadow stacks are enabled/disabled at compile time. AFAIK all processors supporting either AMD SEV-SNP or Intel TDX support shadow stacks, so no runtime checks are implemented. This also avoids the pitfall where the hypervisor lies about shadow stack availability to maliciously lower the security of the SVSM.
KVM intercepts accesses to the MSRs used for shadow stacks, so some host-side modifications are required to make this work.
I implemented a #CP exception handler to display diagnostic information when a shadow stack-related issue occurs. We might want to disable this exception handler for release builds and cause a triple fault instead. #CP exceptions are likely a sign of something fishy going on and we might want to terminate the guest just to be sure.
Currently, shadow stacks are disabled by default for a couple of reasons:
We haven't implemented proper user syscalls (usingsyscall
&sysret
) yet and I don't want to hinder any efforts in that direction by forcing a proper syscall implementation to support shadow stacks out of the box. We should probably get syscalls without shadow stacks working first and once that's merged, we can add shadow stack support later and eventually enable shadow stacks by default.enable-gdb
yet, but I suspect this probably needs some additional work.