-
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
[RFC] c18n: New {get,set}context APIs for libunwind #2122
Conversation
Not for libunwind, but for longjmp, which takes two arguments.
Edit: Ignore this comment. c1 does not need to be preserved here.
… On 18 Jun 2024, at 18:53, Domagoj Stolfa ***@***.***> wrote:
@dstolfa commented on this pull request.
In libexec/rtld-elf/rtld_c18n.c:
> @@ -1009,9 +999,11 @@ _rtld_longjmp(struct jmp_args ret, void *rcsp, void **buf)
}
struct jmp_args
-_rtld_unw_setcontext_impl(struct jmp_args ret, void *rcsp, void **buf)
+_rtld_unw_setcontext(struct jmp_args ret, void *rcsp, void **buf)
While I don't think it does any harm, do we need to preserve c1 here?
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you authored the thread.Message ID: ***@***.***>
|
88e3fbd
to
3af16f4
Compare
This looks good to me now, but you should open a PR on https://github.com/CTSRD-CHERI/llvm-project/ and a separate one on this repo for the rtld changes. |
I've created #2123 and CTSRD-CHERI/llvm-project#740. Note that I no longer define the stub no-op assembly functions in-line because that might be difficult to read. |
8e36b3f
to
a359b71
Compare
@jrtc27 @dstolfa I've implemented what we discussed in CTSRD-CHERI/llvm-project#740. |
I pulled the changes down to give them a test, but they don't build. Building CheriBSD on a Morello box fails for lib32:
While building for CHERI-RISC-V fails almost immediately:
|
@dstolfa The build issue has been resolved now and CI is passing. Could you give it another try? |
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've run it on Morello and it seems to work fine. CHERI-RISC-V also builds fine, but I haven't yet tested isolated libunwind builds. Will report back once I do.
/* | ||
* Zeros | ||
*/ | ||
uint16_t zeros; |
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.
Not specifically related to this diff, but what is "zeros" and why is it here?
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 just padding space that must be filled with zeros.
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.
Why?
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.
@jrtc27 So that when you do a wide load (e.g. a capability load) from the caller
field, you can extract the caller for free by using a narrower register (i.e. the w
register on Morello).
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 will document it.
return c18n_is_tramp(pc, (struct trusted_frame *)tf); | ||
} | ||
|
||
static pint_t getC18NState(R &newRegisters, pint_t tf) { |
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.
The use of "get" here feels a little bit weird since it also populates newRegisters
. More of a comment than anything else, I'm not sure what name would make the most sense here.
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.
How about fillC18NState
?
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 fine to me
d3a0850
to
34d6023
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.
I've tested on both Morello and CHERI-RISC-V and both seem to work fine. It might make sense to update the individual reviews once you've addressed the dummy stack comments from the other review unless @jrtc27 has other comments about the specific functionality here.
libexec/rtld-elf/rtld_c18n.c
Outdated
* Push a dummy trusted frame indicating that the current compartment is | ||
* RTLD. | ||
*/ | ||
*--tf = (struct 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.
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.
Yeah I rebased on #2134 to see if everything works together as a whole. This PR remains focused on the unwind-related bits.
The check for benchmark ABI was erroneously added and conflicts with benchmark ABI-only code below.
This is a common pattern and warrants shared code.
The dummy frame indicates that the current compartment is RTLD. Because _rtld_bind may cause domain switches (e.g., via a ifunc resolver which calls a lazily-bound symbol), a frame that correctly identifies the current compartment as RTLD is necessary. The signal handler has also been updated to handle the temporary inconsistency between the untrusted stack and the callee field of the topmost truted frame that result from the changes above.
The current method of popping the topmost trusted frame and restoring it at the end of the function does not correctly identify the current compartment as RTLD. Instead, push a dummy frame that does so.
This prevents a compartment from being able to set its stack to NULL and then trigger a signal that would cause it to be mis-identified as RTLD.
The dummy frame indicates that the current compartment is RTLD. Because _rtld_tlsdesc_dynamic may cause domain transitions (e.g., locking), a frame that correctly identifies the current compartment as RTLD is necessary.
_rtld_unw_getcontext_epilogue is removed because when c18n is not enabled, the trusted stack field of the unwind cursor is unused anyway, so there's no need to fill it. _rtld_unw_setcontext is no longer in assembly because it is now expected to be called before all registers are restored, so it does not need to restore any register. setjmp and longjmp are updated to use the slightly changed API signatures.
Previously, libunwind hard-codes knowledge about the layout of the trusted frame and has read access to the trusted stack. This is fragile and insecure. Now, the task of extracting the relevant registers from the trusted stack is delegated to RTLD, and libunwind no longer has access to the trusted stack. In addition, unify the APIs exposed to setjmp/longjmp and libunwind.
Assembly stubs for _rtld_unw_{get,set}context are removed. Instead, turn calls to these functions into no-ops when they are not defined by RTLD.
Is this superseded by #2123? |
Yes indeed. Closing now. |
Could you update the two PRs relating to this with the new version that's in this PR? That way we don't have out of date PRs which supersede this one, but don't actually have the same code. |
Done! |
This PR is not intended to be merged but merely to collect feedback.
I changed
_unw_setcontext
to call_rtld_unw_setcontext
before restoring the registers. Also,_unw_setcontext
is now marked as a trusted function so no trampoline is involved when entering and exiting it. This ensures that no register is clobbered when setting the context.Assembly stubs for
_rtld_unw_{get,set}context
in libunwind have been removed. Instead, we make calls to these functions behave like no-ops if they are not defined by RTLD.