/* * Copyright (c) 2022, Google Inc. All rights reserved * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include "btitest.h" .section .text /* Fault handler to return where BTI calls fail. * On return from the caught Branch Target exception, PSTATE.BTYPE will still * be set according to the last branch taken. Therefore we need to land on a * BTI jc to be compatible with all callers - and avoid another immediate * Branch Target exception. */ .Lbtitest_callee_fault: bti jc mov x0, #ERR_FAULT ret /** * int btitest_bl(void) - Use bl to call each of the test functions * * This calls each of the test functions using bl and a relative offset, * which should always be allowed. The functions are expected to all return 0. * * Returns The first non-zero return code, or 0 if all functions pass. */ FUNCTION(btitest_bl) push lr, xzr bl btitest_callee_nop cbnz x0, .Lerror bl btitest_callee_bti cbnz x0, .Lerror bl btitest_callee_bti_c cbnz x0, .Lerror bl btitest_callee_bti_j cbnz x0, .Lerror bl btitest_callee_bti_jc cbnz x0, .Lerror bl btitest_callee_paciasp cbnz x0, .Lerror bl btitest_callee_pacibsp .Lerror: pop lr, xzr ret /** * int btitest_blr(int) - Use blr to call the passed function * * Returns The called function's return value */ FUNCTION(btitest_blr) push lr, xzr bl get_callee blr x0 pop lr, xzr ret /** * int btitest_br(int) - Use br to call the passed function via the x0 register * * Returns The called function's return value */ FUNCTION(btitest_br) push lr, xzr bl get_callee pop lr, xzr br x0 /** * int btitest_br_x16(int) - Use br to call the passed function via the x16 * register * * Returns The called function's return value */ FUNCTION(btitest_br_x16) push lr, xzr bl get_callee pop lr, xzr mov x16, x0 br x16 /** * int btitest_br_x17(int) - Use br to call the passed function via the x17 * register * * Returns The called function's return value */ FUNCTION(btitest_br_x17) push lr, xzr bl get_callee pop lr, xzr mov x17, x0 br x17 /** * int btitest_callee_nop(void) - Function with nop instruction * * Returns ERR_FAULT if the BTI check fails. * Return 0 if the BTI check passes. */ LOCAL_FUNCTION(btitest_callee_nop) set_fault_handler .Lbtitest_callee_fault nop mov x0, #0 ret /** * int btitest_callee_bti(void) - Function with bti instruction * * Returns ERR_FAULT if the BTI check fails. * Return 0 if the BTI check passes. */ LOCAL_FUNCTION(btitest_callee_bti) set_fault_handler .Lbtitest_callee_fault bti mov x0, #0 ret /** * int btitest_callee_bti_c(void) - Function with bti c instruction * * Returns ERR_FAULT if the BTI check fails. * Return 0 if the BTI check passes. */ LOCAL_FUNCTION(btitest_callee_bti_c) set_fault_handler .Lbtitest_callee_fault bti c mov x0, #0 ret /** * int btitest_callee_bti_j(void) - Function with bti j instruction * * Returns ERR_FAULT if the BTI check fails. * Return 0 if the BTI check passes. */ LOCAL_FUNCTION(btitest_callee_bti_j) set_fault_handler .Lbtitest_callee_fault bti j mov x0, #0 ret /** * int btitest_callee_bti_jc(void) - Function with bti jc instruction * * Returns ERR_FAULT if the BTI check fails. * Return 0 if the BTI check passes. */ LOCAL_FUNCTION(btitest_callee_bti_jc) set_fault_handler .Lbtitest_callee_fault bti jc mov x0, #0 ret /** * int btitest_callee_paciasp(void) - Function with paciasp instruction * * Returns ERR_FAULT if the BTI check fails. * Return 0 if the BTI check passes. */ LOCAL_FUNCTION(btitest_callee_paciasp) set_fault_handler .Lbtitest_callee_fault paciasp mov x0, #0 autiasp ret /** * int btitest_callee_pacibsp(void) - Function with pacibsp instruction * * Returns ERR_FAULT if the BTI check fails. * Return 0 if the BTI check passes. */ LOCAL_FUNCTION(btitest_callee_pacibsp) set_fault_handler .Lbtitest_callee_fault pacibsp mov x0, #0 autibsp ret /** * int btitest_callee_error(void) - Error function which always fails * * This is valid as any jump target. * * Returns ERR_INVALID_ARGS unconditionally. */ LOCAL_FUNCTION(btitest_callee_error) bti jc mov x0, #ERR_INVALID_ARGS ret /** * get_callee(int) - Get the address of the callee function. * * Converts the passed function index into the function address. * This is done here to avoid using the C compiler to get function addresses - * the compiler may insert veneers or indirection under some situations (e.g. * for CFI) and break the specific landing pad instructions needed to test BTI. * * Return 0 if the index is not recognised, otherwise the function address. */ LOCAL_FUNCTION(get_callee) cmp w0, #BTITEST_CALLEE_NOP bne .Ltry_bti adr x0, btitest_callee_nop ret .Ltry_bti: cmp w0, #BTITEST_CALLEE_BTI bne .Ltry_bti_c adr x0, btitest_callee_bti ret .Ltry_bti_c: cmp w0, #BTITEST_CALLEE_BTI_C bne .Ltry_bti_j adr x0, btitest_callee_bti_c ret .Ltry_bti_j: cmp w0, #BTITEST_CALLEE_BTI_J bne .Ltry_bti_jc adr x0, btitest_callee_bti_j ret .Ltry_bti_jc: cmp w0, #BTITEST_CALLEE_BTI_JC bne .Ltry_paciasp adr x0, btitest_callee_bti_jc ret .Ltry_paciasp: cmp w0, #BTITEST_CALLEE_PACIASP bne .Ltry_pacibsp adr x0, btitest_callee_paciasp ret .Ltry_pacibsp: cmp w0, #BTITEST_CALLEE_PACIBSP bne .Lunknown adr x0, btitest_callee_pacibsp ret .Lunknown: /* Return error function which unconditionally fails any test */ adr x0, btitest_callee_error ret