diff --git a/LICENSE b/LICENSE index fc48fd28904f6680c1da24e70d27c7ffb7a31c16..2016ff8ae22b64b0270e62eb3521af0f08631083 100644 --- a/LICENSE +++ b/LICENSE @@ -2,5 +2,6 @@ ./newip/ ./xpm/ ./qos_auth/ + ./pac/ As for the specific use of the licenses, please refer to the relevant description in the documents. diff --git a/OAT.xml b/OAT.xml index 9de7aacb31ad265d296ee9139b08fe3783166732..a9a37b963fd3db09b7097551cb97f54310fdc088 100644 --- a/OAT.xml +++ b/OAT.xml @@ -60,9 +60,11 @@ Note:If the text contains special characters, please escape them according to th + + @@ -81,6 +83,7 @@ Note:If the text contains special characters, please escape them according to th + diff --git a/pac/Makefile b/pac/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6fbb431c930b7267f3401b60298342896597fde9 --- /dev/null +++ b/pac/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (c) 2023 Huawei Device Co., Ltd. +# +# Makefile for the Linux PAC module. +# + +obj-$(CONFIG_ARM64_PTR_AUTH_EXT) += src/pointer_auth_key.o +obj-$(CONFIG_ARM64_PTR_AUTH_EXT) += src/asm_pointer_auth_key.o +obj-$(CONFIG_ARM64_PTR_AUTH_DATA_FIELD) += src/pointer_auth_context.o +obj-$(CONFIG_ARM64_PTR_AUTH_DATA_FIELD) += src/asm_pointer_auth_context.o +obj-$(CONFIG_CONSTRUCTORS) += src/asm_pointer_auth_constructors.o diff --git a/pac/README_zh.md b/pac/README_zh.md new file mode 100644 index 0000000000000000000000000000000000000000..0ccf2fe6bc74b564068f50f1f9ef15a7279647fe --- /dev/null +++ b/pac/README_zh.md @@ -0,0 +1,67 @@ +## 背景 + +现阶段,内存安全漏洞是对计算机系统安全最严重的威胁。从漏洞利用的角度分析,借助常见的攻击手段,包括利用缓冲区溢出等实现JOP/ROP攻击,攻击者可以实现控制流劫持,最终导致任意代码执行,这严重摧毁了一个系统的安全性。另一方面,在攻击者利用内存漏洞做提权的过程中,通常会修改指向关键数据(如Cred)的数据指针,这类攻击被归纳为DOP攻击,同样会对系统安全产生严重威胁。 +因此,系统需要高效的漏洞防利用机制,以保护系统的控制流完整性和数据流完整性,这对于提升系统的安全竞争力具有重要意义。当前,从安全性角度,对于系统安全主流的JOP/ROP/DOP攻击,PAC机制均能实现有效防护。 + +## PAC(Pointer Authentication Code)模块 + +PAC模块利用ARMv8.3-a架构提供的PAC特性,基于linux内核提供PAC相关的特性支持,包括密钥管理、数据和指针签名验签,以及任务切换上下文、异常中断上下文的PAC保护机制。PAC主要功能实现如下: + +### 1.密钥管理 + +ARMv8.3-a指令集引入了硬件安全特性PAC,用于保护内存中指针和其他数据的完整性。原理是:ARM硬件基于QARMA密码算法,将被保护的指针或数据、用于签名的密钥和盐值作为输入,计算输出一个MAC值,对于指针来说,将有效的MAC值存放在指针的未使用高位,对于数据来说,需要另开辟内存用于保存MAC值。 + +PAC原理 + +Linux内核的密钥管理分为用户态密钥和内核态密钥,示意图如下: + +![密钥管理](figures/key.png) + +### 2.关键数据和指针保护 + +Linux内核可以利用PAC模块对任务切换上下文、异常中断上下文中的关键字段进行保护,防止在上下文切换的过程中,攻击者利用内存漏洞提权修改关键字段,最终导致任意代码执行。 + +![linux context保护](figures/pac_context.png) + +## 目录 + +PAC主要代码目录结构如下: + +``` +# 代码路径 /kernel/linux/common_modules/pac +├── config # 关键数据、指针标记配置文件 +├── figures # ReadMe 内嵌图例 +├── include # PAC头文件 +├── src # PAC代码 +└── Makefile +``` + +## 配置指导 + +1. PAC使能 + + `CONFIG_ARM64_PTR_AUTH=y` + +2. 密钥使能 + + `CONFIG_ARM64_PTR_AUTH_USER=y` + + `CONFIG_ARM64_PTR_AUTH_KERNEL=y` + + `CONFIG_ARM64_PTR_AUTH_EXT=y` + +3. 关键数据和指针保护使能 + + `CONFIG_ARM64_PTR_AUTH_PTR=y` + + `CONFIG_ARM64_PTR_AUTH_FIELD=y` + +## 相关仓 + +[内核子系统](https://gitee.com/openharmony/docs/blob/master/zh-cn/readme/%E5%86%85%E6%A0%B8%E5%AD%90%E7%B3%BB%E7%BB%9F.md) + +[kernel_linux_5.10](https://gitee.com/openharmony/kernel_linux_5.10) + +[kernel_linux_config](https://gitee.com/openharmony/kernel_linux_config) + +[kernel_linux_build](https://gitee.com/openharmony/kernel_linux_build) diff --git a/pac/apply_pac.sh b/pac/apply_pac.sh new file mode 100755 index 0000000000000000000000000000000000000000..7192d87ed63e2210a44591eb053308c5db5731b5 --- /dev/null +++ b/pac/apply_pac.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2023 Huawei Device Co., Ltd. +# + +set -e + +OHOS_SOURCE_ROOT=$1 +KERNEL_BUILD_ROOT=$2 +PRODUCT_NAME=$3 +KERNEL_VERSION=$4 +PAC_SOURCE_ROOT=$OHOS_SOURCE_ROOT/kernel/linux/common_modules/pac + +function main() +{ + pushd . + + if [ ! -d " $KERNEL_BUILD_ROOT/arch/arm64/pac" ]; then + mkdir $KERNEL_BUILD_ROOT/arch/arm64/pac + fi + + cd $KERNEL_BUILD_ROOT/arch/arm64/pac + ln -s -f $(realpath --relative-to=$KERNEL_BUILD_ROOT/arch/arm64/pac/ $PAC_SOURCE_ROOT)/* ./ + + popd +} + +main diff --git a/pac/config/config.txt b/pac/config/config.txt new file mode 100755 index 0000000000000000000000000000000000000000..3793f5e7f3d9d651cf3cfeb9baf43d0690d21ba5 --- /dev/null +++ b/pac/config/config.txt @@ -0,0 +1,51 @@ +struct.task_struct mm +struct.task_struct stack +struct.task_struct real_parent +struct.task_struct sched_task_group +struct.task_struct files +struct.task_struct nsproxy +struct.task_struct ptracer_cred +struct.task_struct real_cred +struct.task_struct cred +struct.task_struct security +struct.task_struct splice_pipe +struct.task_struct fs +struct.cred session_keyring +struct.cred process_keyring +struct.cred thread_keyring +struct.cred request_key_auth +struct.cred security +struct.cred user +struct.cred user_ns +struct.cred group_info +struct.super_block s_root +struct.super_block s_xattr +struct.super_block s_user_ns +struct.super_block s_d_op +struct.super_block s_vop +struct.super_block s_security +struct.mount mnt_parent +struct.mount mnt_mountpoint +struct.mount mnt_mp +struct.mount mnt_ns +struct.vfsmount mnt_root +struct.vfsmount mnt_sb +struct.inode i_op +struct.inode i_sb +struct.inode i_verity_info +struct.inode i_security +struct.inode i_mapping +struct.dentry d_parent +struct.dentry d_inode +struct.dentry d_op +struct.dentry d_sb +struct.selinux_state status_page +struct.selinux_state avc +struct.selinux_state policy +struct.ipc_namespace user_ns +struct.shmid_kernel shm_file +struct.file f_security +struct.msg_msg security +struct.kern_ipc_perm security +struct.lsm_info blobs +struct.sock_fprog filter diff --git a/pac/figures/key.png b/pac/figures/key.png new file mode 100755 index 0000000000000000000000000000000000000000..10701d465fd63e0dad8393d259c1fb2f1751737d Binary files /dev/null and b/pac/figures/key.png differ diff --git a/pac/figures/pac.png b/pac/figures/pac.png new file mode 100755 index 0000000000000000000000000000000000000000..81556202ea13d6bd3a19a282865a12d1604ca55e Binary files /dev/null and b/pac/figures/pac.png differ diff --git a/pac/figures/pac_context.png b/pac/figures/pac_context.png new file mode 100755 index 0000000000000000000000000000000000000000..5c92414143526cfdf72cd34de25fb2d65d16118f Binary files /dev/null and b/pac/figures/pac_context.png differ diff --git a/pac/include/asm_pointer_auth_context.h b/pac/include/asm_pointer_auth_context.h new file mode 100644 index 0000000000000000000000000000000000000000..bc8acc70f0f4b5997ecf29a74a4a9c931d423bd6 --- /dev/null +++ b/pac/include/asm_pointer_auth_context.h @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + */ + +#ifndef __ASM_POINTER_AUTH_CONTEXT_H +#define __ASM_POINTER_AUTH_CONTEXT_H + +#include +#include + + /* Compute and store hash value of cpu context. */ + .macro sign_thread_context_common, tmp1=x0, tmp2=x1, tmp3=x2 + pacga \tmp2, \tmp1, \tmp2 + pacga \tmp2, \tmp3, \tmp2 + str \tmp2, [\tmp1, CPU_CONTEXT_PAC_HASH] + .endm + + /* Compute and auth hash value of cpu context. */ + .macro auth_thread_context_common, tmp1=x0, tmp2=x1, tmp3=x2 + pacga \tmp2, \tmp1, \tmp2 + pacga \tmp2, \tmp3, \tmp2 + ldr \tmp3, [\tmp1, CPU_CONTEXT_PAC_HASH] + cmp \tmp2, \tmp3 + b.ne .Lthread_context_pac_panic\@ + b .Lauth_thread_context_done\@ +.Lthread_context_pac_panic\@: + adrp x0, .Lthread_context_pac_str + add x0, x0, :lo12:.Lthread_context_pac_str + bl panic +.Lauth_thread_context_done\@: + .endm + + /* Compute and store hash value of the regs. */ + .macro sign_exception_context_common, tmp1=x0, tmp2=x1, tmp3=x2, tmp4=x3, tmp5=x4, tmp6=x5, tmp7=x6 + pacga \tmp2, \tmp1, \tmp2 + pacga \tmp2, \tmp3, \tmp2 + pacga \tmp2, \tmp4, \tmp2 + pacga \tmp2, \tmp5, \tmp2 + pacga \tmp2, \tmp6, \tmp2 + pacga \tmp2, \tmp7, \tmp2 + str \tmp2, [\tmp1, S_PAC_HASH] + .endm + + /* Compute and auth hash value of the regs. */ + .macro auth_exception_context_common, tmp1=x0, tmp2=x1, tmp3=x2, tmp4=x3, tmp5=x4, tmp6=x5, tmp7=x6 + pacga \tmp2, \tmp1, \tmp2 + pacga \tmp2, \tmp3, \tmp2 + pacga \tmp2, \tmp4, \tmp2 + pacga \tmp2, \tmp5, \tmp2 + pacga \tmp2, \tmp6, \tmp2 + pacga \tmp2, \tmp7, \tmp2 + ldr \tmp3, [\tmp1, S_PAC_HASH] + cmp \tmp2, \tmp3 + b.ne .Lpt_regs_pac_panic\@ + b .Lauth_exception_context_done\@ +.Lpt_regs_pac_panic\@: + adrp x0, .Lpt_regs_pac_panic_str + add x0, x0, :lo12:.Lpt_regs_pac_panic_str + bl panic +.Lauth_exception_context_done\@: + .endm + +.Lpt_regs_pac_panic_str: + .asciz "Failed to match pac hash of exception context!\n" + .align 2 + +.Lthread_context_pac_str: + .asciz "Failed to match pac hash of cpu context!\n" + .align 2 + + .macro pac_cpu_context sign_or_auth + .if \sign_or_auth == 0 + /* x0: base of curr task */ + mov x2, x0 + .else + /* x1: base of next task */ + mov x2, x1 + .endif + add x2, x2, #THREAD_CPU_CONTEXT + /* sign sp, lr of cpu context. */ + mov x3, lr + mov x4, x9 + .if \sign_or_auth == 0 + sign_thread_context_common x2, x3, x4 + .else + auth_thread_context_common x2, x3, x4 + .endif + .endm + + .macro sign_cpu_context sign=0 + pac_cpu_context \sign + .endm + + .macro auth_cpu_context auth=1 + pac_cpu_context \auth + .endm + + .macro prepare_compat_pt_regs + /* base of pt_regs */ + mov x23, sp + mov x24, #0 + mov x25, #0 + /* sign lr, sp, pc, pstate of compat task */ + mov x26, x14 + mov x27, x13 + mrs x28, elr_el1 + mov x29, x22 + .endm + + .macro prepare_pt_regs, el, sign_or_auth + /* base of pt_regs */ + mov x23, sp + /* sign x16, x17, lr, sp, pc, pstate of task */ + mov x24, x16 + mov x25, x17 + .if \sign_or_auth == 0 + mov x26, lr + .else + ldr x26, [x23, #S_LR] + .endif + .if \el == 0 + mrs x27, sp_el0 + .else + add x27, x23, #S_FRAME_SIZE + .endif + mrs x28, elr_el1 + .if \sign_or_auth == 0 + mrs x29, spsr_el1 + .else + mov x29, x22 + .endif + .endm + + .macro pac_pt_regs, el, sign_or_auth + .if \el == 0 + /* Test the task is in the mode of 32-bit or 64-bit */ + mrs x23, spsr_el1 + mov x24, #(PSR_MODE32_BIT | PSR_MODE_MASK) + mov x25, #(PSR_MODE32_BIT | PSR_MODE_EL0t) + and x23, x23, x24 + sub x23, x23, x25 + cbnz x23, .Lis_not_compat_task\@ + /* Task in 32-bit mode */ + prepare_compat_pt_regs + b .Lpac_handle\@ + .endif + /* Task in 64-bit mode */ +.Lis_not_compat_task\@: + prepare_pt_regs \el, \sign_or_auth + /* Call the sign or auth function. */ +.Lpac_handle\@: + .if \sign_or_auth == 0 + sign_exception_context_common x23, x24, x25, x26, x27, x28, x29 + .else + auth_exception_context_common x23, x24, x25, x26, x27, x28, x29 + .endif + .endm + + .macro sign_pt_regs, el, sign=0 + pac_pt_regs \el, \sign + .endm + + .macro auth_pt_regs, el, auth=1 + pac_pt_regs \el, \auth + .endm + +#endif /* __ASM_POINTER_AUTH_CONTEXT_H */ diff --git a/pac/include/asm_pointer_auth_key.h b/pac/include/asm_pointer_auth_key.h new file mode 100644 index 0000000000000000000000000000000000000000..d49e1490950167fc391cfdad1251ea9880946159 --- /dev/null +++ b/pac/include/asm_pointer_auth_key.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * + * Pointer authentication keys initialisation. + */ + +#ifndef __ASM_POINTER_AUTH_KEY_H +#define __ASM_POINTER_AUTH_KEY_H + +#include +#include +#include +#include + + .macro __ptrauth_address_keys_install_kernel tmp1, tmp2, tmp3 + ldp \tmp2, \tmp3, [\tmp1, #PTRAUTH_KERNEL_KEY_APIB] + msr_s SYS_APIBKEYLO_EL1, \tmp2 + msr_s SYS_APIBKEYHI_EL1, \tmp3 + + adr_l \tmp1, kernel_common_keys + ldp \tmp2, \tmp3, [\tmp1, #PTRAUTH_KERNEL_KEY_APIA] + msr_s SYS_APIAKEYLO_EL1, \tmp2 + msr_s SYS_APIAKEYHI_EL1, \tmp3 + + ldp \tmp2, \tmp3, [\tmp1, #PTRAUTH_KERNEL_KEY_APDA] + msr_s SYS_APDAKEYLO_EL1, \tmp2 + msr_s SYS_APDAKEYHI_EL1, \tmp3 + + ldp \tmp2, \tmp3, [\tmp1, #PTRAUTH_KERNEL_KEY_APDB] + msr_s SYS_APDBKEYLO_EL1, \tmp2 + msr_s SYS_APDBKEYHI_EL1, \tmp3 + .endm + + .macro __ptrauth_generic_key_install_kernel tmp1, tmp2, tmp3 + ldp \tmp2, \tmp3, [\tmp1, #PTRAUTH_KERNEL_KEY_APGA] + msr_s SYS_APGAKEYLO_EL1, \tmp2 + msr_s SYS_APGAKEYHI_EL1, \tmp3 + .endm + + .macro ptrauth_keys_install_kernel_all tsk, tmp1, tmp2, tmp3 + mov \tmp1, #THREAD_KEYS_KERNEL + add \tmp1, \tsk, \tmp1 + +alternative_if_not ARM64_HAS_ADDRESS_AUTH + b .Lno_addr_auth\@ +alternative_else_nop_endif + __ptrauth_address_keys_install_kernel \tmp1, \tmp2, \tmp3 + +.Lno_addr_auth\@: +alternative_if ARM64_HAS_GENERIC_AUTH + __ptrauth_generic_key_install_kernel \tmp1, \tmp2, \tmp3 +alternative_else_nop_endif + .endm + + .macro __ptrauth_keys_install_kernel_all tsk, tmp1, tmp2, tmp3 + mov \tmp1, #THREAD_KEYS_KERNEL + add \tmp1, \tsk, \tmp1 + __ptrauth_address_keys_install_kernel \tmp1, \tmp2, \tmp3 + __ptrauth_generic_key_install_kernel \tmp1, \tmp2, \tmp3 + .endm + +#endif diff --git a/pac/include/pointer_auth_common.h b/pac/include/pointer_auth_common.h new file mode 100644 index 0000000000000000000000000000000000000000..1eb97e16cb7a59158358c3755bcb09e73fa4e828 --- /dev/null +++ b/pac/include/pointer_auth_common.h @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + */ + +#ifndef __POINTER_AUTH_COMMON_H__ +#define __POINTER_AUTH_COMMON_H__ + +#define PTR_AUTH_PROTECT_PTR __attribute__((pac_protected_ptr)) +#define PTR_AUTH_PROTECT_DATA __attribute__((pac_protected_data)) + +#define pauth_sign(type, key, addr, mod) \ + pauth_common(pac, type, key, addr, mod) + +#define pauth_validate(type, key, addr, mod) \ + pauth_common(aut, type, key, addr, mod) + +#define pauth_strip(type, addr) \ +({ \ + const void *__addr = (addr); \ +\ + asm ("xpac" #type " %0\n" : "+r" (__addr)); \ + (typeof (addr))__addr; \ +}) + +#define pauth_hash(addr, mod) ((unsigned int) (pauth_pacga(addr, mod) >> 32)) + +#define pauth_common(prefix, type, key, addr, mod) \ +({ \ + const void *__addr = (addr); \ + unsigned long __mod = (unsigned long)(mod); \ +\ + if (__builtin_constant_p(mod) && (__mod == 0)) \ + asm (#prefix #type "z" #key " %0\n" : "+r" (__addr)); \ + else \ + asm (#prefix #type #key " %0, %1\n" : "+r" (__addr) : \ + "r" (__mod)); \ + (typeof (addr))(__addr); \ +}) + +#define pauth_get_raw_data(addr) \ +({ \ + const void *__addr; \ + asm ("mov %0, %1\n" : "=&r" (__addr) : \ + "r" (addr)); \ + (void *)(__addr); \ +}) + +#define pauth_sign_function(fun, mod, key) \ +({ \ + const void *__fun = (fun); \ + pauth_common(pac, i, key, __fun, mod); \ + (void *)(__fun); \ +}) + +#define pauth_pacda(addr, mod) pauth_common(pac, d, a, addr, mod) + +#define pauth_pacdb(addr, mod) pauth_common(pac, d, b, addr, mod) + +#define pauth_pacia(addr, mod) pauth_common(pac, i, a, addr, mod) + +#define pauth_pacib(addr, mod) pauth_common(pac, i, b, addr, mod) + +#define pauth_pacga(addr, mod) \ +({ \ + const void *__addr = (addr); \ + unsigned long __mod = (unsigned long)(mod); \ + unsigned long __pac; \ +\ + asm ("pacga %0, %1, %2\n" : "=r" (__pac) : "r" (__addr), \ + "r" (__mod)); \ + __pac; \ +}) + +#define pauth_autda(addr, mod) pauth_common(aut, d, a, addr, mod) + +#define pauth_autdb(addr, mod) pauth_common(aut, d, b, addr, mod) + +#define pauth_autia(addr, mod) pauth_common(aut, i, a, addr, mod) + +#define pauth_autib(addr, mod) pauth_common(aut, i, b, addr, mod) + +#define pauth_xpacd(addr) pauth_strip(d, addr) + +#define pauth_xpaci(addr) pauth_strip(i, addr) + +#endif /* __POINTER_AUTH_COMMON_H__ */ diff --git a/pac/include/pointer_auth_context.h b/pac/include/pointer_auth_context.h new file mode 100644 index 0000000000000000000000000000000000000000..5ef68130cc753ccfa4b40787cd74396332ceda79 --- /dev/null +++ b/pac/include/pointer_auth_context.h @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + */ + +#ifndef __POINTER_AUTH_CONTEXT_H +#define __POINTER_AUTH_CONTEXT_H + +#include +#include +#include + +enum pac_pt_regs { + REGS_X16 = 0, + REGS_X17, + REGS_LR, + REGS_SP, + REGS_PC, + REGS_PSTATE, +}; + +void sign_thread_context(void *cpu_context); +void auth_thread_context(void *cpu_context); + +void sign_exception_context_asm(void *regs); +void auth_exception_context_asm(void *regs); + +int set_exception_context_register_asm(void *regs, int offset, u64 val); + +#ifdef CONFIG_COMPAT +void sign_compat_exception_context_asm(void *regs); +void auth_compat_exception_context_asm(void *regs); + +int set_compat_exception_context_register_asm(void *regs, int offset, u64 val); +#else +static inline void sign_compat_exception_context_asm(void *regs) +{ +} + +static inline void auth_compat_exception_context_asm(void *regs) +{ +} + +static inline int set_compat_exception_context_register_asm(void *regs, int offset, u64 val) +{ + return 0; +} +#endif + +static inline void sign_compat_exception_context(void *regs) +{ + return sign_compat_exception_context_asm(regs); +} + +static inline void auth_compat_exception_context(void *regs) +{ + return auth_compat_exception_context_asm(regs); +} + +static inline void sign_exception_context(void *regs) +{ + if (compat_user_mode((struct pt_regs *)regs)) { + sign_compat_exception_context_asm(regs); + } else { + sign_exception_context_asm(regs); + } +} + +static inline void auth_exception_context(void *regs) +{ + if (compat_user_mode((struct pt_regs *)regs)) { + auth_compat_exception_context_asm(regs); + } else { + auth_exception_context_asm(regs); + } +} + +#define resign_compat_exception_context_start(regs) \ +do { \ + unsigned long irq_flags; \ + local_irq_save(irq_flags); \ + auth_compat_exception_context_asm(regs); + +#define resign_compat_exception_context_end(regs) \ + sign_compat_exception_context_asm(regs); \ + local_irq_restore(irq_flags); \ +} while(0) + +#define resign_exception_context_start(regs) \ +do { \ + unsigned long irq_flags; \ + local_irq_save(irq_flags); \ + auth_exception_context(regs); + +#define resign_exception_context_end(regs) \ + sign_exception_context(regs); \ + local_irq_restore(irq_flags); \ +} while(0) + +#define sign_exception_context_start(regs) \ +do { \ + unsigned long irq_flags; \ + local_irq_save(irq_flags); + +#define sign_exception_context_end(regs) \ + sign_exception_context(regs); \ + local_irq_restore(irq_flags); \ +} while(0) + +int set_compat_exception_context_register(void *regs, enum pac_pt_regs regs_enum, u64 val); +int set_exception_context_register(void *regs, enum pac_pt_regs regs_enum, u64 val); + +void set_compat_exception_context_register_index(struct pt_regs *regs, int index, u64 val); +void set_exception_context_register_index(struct pt_regs *regs, int index, u64 val); + +#endif /* __POINTER_AUTH_CONTEXT_H */ + diff --git a/pac/src/asm_pointer_auth_constructors.S b/pac/src/asm_pointer_auth_constructors.S new file mode 100644 index 0000000000000000000000000000000000000000..4f1405bb1a353d35c70e4cd1188bf9d011761e50 --- /dev/null +++ b/pac/src/asm_pointer_auth_constructors.S @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + */ + +#include +#include +#include + +.pushsection ".init.text", "ax" + +SYM_CODE_START(init_constructors) + mov x21, x30 + adrp x19, __ctors_end + adrp x20, __ctors_start + add x19, x19, #:lo12:__ctors_end + add x20, x20, #:lo12:__ctors_start + cmp x20, x19 + b.cs 4f +3: ldr x8, [x20], #8 + blr x8 + cmp x20, x19 + b.cc 3b +4: mov x30, x21 + ret +SYM_CODE_END(init_constructors) diff --git a/pac/src/asm_pointer_auth_context.S b/pac/src/asm_pointer_auth_context.S new file mode 100644 index 0000000000000000000000000000000000000000..3a4370391c99e6df5aad77352c41c5f91f35df08 --- /dev/null +++ b/pac/src/asm_pointer_auth_context.S @@ -0,0 +1,240 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + */ + +#include "asm_pointer_auth_context.h" + +#include +#include +#include + +#ifdef CONFIG_COMPAT + /* Obtain the regs of compat task to sign or authenticate. */ + .macro ldr_compat_pt_regs + mov x1, #0 + mov x2, #0 + /* load lr, sp, pc, pstate of compat task */ + ldr x3, [x0, #S_COMPAT_LR] + ldr x4, [x0, #S_COMPAT_SP] + ldr x5, [x0, #S_PC] + ldr x6, [x0, #S_PSTATE] + .endm +#endif + + /* Obtain the regs of task to sign or authenticate. */ + .macro ldr_pt_regs + /* load x16, x17, lr, sp, pc, pstate of task */ + ldp x1, x2, [x0, #S_X16] + ldr x3, [x0, #S_LR] + ldr x4, [x0, #S_SP] + ldr x5, [x0, #S_PC] + ldr x6, [x0, #S_PSTATE] + .endm + +/* + * Register sign_thread_context for AArch64. + * void sign_thread_context(struct cpu_context *cpu_context) + * On entry: + * x0: the pointer of cpu_context + */ +SYM_FUNC_START(sign_thread_context) + ldr x1, [x0, #CPU_CONTEXT_PC] + ldr x2, [x0, #CPU_CONTEXT_SP] + sign_thread_context_common + ret +SYM_FUNC_END(sign_thread_context) + +/* + * Register auth_thread_context for AArch64. + * void auth_thread_context(struct cpu_context *cpu_context) + * On entry: + * x0: the pointer of cpu_context + */ +SYM_FUNC_START(auth_thread_context) + stp x29, x30, [sp, #-16]! + mov x29, sp + ldr x1, [x0, #CPU_CONTEXT_PC] + ldr x2, [x0, #CPU_CONTEXT_SP] + auth_thread_context_common + ldp x29, x30, [sp], #16 + ret +SYM_FUNC_END(auth_thread_context) + +/* + * Register set_exception_context_register_asm for AArch64. + * int set_exception_context_register_asm(struct pt_regs *regs, int offset, u64 val); + * On entry: + * x0: the regs of task + * x1: the offset of member in pt_regs struct + * x2: the value need to be update + */ +SYM_FUNC_START(set_exception_context_register_asm) + stp x29, x30, [sp, #-16]! + mov x29, sp + mov x9, x1 + mov x10, x2 + mrs x11, daif + msr daifset, #0x2 + ldr_pt_regs + mov x12, x1 + mov x13, x2 + auth_exception_context_common x0, x12, x13 + cmp x9, #S_LR + b.eq .Lupdate_lr + b.ls .Lchoose_lower + cmp x9, #S_PC + b.eq .Lupdate_pc + b.cc .Lupdate_sp + cmp x9, #S_PSTATE + b.eq .Lupdate_pstate +.Lerror_return: + /* invalid value: return -EINVAL */ + mov x0, #-22 + b .Lreturn +.Lchoose_lower: + cmp x9, #S_X16 + b.eq .Lupdate_x16 + b.hi .Lupdate_x17 + b .Lerror_return +.Lupdate_pstate: + mov x6, x10 +.Lupdate_done: + str x10, [x0, x9] + sign_exception_context_common +.Lreturn: + mov x0, #0 + msr daif, x11 + ldp x29, x30, [sp], #16 + ret + +.Lupdate_x16: + mov x1, x10 + b .Lupdate_done +.Lupdate_x17: + mov x2, x10 + b .Lupdate_done +.Lupdate_lr: + mov x3, x10 + b .Lupdate_done +.Lupdate_sp: + mov x4, x10 + b .Lupdate_done +.Lupdate_pc: + mov x5, x10 + b .Lupdate_done +SYM_FUNC_END(set_exception_context_register_asm) + +#ifdef CONFIG_COMPAT +/* + * Register set_compat_exception_context_register_asm for AArch64. + * int set_compat_exception_context_register_asm(struct pt_regs *regs, int offset, u64 val); + * On entry: + * x0: the regs of compat task + * x1: the offset of member in pt_regs struct + * x2: the value need to be update + */ +SYM_FUNC_START(set_compat_exception_context_register_asm) + stp x29, x30, [sp, #-16]! + mov x29, sp + mov x9, x1 + mov x10, x2 + mrs x11, daif + msr daifset, #0x2 + ldr_compat_pt_regs + mov x12, x1 + mov x13, x2 + auth_exception_context_common x0, x12, x13 + cmp x9, #S_COMPAT_LR + b.eq .Lupdate_compat_lr + b.ls .Lcompat_choose_lower + cmp x9, #S_PSTATE + b.eq .Lupdate_compat_pstate + b.cc .Lupdate_compat_pc +.Lcompat_error_return: + /* invalid value: return -EINVAL */ + mov x0, #-22 + b .Lcompat_return +.Lcompat_choose_lower: + cmp x9, #S_COMPAT_SP + b.eq .Lupdate_compat_sp + b .Lcompat_error_return +.Lupdate_compat_pstate: + mov x6, x10 +.Lcompat_update_done: + str x10, [x0, x9] + sign_exception_context_common +.Lcompat_return: + mov x0, #0 + msr daif, x11 + ldp x29, x30, [sp], #16 + ret + +.Lupdate_compat_lr: + mov x3, x10 + b .Lcompat_update_done +.Lupdate_compat_sp: + mov x4, x10 + b .Lcompat_update_done +.Lupdate_compat_pc: + mov x5, x10 + b .Lcompat_update_done +SYM_FUNC_END(set_compat_exception_context_register_asm) +#endif + +/* + * Register sign_exception_context_asm for AArch64. + * void sign_exception_context_asm(struct pt_regs *regs); + * On entry: + * x0: the regs of task + */ +SYM_FUNC_START(sign_exception_context_asm) + ldr_pt_regs + sign_exception_context_common + ret +SYM_FUNC_END(sign_exception_context_asm) + +/* + * Register auth_exception_context_asm for AArch64. + * void auth_exception_context_asm(struct pt_regs *regs); + * On entry: + * x0: the regs of task + */ +SYM_FUNC_START(auth_exception_context_asm) + stp x29, x30, [sp, #-16]! + mov x29, sp + ldr_pt_regs + auth_exception_context_common + ldp x29, x30, [sp], #16 + ret +SYM_FUNC_END(auth_exception_context_asm) + +#ifdef CONFIG_COMPAT +/* + * Register sign_compat_exception_context_asm for AArch64. + * void sign_compat_exception_context_asm(struct pt_regs *regs); + * On entry: + * x0: the regs of compat task + */ +SYM_FUNC_START(sign_compat_exception_context_asm) + ldr_compat_pt_regs + sign_exception_context_common + ret +SYM_FUNC_END(sign_compat_exception_context_asm) + +/* + * Register auth_compat_exception_context_asm for AArch64. + * void auth_compat_exception_context_asm(struct pt_regs *regs); + * On entry: + * x0: the regs of compat task + */ +SYM_FUNC_START(auth_compat_exception_context_asm) + stp x29, x30, [sp, #-16]! + mov x29, sp + ldr_compat_pt_regs + auth_exception_context_common + ldp x29, x30, [sp], #16 + ret +SYM_FUNC_END(auth_compat_exception_context_asm) +#endif + diff --git a/pac/src/asm_pointer_auth_key.S b/pac/src/asm_pointer_auth_key.S new file mode 100644 index 0000000000000000000000000000000000000000..ab2360de63d62146e640b47fe7ebe86003cb9b6d --- /dev/null +++ b/pac/src/asm_pointer_auth_key.S @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * + * Pointer authentication keys initialisation. + */ + +#include +#include +#include + +.pushsection ".init.text", "ax" + + .macro ptrauth_key_init type, tmp + mrs x25, ap\type\()keylo_el1 + str x25, [\tmp] + mrs x25, ap\type\()keyhi_el1 + str x25, [\tmp, #8] + .endm + + /* init ptrauth key for kernel backward-edge CFI */ + .macro ptrauth_back_key_init + mov x6, x5 /* x5: address of init task */ + mov x7, #THREAD_KEYS_KERNEL + add x6, x6, x7 + add x6, x6, #PTRAUTH_KERNEL_KEY_APIB + ptrauth_key_init ib, x6 + .endm + + /* init common ptrauth keys for kernel forward-edge CFI, data pointer DFI and data field DFI */ + .macro ptrauth_common_keys_init + adr_l x7, kernel_common_keys + mov x6, x7 + add x6, x6, #PTRAUTH_KERNEL_KEY_APIA + ptrauth_key_init ia, x6 + + mov x6, x7 + add x6, x6, #PTRAUTH_KERNEL_KEY_APDA + ptrauth_key_init da, x6 + + mov x6, x7 + add x6, x6, #PTRAUTH_KERNEL_KEY_APDB + ptrauth_key_init db, x6 + + mov x6, x7 + add x6, x6, #PTRAUTH_KERNEL_KEY_APGA + ptrauth_key_init ga, x6 + + .endm + +SYM_CODE_START(ptrauth_kernel_keys_init) + ptrauth_back_key_init + ptrauth_common_keys_init + isb + ret +SYM_CODE_END(ptrauth_kernel_keys_init) diff --git a/pac/src/pointer_auth_context.c b/pac/src/pointer_auth_context.c new file mode 100644 index 0000000000000000000000000000000000000000..95fa3f6bc8ba015b420e481905cf8249d559a583 --- /dev/null +++ b/pac/src/pointer_auth_context.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + */ + +#include +#include +#include +#include + +/* The members of arrays below are corresponding to the enum defined in pointer_auth_context.h: + * enum pac_pt_regs { + * REGS_X16 = 0, + * REGS_X17, + * REGS_LR, + * REGS_SP, + * REGS_PC, + * REGS_PSTATE, + * }; + * + * compat_regs_offset_array[]: + * S_X14: the offset of compat_lr + * S_X13: the offset of compat_sp + */ +static off_t compat_regs_offset_array[] = {0, 0, S_X14, S_X13, S_PC, S_PSTATE}; +static off_t regs_offset_array[] = {S_X16, S_X17, S_LR, S_SP, S_PC, S_PSTATE}; + +int set_compat_exception_context_register(void *regs, enum pac_pt_regs regs_enum, u64 val) +{ + switch (regs_enum) { + case REGS_LR: + case REGS_SP: + case REGS_PC: + case REGS_PSTATE: + return set_compat_exception_context_register_asm(regs, compat_regs_offset_array[regs_enum], val); + default: + return -EINVAL; + } +} + +int set_exception_context_register(void *regs, enum pac_pt_regs regs_enum, u64 val) +{ + if (compat_user_mode((struct pt_regs *)regs)) { + return set_compat_exception_context_register(regs, regs_enum, val); + } else { + switch (regs_enum) { + case REGS_X16: + case REGS_X17: + case REGS_LR: + case REGS_SP: + case REGS_PC: + case REGS_PSTATE: + return set_exception_context_register_asm(regs, regs_offset_array[regs_enum], val); + default: + return -EINVAL; + } + } +} + +void set_compat_exception_context_register_index(struct pt_regs *regs, int index, uint64_t val) +{ + /* 14 means the index of compat_lr */ + if (index == 14) { + set_compat_exception_context_register_asm(regs, S_X14, val); + /* 13 means the index of compat_sp */ + } else if (index == 13) { + set_compat_exception_context_register_asm(regs, S_X13, val); + } else { + regs->regs[index] = val; + } +} + +void set_exception_context_register_index(struct pt_regs *regs, int index, uint64_t val) +{ + off_t offset; + + if (compat_user_mode(regs)) { + set_compat_exception_context_register_index(regs, index, val); + } else { + switch (index) { + /* 16 means the index of regs[16] */ + case 16: + /* 17 means the index of regs[17] */ + case 17: + /* 30 means the index of regs[30] */ + case 30: + offset = offsetof(struct pt_regs, regs[index]); + set_exception_context_register_asm(regs, offset, val); + break; + default: + regs->regs[index] = val; + } + } +} + diff --git a/pac/src/pointer_auth_key.c b/pac/src/pointer_auth_key.c new file mode 100644 index 0000000000000000000000000000000000000000..929341380733d931ec6cb1c10653a0ab12f66bc6 --- /dev/null +++ b/pac/src/pointer_auth_key.c @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * + * Pointer authentication keys initialisation. + */ + +#include + +struct ptrauth_keys_kernel_common kernel_common_keys = {{-1, -1}};