Open
Description
All trampolines in aarch64 do not backup the local variable register. https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/xray/xray_trampoline_AArch64.S#L4
this is unsound in tailcall functions that use function pointer.
Since tailcall trampoline (it's actually exit trampoline, because #141051) does not backup x9 register, it is possible to corrupt x9 during an xray rt call. the br instruction will then jump to corrupted address.
I can reproduce the crash using the following code
#include <stdint.h>
typedef struct Func {
int(*ptr)(
unsigned long a0,
unsigned long a1,
unsigned long a2,
unsigned long a3,
unsigned long a4,
unsigned long a5,
unsigned long a6,
unsigned long a7
);
} func_t;
__attribute__ ((noinline))
int fx(
unsigned long a0,
unsigned long a1,
unsigned long a2,
unsigned long a3,
unsigned long a4,
unsigned long a5,
unsigned long a6,
unsigned long a7
) {
return a0
+ a1
- a2
* a3
/ a4
^ a5
& a6
<< a7
;
}
__attribute__ ((noinline))
int foo(
unsigned long a0,
unsigned long a1,
unsigned long a2,
unsigned long a3,
unsigned long a4,
unsigned long a5,
unsigned long a6,
unsigned long a7,
struct Func *f
) {
unsigned long n1 = a1 + a2;
unsigned long n2 = a3 - a4;
return ((*f).ptr)(
n1,
n2 ? a1 : a2,
a2,
a3,
a4,
a5,
a6,
a7
);
}
int main() {
struct Func func = { fx };
foo(
1,
2,
3,
4,
5,
6,
7,
8,
&func
);
}
and
$ clang foo.c -O2 -fxray-instrument -fxray-instruction-threshold=1 -fuse-ld=lld
$ env XRAY_OPTIONS="patch_premain=true verbosity=1 xray_mode=xray-basic" ./a.out
==15386==XRay: Log file in 'xray-log.a.out.JQTDQR'
fish: Job 1, 'env XRAY_OPTIONS="patch_premain…' terminated by signal SIGSEGV (Address boundary error)