Skip to content

fix: Strip PAC bits from return addresses in POSIX crash handler#315

Draft
awforsythe wants to merge 1 commit into
developfrom
aforsythe/chore/posix-crash-pac-bits
Draft

fix: Strip PAC bits from return addresses in POSIX crash handler#315
awforsythe wants to merge 1 commit into
developfrom
aforsythe/chore/posix-crash-pac-bits

Conversation

@awforsythe

Copy link
Copy Markdown
Contributor

ARM64 has a security feature called Pointer Authentication Codes (PAC), where the CPU cryptographically signs address values, encoding the signature in the upper bits of the 64-bit value. It can then verify these addresses before jumping to them, to detect stack manipulation etc. at the hardware level.

The SDK's in-process crash handler for POSIX reads return addresses as it walks the stack frame. When running arm64 Linux builds in Docker, I noticed that these addresses weren't being correctly resolved to loaded modules for shared libraries.

As it turns out, module resolution was failing because the upper bits were set by PAC, causing the resolved address to land outside the load range of the module. Masking out these upper bits to preserve only the lower 48 bits resolved the issue in my tests.

ARM64 has a security feature called Pointer Authentication Codes (PAC),
where the CPU cryptographically signs address values, encoding the
signature in the upper bits of the 64-bit value. It can then verify
these addresses before jumping to them, to detect stack manipulation
etc. at the hardware level.

The SDK's in-process crash handler for POSIX reads return addresses as
it walks the stack frame. When running arm64 Linux builds in Docker, I
noticed that these addresses weren't being correctly resolved to loaded
modules for shared libraries.

As it turns out, module resolution was failing because the upper bits
were set by PAC, causing the resolved address to land outside the load
range of the module. Masking out these upper bits to preserve only the
lower 48 bits resolved the issue in my tests.
@awforsythe

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7dac37e8c8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// bits, so we need to mask to 48-bit virtual address space to end up with the
// actual address within the relevant module.
uint64_t raw_ret = reinterpret_cast<uint64_t>(ret_addr);
raw_ret &= 0x0000ffffffffffff;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve VA bits when stripping PAC

On AArch64 Linux processes that opt in to 52-bit user VAs (for example, executable mappings above 0x0000ffffffffffff), this hard-coded 48-bit mask truncates legitimate address bits before crash processing. write_modules() records full uintptr_t ranges from /proc/self/maps, so the truncated frame address will no longer fall inside the module range and symbolication will report the frame as unknown; use an architecture PAC-strip instruction/kernel PAC mask or derive the active VA width instead of assuming 48 bits.

Useful? React with 👍 / 👎.

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.

1 participant