Skip to content
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

Teach memray to patch libraries that are part of the macOS linker cache #401

Merged
merged 1 commit into from
Jun 16, 2023

Conversation

pablogsal
Copy link
Member

@pablogsal pablogsal commented Jun 14, 2023

No description provided.

@pablogsal pablogsal force-pushed the upterm branch 2 times, most recently from 77eb601 to e961828 Compare June 14, 2023 14:44
@codecov-commenter
Copy link

codecov-commenter commented Jun 14, 2023

Codecov Report

Patch coverage has no change and project coverage change: -0.06 ⚠️

Comparison is base (ae1fdde) 85.00% compared to head (9f63544) 84.94%.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #401      +/-   ##
==========================================
- Coverage   85.00%   84.94%   -0.06%     
==========================================
  Files          29       29              
  Lines        3621     3621              
==========================================
- Hits         3078     3076       -2     
- Misses        543      545       +2     
Flag Coverage Δ
cpp 84.94% <ø> (-0.06%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

see 4 files with indirect coverage changes

☔ View full report in Codecov by Sentry.
📢 Do you have feedback about the report comment? Let us know in this issue.

@pablogsal pablogsal force-pushed the upterm branch 9 times, most recently from b184793 to cb6a9ea Compare June 15, 2023 10:16
@pablogsal pablogsal changed the title Here we go again Teach memray to patch libraries that are part of the macOS linker cache Jun 15, 2023
@pablogsal pablogsal marked this pull request as ready for review June 15, 2023 10:23
@pablogsal pablogsal force-pushed the upterm branch 2 times, most recently from 23d7a19 to b7ff4bf Compare June 15, 2023 11:45
@pablogsal pablogsal requested a review from godlygeek June 15, 2023 13:11
Comment on lines 72 to 87
// Constants for ARM64 architecture
constexpr uint32_t ADRP_MASK = 0x9F000000;
constexpr uint32_t ADRP_INSTRUCTION = 0x90000000;
constexpr uint32_t ADRP_ARG_MASK1 = 0x00FFFFE0;
constexpr uint32_t ADRP_ARG_SHIFT1 = 3;
constexpr uint32_t ADRP_ARG_MASK2 = 0x60000000;
constexpr uint32_t ADRP_ARG_SHIFT2 = 29;
constexpr uint32_t ADRP_ARG_NEGATIVE = 0x00800000;
constexpr int32_t ADRP_ARG_SIGN_EXTEND = 0xFFF00000;
constexpr uint32_t ADD_INSTRUCTION_MASK = 0xDFC00000;
constexpr uint32_t ADD_INSTRUCTION = 0x91000000;
constexpr uint32_t ADD_ARG_MASK = 0x00000FFF;

// Constants for x86_64 architecture
constexpr uint32_t JMP_INSTRUCTION = 0x25ff;
constexpr size_t X86_64_PLT_ENTRY_SIZE = 6;
Copy link
Contributor

@godlygeek godlygeek Jun 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I don't find these named constants particularly helpful. Each one is used in only a single function, their names are super arbitrary (ADRP_ARG_SHIFT2 is a terrible name), and having to jump around in the code to reference them makes it harder to understand this code than it would be if you could just see the constants' values at the point where they're used.

I've taken a swing at making this code more readable - as readable as possible, at least. I also made sort of a lot of changes, considering that I can't easily test this myself - sorry 😅

I believe I've left all of the implementation the same, and just rearranged and renamed things to make what's happening clearer for future readers, but I'll need you to check my work.

Copy link
Contributor

@godlygeek godlygeek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After my changes, this all LGTM, so if my changes all seem correct to you, I think this is good to land.

Since macOS Ventura there have been changes in the way symbols are
included in libraries in the shared linker cache. Specifically, the
symbols that we care about are now stored in a Procedure Linkage Table
(PLT) that does't have an associated GOT in a separate DATA segment that
can be easily read.

To understand this change, let's first explain the purpose of the PLT
and the GOT. In dynamic linking, the PLT is a data structure used to
handle the resolution of function calls to external symbols. It contains
a sequence of instructions that redirect the control flow to the
appropriate symbol implementation. The PLT acts as a dynamic dispatch
table, allowing the resolution of symbols at runtime.

On the other hand, the GOT is a data structure used for
position-independent code. It stores addresses of external symbols that
are referenced by the shared object. The addresses in the GOT are
initially set to point to stub functions, which are small pieces of code
responsible for resolving the actual addresses of the symbols during
runtime. When a function is called, the stub code in the PLT is
executed, looks for the address in the GOT and redirects the control
flow to it.

In previous versions of macOS, the symbols of interest were stored in a
GOT that resided in a separate DATA segment that could be easily read
and modified. This allowed us to know immediately where to patch by
reading the metadata in the relevant DATA section.

However, starting from macOS Ventura, the symbols of interest are no
longer stored in a GOT that we can easily locate by reading DATA
segments.

This commit adds functionality to patch symbols in the
__stubs/__auth_stubs PLT section of shared libraries that are part of
the shared cache. This is necessary because the symbols in this section
point to a Global Offset Table (GOT) that cannot be accessed directly
through data sections. The commit implements the logic to analyze the
assembly code of the PLT stubs and calculate the address of the GOT
entry. The patching process is performed for each hooked function in the
section, applying the necessary modifications to redirect the symbols to
the corresponding hook functions. This allows for proper interception
and manipulation of the function calls in system libraries (like the C++
standard template library) that are part of the linker shared cache.

Signed-off-by: Pablo Galindo <pablogsal@gmail.com>
@pablogsal pablogsal merged commit 173401f into bloomberg:main Jun 16, 2023
28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants