blob: f2e1c73faec49495e03d7ef8fd8d0be0f09e1f58 [file]
/*
* 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.
*/
/* Tests for ARM64 FEAT_BTI (Branch Target Identification)
* This is a mandatory CPU feature at ARM-A v8.5. Prior to that level, the
* BTI instructions are treated as NOPs and there is no enforcement.
* The test here will check either case, based on build configuration and
* runtime target support.
* Since this is an ARM64 feature, this should not be built for other arches.
*/
#ifndef ARCH_ARM64
#error BTI is an ARM64 feature
#endif
#include "btitest.h"
#include <arch/ops.h>
#include <err.h>
#include <lib/unittest/unittest.h>
#include <lk/init.h>
#include <stdio.h>
/** Assembly relative function call test of all BTI-relevant calls.
*/
int btitest_bl(void);
/* Assembly indirect call functions, using all BTI-relevant calls.
* BR via x16 and x17 is often used by linkers for veneers and has some
* additional handling described in the ARM Architecture Reference Manual,
* Table D8-36 (IYWFHD).
* The passed func_idx should be one of the BTITEST_CALLEE_ macros, which covers
* the landing pad instruction types given in the ARM Architecture Reference
* Manual, Table D8-37 (ICNBPL).
*/
int btitest_blr(int func_idx);
int btitest_br_x16(int func_idx);
int btitest_br_x17(int func_idx);
int btitest_br(int func_idx);
/* Get the expected return code when a BTI access should be trapped */
static int bti_trap_code(void) {
#ifdef KERNEL_BTI_ENABLED
if (arch_bti_supported()) {
return ERR_FAULT;
}
#endif
/* No BTI, or not enabled - faults are not detected */
return 0;
}
TEST(btitest, supported) {
if (!arch_bti_supported()) {
trusty_unittest_printf("[ INFO ] BTI is not supported\n");
GTEST_SKIP();
}
EXPECT_EQ(true, arch_bti_supported());
test_abort:;
}
/* Smoke-test the callee functions; they should return 0 when called with BL */
TEST(btitest, smoke) {
EXPECT_EQ(0, btitest_bl());
}
TEST(btitest, nop) {
/* Fault on jump or call to non-bti target */
EXPECT_EQ(bti_trap_code(), btitest_br(BTITEST_CALLEE_NOP));
EXPECT_EQ(bti_trap_code(), btitest_blr(BTITEST_CALLEE_NOP));
EXPECT_EQ(bti_trap_code(), btitest_br_x16(BTITEST_CALLEE_NOP));
EXPECT_EQ(bti_trap_code(), btitest_br_x17(BTITEST_CALLEE_NOP));
}
TEST(btitest, bti) {
/* Fault on any jump or call to non-target bti */
EXPECT_EQ(bti_trap_code(), btitest_br(BTITEST_CALLEE_BTI));
EXPECT_EQ(bti_trap_code(), btitest_blr(BTITEST_CALLEE_BTI));
EXPECT_EQ(bti_trap_code(), btitest_br_x16(BTITEST_CALLEE_BTI));
EXPECT_EQ(bti_trap_code(), btitest_br_x17(BTITEST_CALLEE_BTI));
}
TEST(btitest, bti_c) {
/* Call or branch via x16/17 to a call target is valid */
EXPECT_EQ(0, btitest_blr(BTITEST_CALLEE_BTI_C));
EXPECT_EQ(0, btitest_br_x16(BTITEST_CALLEE_BTI_C));
EXPECT_EQ(0, btitest_br_x17(BTITEST_CALLEE_BTI_C));
/* Fault on branch to call target */
EXPECT_EQ(bti_trap_code(), btitest_br(BTITEST_CALLEE_BTI_C));
}
TEST(btitest, bti_j) {
/* Any branch to jump target is valid */
EXPECT_EQ(0, btitest_br(BTITEST_CALLEE_BTI_J));
EXPECT_EQ(0, btitest_br_x16(BTITEST_CALLEE_BTI_J));
EXPECT_EQ(0, btitest_br_x17(BTITEST_CALLEE_BTI_J));
/* Fault on call to jump target */
EXPECT_EQ(bti_trap_code(), btitest_blr(BTITEST_CALLEE_BTI_J));
}
TEST(btitest, bti_jc) {
/* Either branch type allowed to call and jump target */
EXPECT_EQ(0, btitest_br(BTITEST_CALLEE_BTI_JC));
EXPECT_EQ(0, btitest_br_x16(BTITEST_CALLEE_BTI_JC));
EXPECT_EQ(0, btitest_br_x17(BTITEST_CALLEE_BTI_JC));
EXPECT_EQ(0, btitest_blr(BTITEST_CALLEE_BTI_JC));
}
TEST(btitest, pacisp) {
if (!arch_pac_address_supported()) {
trusty_unittest_printf("[ INFO ] PAC is not supported\n");
GTEST_SKIP();
}
/* PACIASP is a valid target for all branch types */
EXPECT_EQ(0, btitest_br(BTITEST_CALLEE_PACIASP));
EXPECT_EQ(0, btitest_br_x16(BTITEST_CALLEE_PACIASP));
EXPECT_EQ(0, btitest_br_x17(BTITEST_CALLEE_PACIASP));
EXPECT_EQ(0, btitest_blr(BTITEST_CALLEE_PACIASP));
/* PACIBSP is a valid target for all branch types */
EXPECT_EQ(0, btitest_br(BTITEST_CALLEE_PACIBSP));
EXPECT_EQ(0, btitest_br_x16(BTITEST_CALLEE_PACIBSP));
EXPECT_EQ(0, btitest_br_x17(BTITEST_CALLEE_PACIBSP));
EXPECT_EQ(0, btitest_blr(BTITEST_CALLEE_PACIBSP));
test_abort:;
}
PORT_TEST(btitest, "com.android.kernel.btitest");