relink_special_ibl_xfer() may overwrite first instruction of target block on AArch64 (CRASH)
This bug was spotted by a user and posted at https://groups.google.com/g/dynamorio-users/c/Ai5fFN9Q6iE
AArch64 uses two instructions to patch an IBL: LDR
followed by BR
.
However, both AArch32 and x86 use one jump instruction and the IBL patching functions assume only a one instruction jump patch. This can result in AArch64 applications crashing as summarised below.
Code generated by emit_special_ibl_xfer()
on AArch64 (using -loglevel 4
):
client_ibl_xfer:
. . .
0x0000000041e424b8 f9403f81 ldr +0x78(%x28)[8byte] -> %x1
0x0000000041e424bc d61f0020 br %x1
clean_call_save:
0x0000000041e424c0 a90007e0 stp %x0 %x1 -> (%sp)[16byte]
. . .
When relink_special_ibl_xfer()
is called the BR
instruction of the LDR
/BR
pair overwrites:
. . .
0x0000000041e424b8 f9403f81 ldr +0x78(%x28)[8byte] -> %x1 <-- ldr +0x78(%x28)[8byte] -> %x1
0x0000000041e424bc d61f0020 br %x1 <-- ldr +0x78(%x28)[8byte] -> %x1
clean_call_save:
0x0000000041e424c0 a90007e0 stp %x0 %x1 -> (%sp)[16byte] <-- br %x1 <-- STP overwritten!
. . .
We have not seen this bug cause failure before due to NOP
padding used for e.g. cache alignment which depends on the machine's cache line size:
client_ibl_xfer:
. . .
0x00000000310124ac f9403f81 ldr +0x78(%x28)[8byte] -> %x1 <-- ldr +0x78(%x28)[8byte] -> %x1
0x00000000310124b0 d61f0020 br %x1 <-- ldr +0x78(%x28)[8byte] -> %x1
0x00000000310124b4 d503201f nop <-- br %x1
0x00000000310124b8 d503201f nop
0x00000000310124bc d503201f nop
clean_call_save:
0x00000000310124c0 a90007e0 stp %x0 %x1 -> (%sp)[16byte] <-- NOT overwritten because of NOP padding above.
. . .