Skip to content

aarch64: initial pauth support#5

Open
kovdan01 wants to merge 1 commit intomasterfrom
v1.2.5-pauth
Open

aarch64: initial pauth support#5
kovdan01 wants to merge 1 commit intomasterfrom
v1.2.5-pauth

Conversation

@kovdan01
Copy link

  1. Support PAuth dynamic relocs:

    • R_AARCH64_AUTH_ABS64;
    • R_AARCH64_AUTH_RELATIVE (including relr);
    • R_AARCH64_JUMP_SLOT (sign slot contents if DT_AARCH64_PAC_PLT dynamic tag is present);
    • R_AARCH64_AUTH_GLOB_DAT;
    • R_AARCH64_AUTH_TLSDESC.
  2. Support signed function pointers in init/fini arrays (with optional address discrimination enabled).

  3. Check PAuth core info compatibility for DSOs in the process.

TODO:

  1. Support function pointer type discrimination. This should not be enabled under normal conditions though, and pauthtest ABI in LLVM intentionally does not include that.

  2. Do not store unsigned LR in memory in raw assembly code: see [PAC] Do not store unsigned LR in memory in raw assembly code #3.

  3. Support non-null __ehdr_start. See in-code comment in __dls2 function in src/dynlink.c for details.

  4. Enhance test coverage: current proof-of-concept is good enough to run llvm-test-suite, but we lack test coverage of some parts of musl.

1. Support PAuth dynamic relocs:

   - R_AARCH64_AUTH_ABS64;
   - R_AARCH64_AUTH_RELATIVE (including relr);
   - R_AARCH64_JUMP_SLOT (sign slot contents if DT_AARCH64_PAC_PLT
     dynamic tag is present);
   - R_AARCH64_AUTH_GLOB_DAT;
   - R_AARCH64_AUTH_TLSDESC.

2. Support signed function pointers in init/fini arrays (with optional
   address discrimination enabled).

3. Check PAuth core info compatibility for DSOs in the process.

TODO:

1. Support function pointer type discrimination. This should not be
   enabled under normal conditions though, and pauthtest ABI in LLVM
   intentionally does not include that.

2. Do not store unsigned LR in memory in raw assembly code: see
   #3.

3. Support non-null `__ehdr_start`. See in-code comment in `__dls2`
   function in src/dynlink.c for details.

4. Enhance test coverage: current proof-of-concept is good enough to run
   llvm-test-suite, but we lack test coverage of some parts of musl.

Co-authored-by: Evgeny Leviant <eleviant@accesssoftek.com>
Co-authored-by: Anatoly Trosinenko <atrosinenko@accesssoftek.com>
@ojhunt
Copy link

ojhunt commented Jul 31, 2025

Does musl perform dynamic load fixups/relocations from within the target process?

@kovdan01
Copy link
Author

Does musl perform dynamic load fixups/relocations from within the target process?

@ojhunt Are you talking about dlopen support? If so, then no, this is not currently supported. We resolve the relocations for the executable which is about to run and from its dependencies. But we don't support loading additional library containing AUTH relocs from within a process which is already running.

@ojhunt
Copy link

ojhunt commented Jul 31, 2025

Does musl perform dynamic load fixups/relocations from within the target process?

@ojhunt Are you talking about dlopen support? If so, then no, this is not currently supported. We resolve the relocations for the executable which is about to run and from its dependencies. But we don't support loading additional library containing AUTH relocs from within a process which is already running.

Ok, so map_library only ever runs prior to user code execution? My concern from going through this code was potential for cross thread attacks on the loader which obviously can't happen if linking only occurs prior to execution starting (including global initializers)

Also, are the dso objects stored in readonly memory?

@ojhunt
Copy link

ojhunt commented Jul 31, 2025

oh, and unrelated to this pr I saw ADDEND_LIMIT is defined as 4096 which is a suspiciously "this is how big pages are" type of constant :D

Copy link

@ojhunt ojhunt left a comment

Choose a reason for hiding this comment

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

In terms of general security attacks the fact the all this code only runs prior to user execution.

There is an something that might be an issue, it does depend on how much control/how restricted your library loading policies are.

There are a number of environment variables that can be used to inject libraries into a process launch prior to user code execution. Corrupt libraries can be used to attack the linker itself, including the data structures and stack state of the library parser.

The data going into and out of reloc_addr in do_relocs present a significant attack vector for such an attack, unprotected data in dso is similarly impacted, dso::ptrauth especially but there are a lot of significant metadata pointers in dso (funcdescs, base, P and Ehdr pointers). Similarly there are unprotected locals in do_relocs that can be used as oracles.

Obviously this is initial support but I just wanted to do an info dump :D

if (prop[1] != 16) return;

/* We do not expect multiple PAuth GNU properties. */
if (dso->pauth != 0) return;
Copy link

Choose a reason for hiding this comment

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

bogus pointer auth state should really produce guaranteed termination.

(I don't recall any ptrauth related bugs in this class, but I recall a number of issues in various OS's where accepting incorrect libraries resulted in incorrect resolution so my presumption is failing to link anything incorrect should always be preferred)

@kovdan01 kovdan01 requested review from asl and atrosinenko July 31, 2025 07:16
@kovdan01
Copy link
Author

Thanks @ojhunt for an extensive review! Yeah, this was mostly intended to serve as a proof-of-concept which allows people to try playing with pauth w/o having to think how to deal with relocation resolving. But it's definitely worth dive into the security-related issues you've pointed out.

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.

2 participants