-
Notifications
You must be signed in to change notification settings - Fork 15
cjal{,r}: always seal return pointers #101
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
base: main
Are you sure you want to change the base?
Conversation
This implements David's proposal at #100 (comment) The RTOS test suite passes, but further review is probably wise.
Background on Backward SentriesThe initial sentry was created to specify the interrupt disposition of the callee - enabling/disabling/inheriting. The backward sentry was created to avoid a potential availability attack by a malicious caller by calling into an interrupt-disabling library: the malicious caller can set up the return address to be the same as the library call's entry point (which is an interrupt-disabling sentry), leading to that non-malicious library being called repeatedly by the malicious caller without re-enabling interrupts. (An aside: Given that sentries are possible entry points, a backward sentry is especially critical: it is created dynamically and produces an arbitrary entry points which are not specified in the export tables. So, if a malicious compartment gets hold of a backwards sentry, it can keep attacking the target of the sentry, forcing it to handle a return when it's not expecting. That's one of the reasons for initially forcing a backwards sentry to be Local so that it cannot be stashed in global memory indefinitely - but that proved to be cumbersome when the stack is in the heap, preventing any spill of backwards sentries.) Background on Tail callA tail call X doesn't create a call frame, and instead re-uses an existing return address to its caller that its callee can use to directly return to its caller skipping X. The interrupt disposition of the caller of X should be restored on the final return. The callee's interrupt status can potentially be different from that of X which can be different from that of the caller of X. Background on OutliningOutlining is the opposite of inlining: you create functions to capture repeated code snippets. In CHERIoT, these outlined functions can potentially be implemented (not sure if it's done currently) as common libraries shared across multiple compartments. Outlined functions necessarily have the same interrupt disposition as that of its invocation, i.e. the caller of the outlined function (as one cannot change the interrupt status in the middle of a call). And to avoid register spills, the outline function's caller's return address register should not be reused for the outline function's return. In particular, if Ideal solutionLet's say we have different instructions to convey different jump types. We can also discuss if they can all be collapsed into one instruction. Here are the main types:
This would work because This is the ideal solution but requires a new instruction. Forcing same opcode for different jumpsIf we are forced to use the same opcode for The proposed solution for forcing same opcode for different jumps (#100 )Create a backwards inheriting sentry that is always created for Such a backwards inheriting sentry can also be used for a I think this solution works, but it might be better overall to spare another opcode for disambiguating this instead of this complex logic and analysis. It would make the overall exception pipeline simpler and would remove all restrictions on the addresses used for I think there's actually no need to seal the return address for unsealed forward address because it necessarily denotes the same compartment (buggy code be damned), making the whole proposal moot. Instead, sealed addresses should only be used for library/cross-compartment calls or returns. But I still think, even if the return addresses are not sealed, one should have different instructions to disambiguate calls and returns that use sentries |
vmurali
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.
I added my review in the conversation
|
@davidchisnall @nwf , what are your objections to a new "Ret" instruction other than RISC-V doesn't have it? Does this free up arbitrary restrictions on the registers passed to tailcalls/outlining calls? Or does it not solve the ambiguity anyway? |
This implements David's proposal at
#100 (comment)
The RTOS test suite passes, but further review is probably wise.
This is not so much intended for immediate merge or propagation to existing CHERIoT targets, but to reduce our divergence, if we can, against the RISC-V Y draft.