-
Notifications
You must be signed in to change notification settings - Fork 60
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
c18n: [Draft] Save caller's stack pointer in trusted frame #2060
Closed
Changes from 1 commit
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
5094160
c18n: Save caller's stack pointer in trusted frame
dpgao 59e2ccd
c18n: Support compartment policy files
dpgao 8126e92
c18n: Store compartment's name at the bottom of its stack
dpgao c0fa389
c18n: Trust execve to avoid vfork stack corruption
dpgao b8f6069
c18n: Simplify the trampoline hook interface
dpgao 5b6f3c8
c18n: Option to provide verbose utrace information
dpgao File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
Oops, something went wrong.
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.
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.
Hmm, is libunwind using this? GDB doesn't use the cookie, it matches on the instruction sequence just like for signal frames. That is, I don't understand how
cookie
is different frompc
?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.
libunwind uses this to detect if the current return address is a trampoline and we need to unwind from the trusted frame.
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.
pc
is what the trampoline should return to.cookie
is where the callee should return to. It is an address within the trampoline.Checking the Executive bit of the return address to determine whether we are at a compartment boundary is unreliable because we might be returning into RTLD directly. Checking that the return address matches the cookie gives full assurance, and it also works under the benchmark ABI where everything is Executive.
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.
I guess what I don't understand is that since the cookie is already on the trusted stack, doesn't libunwind have to know before it can even see the cookie that it needs to read from the trusted stack (ECSP) instead of the normal stack (RCSP)? That is, when libunwind is unwinding from the uppermost frame of a compartment back out to the compartment switch, it gets a CLR (and thus PCC) value that points into a trampoline. How does it then decide that for this new frame that it is a compartment frame that is a compartment boundary thus requiring it to go looking in ECSP instead or RCSP for its saved frame? If this were DWARF based, you would look up the FDE/CFI based on the unwound PC value and it would tell you the register for CFA and the offsets of saved registers relative to the CFA. For custom unwinders in GDB including signal frames, GDB does a pattern match against known instructions (e.g. the first 3 instructions CLR points to) to locate a custom unwinder. Does CFP in this case store a scalar address back into the trusted stack (yes, that appears to be true) that libunwind notices is out of the bounds of RCSP and thus assume it might be on the trusted stack? If you aren't doing the bounds check, how do you avoid potential false positives if the stack garbage at the offset of
cookie
in a "normal" frame happens to match PC? If you are doing the bounds check, isn't that alone sufficient to know you are on an alternate stack? (And you could even check if it is in bounds of the trusted stack which libunwind presumably has access to.)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.
libunwind always just blindly checks whether the CLR matches the cookie of the top trusted frame to decide if it's at a compartment boundary. (See https://github.com/CTSRD-CHERI/llvm-project/pull/731/files#diff-6dd9111398b6f61443d5eec566d751eb857a8ee262fe9c5f38c192881826300dR363 which is being used at https://github.com/CTSRD-CHERI/llvm-project/pull/731/files#diff-6dd9111398b6f61443d5eec566d751eb857a8ee262fe9c5f38c192881826300dR602)
The cookie feature was implemented before I started to properly set the CFP value, and your suggestion of checking if CFP is in bounds does seem like a viable idea. @dstolfa What do you think?
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.
That sounds like it could work, I'll prototype it to check.
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.
What I'm after is if we no longer need the cookie value, then we can remove it from the trusted_frame and with a bit of reorganizing have room for the full ecsp in place of the current ptraddr_t for csp.
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.
In particular, it is pretty unusual to restore "part" of a register on a stack frame in an unwinder. DWARF CFI annotations don't (afaik) have a way to describe this kind of case currently for example as stack frames in general save/restore entire registers. It's true that we can't use DWARF to describe this frame today for multiple reasons (dynamically allocated trampolines; no DWARF register number for RCSP and ECSP, just CSP; etc.), but I do think we should aim to create a frame that is generally compatible with how other stack frames generally work as we are less likely to run afoul of assumptions in other unwinders.