-
Notifications
You must be signed in to change notification settings - Fork 249
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
Darwin: Fixup TLV thunk functions during mapping #709
Conversation
b206895
to
3100050
Compare
50ff3b0
to
ec981e5
Compare
Tested on M1 / amd64 macOS. The memory budget for the additional code is a bit generous (196 bytes over the 134 bytes for x86 and the 92 bytes for arm64). I'm not sure whether anything would still need to be done to account for PAC/arm64e, but I'm also very unsure how to test that. |
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.
Thanks! 🙌
This will need some style fixes. The style is documented here.
(Happy to help with tweaking the style once I have a bit more bandwidth, but leaving this note here in the meantime.)
ec981e5
to
245d811
Compare
I tried to fix the style issues -- in case I overlooked some rule, please let me know :) |
dbf12e8
to
4ac5b53
Compare
67b1c59
to
d12a99e
Compare
Rebased, added runtime code to copy over the initial values for the Frida thread, and added somewhat-verbose commit messages describing what's happening. |
03de284
to
252699f
Compare
Within a Mach-O image, each TLV descriptor contains a thunk function pointer to resolve the variable's address, a thread key, and an offset to be used to index into the per-thread area. At runtime the thunk function is invoked, passed a pointer to the TLV descriptor, and returns a pointer to the TLV storage. Add functions to parse these from an Image.
Dyld has a randezvous area in a section named `__DATA,__dyld4`, where it exposes its public API. This includes a pointer to tlv_get_addr at a well-known offset within this section.
These hold the initial values for TLV.
Within a module's image, before loading, the TLV descriptors thunk function is set to _tlv_bootstrap, which calls abort at runtime. The key values are also set to 0 on non-dyld_shared_cache images. We create a new pthread_key at runtime, and store it in each TLV descriptor. Additionally, we fix up the thunk function to tlv_get_addr, which returns a pointer to the variable's storage as ((void**) gsbase)[descriptor->key] + descriptor->offset. We're not handling any non-zero keys in the image, as those are only used within the dyld_shared_cache.
Dyld's tlv_get_addr function retrieves the thread local storage by using a descriptor's key to index into the thread local storage held in gsbase on x86 or TPIDRRO_EL0 on arm64 to retrieve a thread- and module- specific data area to offset into. If this offset-specific area pointer is NULL, it will be lazily allocated by tlv_get_addr through a call to RuntimeState::_instantiateTLVs. This allocates the area, using a size stored in a Dyld-private vector _tlvInfos, and copies over intial data. When a module is loaded through Dyld, it stores the nesseary size along with the key in _tlvInfos. Since we don't have a way to insert our newly generated key into this array through public (and hence stable) APIs, we pre-allocate and initialize the per-thread area for the initial thread in the runtime.
252699f
to
923a776
Compare
Landed in 5f81484. Thanks! 🙌 |
Wonderful, thank you so much! |
See-also: frida/frida#2395