diff --git a/arch/aarch64/reloc.h b/arch/aarch64/reloc.h index b1b68c725..a50a80281 100644 --- a/arch/aarch64/reloc.h +++ b/arch/aarch64/reloc.h @@ -22,3 +22,22 @@ #define CRTJMP(pc,sp) __asm__ __volatile__( \ "mov sp,%1 ; br %0" : : "r"(pc), "r"(sp) : "memory" ) + +#ifdef MUSL_EXPERIMENTAL_PAC +#define TARGET_RELOCATE(dso, type, reladdr, sym, addend, is_phase_2) \ + do_target_reloc(dso, type, reladdr, sym, addend, is_phase_2) +#define DO_TARGET_RELR(dso, dyn) do_pauth_relr(dso, dyn) + +int do_target_reloc(int type, uint64_t* reladdr, uint64_t base, + uint64_t symval, uint64_t addend, int is_phase_2); + +void do_pauth_relr(uint64_t base, uint64_t* dyn); + +#define GETFUNCSYM(fp, sym, got) do { \ + hidden void sym(); \ + *(fp) = sym; } while(0) + +#define FPTR_CAST(fty, p) \ + ((fty)__builtin_ptrauth_sign_unauthenticated((void*)(p), 0, 0)) + +#endif diff --git a/conf.sh b/conf.sh new file mode 100755 index 000000000..bb5bdb584 --- /dev/null +++ b/conf.sh @@ -0,0 +1,6 @@ +export CC=/usr/bin/clang + +TARGET=aarch64-linux-gnu +export CFLAGS="-O0 --target=$TARGET -mcpu=cortex-a78c -DMUSL_EXPERIMENTAL_PAC" +export LDFLAGS="--target=$TARGET -fuse-ld=lld" +./configure --enable-debug --host=$TARGET diff --git a/ldso/dynlink.c b/ldso/dynlink.c index ceca3c98a..6928041e8 100644 --- a/ldso/dynlink.c +++ b/ldso/dynlink.c @@ -19,6 +19,9 @@ #include #include #include +#ifdef MUSL_EXPERIMENTAL_PAC_INIT_FINI +#include +#endif #include "pthread_impl.h" #include "fork_impl.h" #include "dynlink.h" @@ -45,6 +48,18 @@ static void (*error)(const char *, ...) = error_noop; #define container_of(p,t,m) ((t*)((char *)(p)-offsetof(t,m))) #define countof(a) ((sizeof (a))/(sizeof (a)[0])) +#ifndef TARGET_RELOCATE +#define TARGET_RELOCATE(...) 0 +#endif + +#ifndef DO_TARGET_RELR +#define DO_TARGET_RELR(...) +#endif + +#ifndef FPTR_CAST +#define FPTR_CAST(fty, p) ((fty)(p)) +#endif + struct debug { int ver; void *head; @@ -111,6 +126,7 @@ struct dso { size_t *got; } *funcdescs; size_t *got; + size_t* pauth; char buf[]; }; @@ -549,6 +565,8 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri #endif break; default: + if (TARGET_RELOCATE(type, reloc_addr, (size_t)base, sym_val, addend, head == &ldso)) + break; error("Error relocating %s: unsupported relocation type %d", dso->name, type); if (runtime) longjmp(*rtld_fail, 1); @@ -697,6 +715,7 @@ static void *map_library(int fd, struct dso *dso) unsigned char *map=MAP_FAILED, *base; size_t dyn=0; size_t tls_image=0; + size_t notes[8] = {}; size_t i; ssize_t l = read(fd, buf, sizeof buf); @@ -737,6 +756,13 @@ static void *map_library(int fd, struct dso *dso) ph->p_memsz < DEFAULT_STACK_MAX ? ph->p_memsz : DEFAULT_STACK_MAX; } + } else if (ph->p_type == PT_NOTE && ph->p_memsz >= 32) { + for (unsigned in = 0; in < sizeof(notes)/sizeof(notes[0]); ++in) { + if (notes[in] == 0) { + notes[in] = ph->p_vaddr; + break; + } + } } if (ph->p_type != PT_LOAD) continue; nsegs++; @@ -858,6 +884,13 @@ static void *map_library(int fd, struct dso *dso) dso->base = base; dso->dynv = laddr(dso, dyn); if (dso->tls.size) dso->tls.image = laddr(dso, tls_image); + for (unsigned in = 0; in < sizeof(notes)/sizeof(notes[0]) && notes[in]; ++in) { + uint32_t* pnote = laddr(dso, notes[in]); + if (pnote[2] == NT_GNU_ABI_TAG && !strncmp((char*)&pnote[3], "ARM", 4)) { + dso->pauth = (size_t*)&pnote[4]; + break; + } + } free(allocated_buf); return map; noexec: @@ -1050,6 +1083,16 @@ static void makefuncdescs(struct dso *p) } } +static int check_pauth_abi_compatible(struct dso* first, struct dso* second) +{ + if (first->pauth == second->pauth) + return 1; + if (first->pauth == 0 || second->pauth == 0) + return 0; + return first->pauth[0] == second->pauth[0] && + first->pauth[1] == second->pauth[1]; +} + static struct dso *load_library(const char *name, struct dso *needed_by) { char buf[2*NAME_MAX+2]; @@ -1182,6 +1225,11 @@ static struct dso *load_library(const char *name, struct dso *needed_by) close(fd); if (!map) return 0; + if (!check_pauth_abi_compatible(head, &temp_dso)) { + dprintf(2, "incompatible PAuth ABI between %s and %s\n", head->name, name); + return 0; + } + /* Avoid the danger of getting two versions of libc mapped into the * same process when an absolute pathname was used. The symbols * checked are chosen to catch both musl and glibc, and to avoid @@ -1419,6 +1467,9 @@ static void reloc_all(struct dso *p) do_relocs(p, laddr(p, dyn[DT_RELA]), dyn[DT_RELASZ], 3); if (!DL_FDPIC) do_relr_relocs(p, laddr(p, dyn[DT_RELR]), dyn[DT_RELRSZ]); + if (p != &ldso) { + DO_TARGET_RELR((uint64_t)p->base, p->dynv); + } if (head != &ldso && p->relro_start != p->relro_end) { long ret = __syscall(SYS_mprotect, laddr(p, p->relro_start), @@ -1485,7 +1536,16 @@ void __libc_exit_fini() if (dyn[0] & (1<