diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h index 1fbab854a51b0ee5872b9f23991c3f0ae72fb9b3..e5bb00d793ce1062a1d985b5682429bac65d2f8d 100644 --- a/arch/arm64/include/asm/thread_info.h +++ b/arch/arm64/include/asm/thread_info.h @@ -17,6 +17,7 @@ struct task_struct; #include #include #include +#include typedef unsigned long mm_segment_t; @@ -47,8 +48,13 @@ struct thread_info { #endif }; +#ifdef CONFIG_ARM64_PTR_AUTH #define thread_saved_pc(tsk) \ - ((unsigned long)(tsk->thread.cpu_context.pc)) + ptrauth_strip_insn_pac((unsigned long)(tsk->thread.cpu_context.pc)) +#else +#define thread_saved_pc(tsk) \ + ((unsigned long)(tsk->thread.cpu_context.pc)) +#endif #define thread_saved_sp(tsk) \ ((unsigned long)(tsk->thread.cpu_context.sp)) #define thread_saved_fp(tsk) \ diff --git a/arch/arm64/kernel/alternative.c b/arch/arm64/kernel/alternative.c index c56cec242274e9e498489e537d4f0e673e4ffe1e..11bb5bf9e2e0fa4b43ee49cd4ce62ed32ebebdd9 100644 --- a/arch/arm64/kernel/alternative.c +++ b/arch/arm64/kernel/alternative.c @@ -17,6 +17,10 @@ #include #include +#ifdef CONFIG_ARM64_PTR_AUTH_FWD_CFI +#include +#endif + #define __ALT_PTR(a,f) ((void *)&(a)->f + (a)->f) #define ALT_ORIG_PTR(a) __ALT_PTR(a, orig_offset) #define ALT_REPL_PTR(a) __ALT_PTR(a, alt_offset) @@ -164,9 +168,13 @@ static void __nocfi __apply_alternatives(void *alt_region, bool is_module, if (alt->cpufeature < ARM64_CB_PATCH) alt_cb = patch_alternative; - else + else { alt_cb = ALT_REPL_PTR(alt); - +#ifdef CONFIG_ARM64_PTR_AUTH_FWD_CFI + alt_cb = pauth_pacia(alt_cb, __builtin_get_modifier_bytype(alternative_cb_t)); +#endif + } + alt_cb(alt, origptr, updptr, nr_inst); if (!is_module) { diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index 34ef70877de45abb1e2e9d9a93ce7e54b41df08d..2bda25bd01912e09b7a4490d35477bd617c46fcb 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -145,6 +145,11 @@ int main(void) DEFINE(PTRAUTH_USER_KEY_APGA, offsetof(struct ptrauth_keys_user, apga)); DEFINE(PTRAUTH_KERNEL_KEY_APIA, offsetof(struct ptrauth_keys_kernel, apia)); BLANK(); +#ifdef CONFIG_ARM64_PTR_AUTH_FWD_CFI + DEFINE(GIC_HANDLE_IRQ_TYPEID, __builtin_get_modifier_bytype(void (*)(struct pt_regs *))); + DEFINE(KERNEL_INIT_TYPEID, __builtin_get_modifier_bytype(int (*)(void *))); +#endif + #endif return 0; } diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index d5bc1dbdd2fda84cd1e6e9508c07be5b41fae793..9751536802c63c70710c1177723b6e1da8854a88 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -482,7 +482,12 @@ tsk .req x28 // current thread_info ldr_l x1, \handler mov x0, sp irq_stack_entry +#ifdef CONFIG_ARM64_PTR_AUTH_FWD_CFI + mov x16, GIC_HANDLE_IRQ_TYPEID + blraa x1, x16 +#else blr x1 +#endif irq_stack_exit .endm @@ -1037,7 +1042,12 @@ SYM_CODE_START(ret_from_fork) bl schedule_tail cbz x19, 1f // not a kernel thread mov x0, x20 +#ifdef CONFIG_ARM64_PTR_AUTH_FWD_CFI + mov x16, KERNEL_INIT_TYPEID + blraa x19, x16 +#else blr x19 +#endif 1: get_current_task tsk b ret_to_user SYM_CODE_END(ret_from_fork) diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index e1c25fa3b8e6ca6566876ece29871cefdcd73d1b..6e8f91030c130477461ec08b095841c56ccee717 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S @@ -462,6 +462,9 @@ SYM_FUNC_START_LOCAL(__primary_switched) ldp x29, x30, [sp], #16 // we must enable KASLR, return ret // to __primary_switch() 0: +#endif +#ifdef CONFIG_ARM64_PTR_AUTH_FWD_CFI + bl ptrauth_init_globals #endif add sp, sp, #16 mov x29, #0 diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 22275d8518eb39fa8bd4287deaad832453cfa0fb..b2bf38f29fc5b853ad8294128d0c3767b7cbd8c7 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -436,7 +436,14 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start, p->thread.cpu_context.x19 = stack_start; p->thread.cpu_context.x20 = stk_sz; } + // when CONFIG_ARM64_PTR_AUTH_FWD_CFI is true, directly assignment will use a modifier(function type) to sign pc + // which is used ret to jump in cpu_switch_to +#ifdef CONFIG_ARM64_PTR_AUTH_FWD_CFI + asm ("mov %0, %1\n" : "=&r" (p->thread.cpu_context.pc) : "r" (ret_from_fork)); +#else p->thread.cpu_context.pc = (unsigned long)ret_from_fork; +#endif + p->thread.cpu_context.sp = (unsigned long)childregs; ptrace_hw_copy_thread(p); diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 795d224f184ff2ce63d8427f5e70d4a9a89fd4ef..d95946c075c2680fa77b5bbcb7d6ea496bee6ff8 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -39,6 +39,8 @@ #include #include +#include + struct fault_info { int (*fn)(unsigned long addr, unsigned int esr, struct pt_regs *regs); @@ -307,7 +309,13 @@ static void __do_kernel_fault(unsigned long addr, unsigned int esr, */ if (!is_el1_instruction_abort(esr) && fixup_exception(regs)) return; - +#ifdef CONFIG_ARM64_PTR_AUTH_FWD_CFI_DEBUG + if (is_el1_instruction_abort(esr) && ((addr >> 48) ^ 0xffff)) { + regs->pc = ptrauth_strip_insn_pac(addr); + printk(KERN_ERR "pac-blraa exception PC = %llx X30 = %lx\n", regs->pc, regs->regs[30]); + return; + } +#endif if (WARN_RATELIMIT(is_spurious_el1_translation_fault(addr, esr, regs), "Ignoring spurious kernel translation fault at virtual address %016lx\n", addr)) return; diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index ed600473ad7e3e63d4d27a7e634bb96dc59320fa..2f74322bc335f244eb0ff6d2130ea1c523a39cf1 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -23,6 +23,9 @@ #include #include #include +#ifdef CONFIG_ARM64_PTR_AUTH_FWD_CFI +#include +#endif #include "tpm.h" DEFINE_IDR(dev_nums_idr); @@ -389,10 +392,16 @@ struct tpm_chip *tpmm_chip_alloc(struct device *pdev, chip = tpm_chip_alloc(pdev, ops); if (IS_ERR(chip)) return chip; - +#ifdef CONFIG_ARM64_PTR_AUTH_FWD_CFI + rc = devm_add_action_or_reset(pdev, + pauth_sign_ptr_parameter(put_device, + __builtin_get_modifier_bytype(void (*)(void *)), a), + &chip->dev); +#else rc = devm_add_action_or_reset(pdev, (void (*)(void *)) put_device, &chip->dev); +#endif if (rc) return ERR_PTR(rc); diff --git a/drivers/misc/lkdtm/Makefile b/drivers/misc/lkdtm/Makefile index 0d768a13e2bb705ff645df6cf1e3d1c7a0055726..057aeb94cbba4bae7cce8875395becf3daa8b6c0 100644 --- a/drivers/misc/lkdtm/Makefile +++ b/drivers/misc/lkdtm/Makefile @@ -10,6 +10,7 @@ lkdtm-$(CONFIG_LKDTM) += rodata_objcopy.o lkdtm-$(CONFIG_LKDTM) += usercopy.o lkdtm-$(CONFIG_LKDTM) += stackleak.o lkdtm-$(CONFIG_LKDTM) += cfi.o +lkdtm-$(CONFIG_LKDTM) += ptrauth_ext.o KASAN_SANITIZE_stackleak.o := n KCOV_INSTRUMENT_rodata.o := n diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c index 32b3d77368e37d734ad541e1cda80997fa733345..193791da61a64e80f34d4722a75082e580890e81 100644 --- a/drivers/misc/lkdtm/core.c +++ b/drivers/misc/lkdtm/core.c @@ -174,6 +174,10 @@ static const struct crashtype crashtypes[] = { CRASHTYPE(STACKLEAK_ERASING), CRASHTYPE(CFI_FORWARD_PROTO), CRASHTYPE(DOUBLE_FAULT), + CRASHTYPE(CFI_FWD_CHANGE_FUN_TYPE), + CRASHTYPE(CFI_FWD_CMPXCHG), + CRASHTYPE(CFI_FWD_AUT_PTR), + CRASHTYPE(CFI_FWD_ADD_INSN), }; diff --git a/drivers/misc/lkdtm/lkdtm.h b/drivers/misc/lkdtm/lkdtm.h index 6dec4c9b442ff34e9c516e54ee8d4706af7ad0bd..fd5614643f5294ed946b4556836817a283f1338e 100644 --- a/drivers/misc/lkdtm/lkdtm.h +++ b/drivers/misc/lkdtm/lkdtm.h @@ -101,5 +101,11 @@ void lkdtm_STACKLEAK_ERASING(void); /* cfi.c */ void lkdtm_CFI_FORWARD_PROTO(void); +void lkdtm_CFI_FWD_CHANGE_FUN_TYPE(void); +void lkdtm_CFI_FWD_CMPXCHG(void); +void lkdtm_CFI_FWD_AUT_PTR(void); +void lkdtm_CFI_FWD_ADD_INSN(void); + + #endif diff --git a/drivers/misc/lkdtm/ptrauth_ext.c b/drivers/misc/lkdtm/ptrauth_ext.c new file mode 100644 index 0000000000000000000000000000000000000000..f04aea0f49ddae1a45b033e6e52a6c89581b4238 --- /dev/null +++ b/drivers/misc/lkdtm/ptrauth_ext.c @@ -0,0 +1,188 @@ +#ifdef CONFIG_ARM64_PTR_AUTH_EXT +#ifdef CONFIG_ARM64_PTR_AUTH_FWD_CFI + +#include +#include +#include "lkdtm.h" + +typedef void (*void_fun_pointer)(void); + +struct test_struct { + void_fun_pointer fun; + void *vptr; + unsigned long ulptr; +} + +static struct test_struct data = { + .fun = NULL, + .vptr = NULL, + .ulptr = 0L, +} + +static noinline void fun_symbol(void) +{ + printk("this is PAC front cfi test, 1"); +} + +static noinline int fun_symbol_2(void) +{ + printk("this is PAC front cfi test, 2"); + return (unsigned long)data.fun >> 48; +} + +static noinline int fun_symbol_3(void) +{ + printk("this is PAC front cfi test, 3"); + return (unsigned long)data.fun >> 48; +} + +static noinline void store_fun_pointer(void_fun_pointer fun, int val) +{ + if (val == 0) { + data.fun = fun; + } + + if (val == 1) { + data.vptr = fun; + } + + if (val == 2) { + data.ulptr = (unsigned long)fun; + } +} + +static noinline void storepointer(void *fun, int val) +{ + if (val == 0) { + data.fun = fun; + } + + if (val == 1) { + data.vptr = fun; + } + + if (val == 2) { + data.ulptr = (unsigned long)fun; + } +} + +static noinline void use_fun_pointer(int val) +{ + if (val == 0) { + data.fun(); + } + + if (val == 1) { + void_fun_pointer ptr = data.vptr; + ptr(); + } + + if (val == 2) { + void_fun_pointer ptr = (void_fun_pointer)data.ulptr; + ptr(); + } +} + +typedef void chg_func(void); +static chg_func *chg_test_fun; + +static noinline int fwd_cmpxchg(chg_func *cmp_fn) +{ + uintptr_t fn_data; + int ret = 0; + + ret = (cmpxchg((chg_func **)&chg_test_fun, cmp_fn, NULL) == cmp_fn) ? + 0 : -1; + if (ret == -1) { + printk("because of resigned, cmpxchg failed\n"); + } + + fn_data = (uintptr_t)cmp_fn; + ret = ((uintptr_t)cmpxchg(( **)&chg_test_fun, cmp_fn, NULL) == fn_data) ? + 0 : -EINVAL; + if (ret == 0) { + printk("we avoid resigning !!!\n"); + } + return ret; +} + +static noinline u64 fun_base(void) +{ + return 0; +} + +void lkdtm_CFI_FWD_CHANGE_FUN_TYPE(void) +{ + store_fun_pointer(fun_symbol, 0); + use_fun_pointer(0); + //作非匹配类型的函数指针入参 + store_fun_pointer(pauth_sign_ptr_parameter(fun_symbol_2, + __builtin_get_modifier_bytype(void_fun_pointer), a), 0); + use_fun_pointer(0); + // 作非匹配类型的void *入参 + store_pointer(pauth_sign_ptr_parameter(fun_symbol_3, + __builtin_get_modifier_bytype(void_fun_pointer), a), 0); + use_fun_pointer(0); + printk("welcome here, everything is ok !!!\n"); +} + +void lkdtm_CFI_FWD_CMPXCHG(void) +{ + int ret = 0; + ret = fwd_cmpxchg(chg_test_fun); + if (ret == -1) { + printk("cmpxchg is failed !\n"); + } +} + +void lkdtm_CFI_FWD_AUT_PTR(void) +{ + unsigned long temp_ulptr; + if (chg_test_fun == NULL) { + chg_test_fun = fun_symbol; + } + printk("this is the ptr before aut, %llx\n", chg_test_fun); + temp_ulptr = (unsigned long)pauth_autia(chg_test_fun, + __builtin_get_modifier_bytype(chg_test_fun)); + if (temp_ulptr >> 48 ^0xffff) { + printk("aut failed\n"); + } + printk("this is the ptr after aut, %llx\n", temp_ulptr); +} + +void lkdtm_CFI_FWD_ADD_INSN(void) +{ + typedef u64 (*target_fn_t)(u64); + u32 num; + unsigned long temp_ulptr; + target_fn_t call_pac; + uintptr_t addr; + + num = get_random_int(); + printk("this is insn, %d/n", num); + + addr = (uintptr_t)fun_base + (s32)(num); + printk("this is the address which need to be paced, %llx\n", addr); + + call_pac = + (target_fn_t)(pauth_pacia((void *)addr, __builtin_get_modifier_bytype(target_fn_t))); + printk("this is the address has been paced, %llx\n", call_pac); + + temp_ulptr = (unsigned long)pauth_autia(call_pac, + __builtin_get_modifier_bytype(target_fn_t)); + if (temp_ulptr >> 48 ^0xffff) { + printk("aut failed\n"); + } + printk("this is the address after aut, %llx\n", temp_ulptr); +} + + + + + + + + + +#endif +#endif \ No newline at end of file