diff --git a/libexec/rtld-elf/aarch64/rtld_c18n_asm.S b/libexec/rtld-elf/aarch64/rtld_c18n_asm.S index f4be1a31214d..4f9dfa1a2bb6 100644 --- a/libexec/rtld-elf/aarch64/rtld_c18n_asm.S +++ b/libexec/rtld-elf/aarch64/rtld_c18n_asm.S @@ -226,9 +226,14 @@ TRAMP(tramp_save_caller) #endif /* - * Save the number of unused return value registers. + * Save the address that the callee should return to. */ -1: movz x13, #0 /* To be patched at runtime */ +1: adr c13, #0 /* To be patched at runtime */ + /* + * Save the number of unused return value registers in the 2 least + * significant bits of the register. + */ +2: add x13, x13, #0 /* To be patched at runtime */ /* Push frame */ stp x12, x13, [TRUSTED_STACK, #-(CAP_WIDTH * 14)]! @@ -244,11 +249,12 @@ TRAMP(tramp_save_caller) #endif #undef TRUSTED_STACK -2: ldr c19, #0 /* To be patched at runtime */ +3: ldr c19, #0 /* To be patched at runtime */ TRAMPEND(tramp_save_caller) -PATCH_POINT(tramp_save_caller, ret_args, 1b) -PATCH_POINT(tramp_save_caller, target, 2b) +PATCH_POINT(tramp_save_caller, cookie, 1b) +PATCH_POINT(tramp_save_caller, ret_args, 2b) +PATCH_POINT(tramp_save_caller, target, 3b) TRAMP(tramp_call_hook) 1: ldr c18, #0 /* To be patched at runtime */ @@ -438,7 +444,8 @@ TRAMP(tramp_pop_frame) * * Use subs instead of cmp to clear a register tag. */ - subs x16, x11, #0b01 + and x16, x11, #0b11 + subs x17, x16, #0b01 csel c0, czr, c0, hi csel c1, czr, c1, hs @@ -465,9 +472,9 @@ TRAMP(tramp_pop_frame) * - c13: Bottom of caller's stack (scalar) * - c14: Bottom of caller's stack * - c15: Current top of caller's stack - * - c16: Comparison result (scalar) + * - c16: Logical operation result (scalar) + * - c17: Comparison result (scalar) */ - mov x17, xzr mov x18, xzr /* diff --git a/libexec/rtld-elf/aarch64/rtld_c18n_machdep.c b/libexec/rtld-elf/aarch64/rtld_c18n_machdep.c index 176249c8fd36..fbd4d4d0878e 100644 --- a/libexec/rtld-elf/aarch64/rtld_c18n_machdep.c +++ b/libexec/rtld-elf/aarch64/rtld_c18n_machdep.c @@ -73,6 +73,7 @@ tramp_compile(void **entry, const struct tramp_data *data) #undef IMPORT uint32_t *buf = *entry; + uint32_t *cookie_patch; size_t size = 0; int to_clear; bool executive = cheri_getperm(data->target) & CHERI_PERM_EXECUTIVE; @@ -99,7 +100,16 @@ tramp_compile(void **entry, const struct tramp_data *data) #define PATCH_MOV(tramp, name, value) \ do { \ - *PATCH_POINT(tramp, name) |= ((uint16_t)value) << 5; \ + uint32_t _value = (value); \ + _value = ((_value & 0xffff) << 5); \ + *PATCH_POINT(tramp, name) |= _value; \ + } while (0) + +#define PATCH_ADD(tramp, name, value) \ + do { \ + uint32_t _value = (value); \ + _value = ((_value & 0xfff) << 10); \ + *PATCH_POINT(tramp, name) |= _value; \ } while (0) #define PATCH_LDR_IMM(tramp, name, offset) \ @@ -111,6 +121,16 @@ tramp_compile(void **entry, const struct tramp_data *data) sizeof(void *)) & 0x1ffff0) << 1; \ } while(0) +#define PATCH_ADR(point, target) \ + do { \ + uint32_t _offset = \ + (ptraddr_t)(target) - (ptraddr_t)(point); \ + _offset = \ + ((_offset & 0x3) << 29) | \ + ((_offset & 0x1ffffc) << 3); \ + *(point) |= _offset; \ + } while (0) + header.target = data->target; COPY_DATA(header); @@ -124,9 +144,10 @@ tramp_compile(void **entry, const struct tramp_data *data) *entry = buf; COPY(save_caller); + cookie_patch = PATCH_POINT(save_caller, cookie); PATCH_LDR_IMM(save_caller, target, 0); if (data->sig.valid) - PATCH_MOV(save_caller, ret_args, data->sig.ret_args); + PATCH_ADD(save_caller, ret_args, data->sig.ret_args); if (hook) { COPY(call_hook); @@ -165,6 +186,7 @@ tramp_compile(void **entry, const struct tramp_data *data) COPY(invoke_res); } + PATCH_ADR(cookie_patch, buf); COPY(pop_frame); if (hook) { diff --git a/libexec/rtld-elf/rtld_c18n.c b/libexec/rtld-elf/rtld_c18n.c index a4c3ea7c7eb5..f83814d74fb9 100644 --- a/libexec/rtld-elf/rtld_c18n.c +++ b/libexec/rtld-elf/rtld_c18n.c @@ -480,7 +480,8 @@ get_rstk(unsigned index) struct trusted_frame { ptraddr_t next; - ptraddr_t reserved; + uint8_t ret_args : 2; + ptraddr_t cookie : 62; /* * INVARIANT: This field contains the top of the caller's stack when the * caller was last entered.