mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00

Add support for the stackleak feature. It initializes the stack with the poison value before returning from system calls which improves the kernel security. At the same time, disables the plugin in EFI stub code because EFI stub is out of scope for the protection. Tested on Loongson-3A5000 (enable GCC_PLUGIN_STACKLEAK and LKDTM): # echo STACKLEAK_ERASING > /sys/kernel/debug/provoke-crash/DIRECT # dmesg lkdtm: Performing direct entry STACKLEAK_ERASING lkdtm: stackleak stack usage: high offset: 320 bytes current: 448 bytes lowest: 1264 bytes tracked: 1264 bytes untracked: 208 bytes poisoned: 14528 bytes low offset: 64 bytes lkdtm: OK: the rest of the thread stack is properly erased Signed-off-by: Youling Tang <tangyouling@kylinos.cn> Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
252 lines
5.5 KiB
C
252 lines
5.5 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Copyright (C) 2020-2022 Loongson Technology Corporation Limited
|
|
*/
|
|
#ifndef _ASM_STACKFRAME_H
|
|
#define _ASM_STACKFRAME_H
|
|
|
|
#include <linux/threads.h>
|
|
|
|
#include <asm/addrspace.h>
|
|
#include <asm/asm.h>
|
|
#include <asm/asmmacro.h>
|
|
#include <asm/asm-offsets.h>
|
|
#include <asm/loongarch.h>
|
|
#include <asm/thread_info.h>
|
|
#include <asm/unwind_hints.h>
|
|
|
|
/* Make the addition of cfi info a little easier. */
|
|
.macro cfi_rel_offset reg offset=0 docfi=0
|
|
.if \docfi
|
|
.cfi_rel_offset \reg, \offset
|
|
.endif
|
|
.endm
|
|
|
|
.macro cfi_st reg offset=0 docfi=0
|
|
cfi_rel_offset \reg, \offset, \docfi
|
|
LONG_S \reg, sp, \offset
|
|
.endm
|
|
|
|
.macro cfi_restore reg offset=0 docfi=0
|
|
.if \docfi
|
|
.cfi_restore \reg
|
|
.endif
|
|
.endm
|
|
|
|
.macro cfi_ld reg offset=0 docfi=0
|
|
LONG_L \reg, sp, \offset
|
|
cfi_restore \reg \offset \docfi
|
|
.endm
|
|
|
|
.macro SETUP_DMWINS temp
|
|
li.d \temp, CSR_DMW0_INIT # WUC, PLV0, 0x8000 xxxx xxxx xxxx
|
|
csrwr \temp, LOONGARCH_CSR_DMWIN0
|
|
li.d \temp, CSR_DMW1_INIT # CAC, PLV0, 0x9000 xxxx xxxx xxxx
|
|
csrwr \temp, LOONGARCH_CSR_DMWIN1
|
|
li.d \temp, CSR_DMW2_INIT # WUC, PLV0, 0xa000 xxxx xxxx xxxx
|
|
csrwr \temp, LOONGARCH_CSR_DMWIN2
|
|
li.d \temp, CSR_DMW3_INIT # 0x0, unused
|
|
csrwr \temp, LOONGARCH_CSR_DMWIN3
|
|
.endm
|
|
|
|
/* Jump to the runtime virtual address. */
|
|
.macro JUMP_VIRT_ADDR temp1 temp2
|
|
li.d \temp1, CACHE_BASE
|
|
pcaddi \temp2, 0
|
|
bstrins.d \temp1, \temp2, (DMW_PABITS - 1), 0
|
|
jirl zero, \temp1, 0xc
|
|
.endm
|
|
|
|
.macro STACKLEAK_ERASE
|
|
#ifdef CONFIG_GCC_PLUGIN_STACKLEAK
|
|
bl stackleak_erase_on_task_stack
|
|
#endif
|
|
.endm
|
|
|
|
.macro BACKUP_T0T1
|
|
csrwr t0, EXCEPTION_KS0
|
|
csrwr t1, EXCEPTION_KS1
|
|
.endm
|
|
|
|
.macro RELOAD_T0T1
|
|
csrrd t0, EXCEPTION_KS0
|
|
csrrd t1, EXCEPTION_KS1
|
|
.endm
|
|
|
|
.macro SAVE_TEMP docfi=0
|
|
RELOAD_T0T1
|
|
cfi_st t0, PT_R12, \docfi
|
|
cfi_st t1, PT_R13, \docfi
|
|
cfi_st t2, PT_R14, \docfi
|
|
cfi_st t3, PT_R15, \docfi
|
|
cfi_st t4, PT_R16, \docfi
|
|
cfi_st t5, PT_R17, \docfi
|
|
cfi_st t6, PT_R18, \docfi
|
|
cfi_st t7, PT_R19, \docfi
|
|
cfi_st t8, PT_R20, \docfi
|
|
.endm
|
|
|
|
.macro SAVE_STATIC docfi=0
|
|
cfi_st s0, PT_R23, \docfi
|
|
cfi_st s1, PT_R24, \docfi
|
|
cfi_st s2, PT_R25, \docfi
|
|
cfi_st s3, PT_R26, \docfi
|
|
cfi_st s4, PT_R27, \docfi
|
|
cfi_st s5, PT_R28, \docfi
|
|
cfi_st s6, PT_R29, \docfi
|
|
cfi_st s7, PT_R30, \docfi
|
|
cfi_st s8, PT_R31, \docfi
|
|
.endm
|
|
|
|
/*
|
|
* get_saved_sp returns the SP for the current CPU by looking in the
|
|
* kernelsp array for it. It stores the current sp in t0 and loads the
|
|
* new value in sp.
|
|
*/
|
|
.macro get_saved_sp docfi=0
|
|
la_abs t1, kernelsp
|
|
#ifdef CONFIG_SMP
|
|
csrrd t0, PERCPU_BASE_KS
|
|
LONG_ADD t1, t1, t0
|
|
#endif
|
|
move t0, sp
|
|
.if \docfi
|
|
.cfi_register sp, t0
|
|
.endif
|
|
LONG_L sp, t1, 0
|
|
.endm
|
|
|
|
.macro set_saved_sp stackp temp temp2
|
|
la.pcrel \temp, kernelsp
|
|
#ifdef CONFIG_SMP
|
|
LONG_ADD \temp, \temp, u0
|
|
#endif
|
|
LONG_S \stackp, \temp, 0
|
|
.endm
|
|
|
|
.macro SAVE_SOME docfi=0
|
|
csrrd t1, LOONGARCH_CSR_PRMD
|
|
andi t1, t1, 0x3 /* extract pplv bit */
|
|
move t0, sp
|
|
beqz t1, 8f
|
|
/* Called from user mode, new stack. */
|
|
get_saved_sp docfi=\docfi
|
|
8:
|
|
PTR_ADDI sp, sp, -PT_SIZE
|
|
.if \docfi
|
|
.cfi_def_cfa sp, 0
|
|
.endif
|
|
cfi_st t0, PT_R3, \docfi
|
|
cfi_rel_offset sp, PT_R3, \docfi
|
|
LONG_S zero, sp, PT_R0
|
|
csrrd t0, LOONGARCH_CSR_PRMD
|
|
LONG_S t0, sp, PT_PRMD
|
|
csrrd t0, LOONGARCH_CSR_CRMD
|
|
LONG_S t0, sp, PT_CRMD
|
|
csrrd t0, LOONGARCH_CSR_EUEN
|
|
LONG_S t0, sp, PT_EUEN
|
|
csrrd t0, LOONGARCH_CSR_ECFG
|
|
LONG_S t0, sp, PT_ECFG
|
|
csrrd t0, LOONGARCH_CSR_ESTAT
|
|
PTR_S t0, sp, PT_ESTAT
|
|
cfi_st ra, PT_R1, \docfi
|
|
cfi_st a0, PT_R4, \docfi
|
|
cfi_st a1, PT_R5, \docfi
|
|
cfi_st a2, PT_R6, \docfi
|
|
cfi_st a3, PT_R7, \docfi
|
|
cfi_st a4, PT_R8, \docfi
|
|
cfi_st a5, PT_R9, \docfi
|
|
cfi_st a6, PT_R10, \docfi
|
|
cfi_st a7, PT_R11, \docfi
|
|
csrrd ra, LOONGARCH_CSR_ERA
|
|
LONG_S ra, sp, PT_ERA
|
|
.if \docfi
|
|
.cfi_rel_offset ra, PT_ERA
|
|
.endif
|
|
cfi_st tp, PT_R2, \docfi
|
|
cfi_st fp, PT_R22, \docfi
|
|
|
|
/* Set thread_info if we're coming from user mode */
|
|
csrrd t0, LOONGARCH_CSR_PRMD
|
|
andi t0, t0, 0x3 /* extract pplv bit */
|
|
beqz t0, 9f
|
|
|
|
li.d tp, ~_THREAD_MASK
|
|
and tp, tp, sp
|
|
cfi_st u0, PT_R21, \docfi
|
|
csrrd u0, PERCPU_BASE_KS
|
|
9:
|
|
#ifdef CONFIG_KGDB
|
|
li.w t0, CSR_CRMD_WE
|
|
csrxchg t0, t0, LOONGARCH_CSR_CRMD
|
|
#endif
|
|
UNWIND_HINT_REGS
|
|
.endm
|
|
|
|
.macro SAVE_ALL docfi=0
|
|
SAVE_SOME \docfi
|
|
SAVE_TEMP \docfi
|
|
SAVE_STATIC \docfi
|
|
.endm
|
|
|
|
.macro RESTORE_TEMP docfi=0
|
|
cfi_ld t0, PT_R12, \docfi
|
|
cfi_ld t1, PT_R13, \docfi
|
|
cfi_ld t2, PT_R14, \docfi
|
|
cfi_ld t3, PT_R15, \docfi
|
|
cfi_ld t4, PT_R16, \docfi
|
|
cfi_ld t5, PT_R17, \docfi
|
|
cfi_ld t6, PT_R18, \docfi
|
|
cfi_ld t7, PT_R19, \docfi
|
|
cfi_ld t8, PT_R20, \docfi
|
|
.endm
|
|
|
|
.macro RESTORE_STATIC docfi=0
|
|
cfi_ld s0, PT_R23, \docfi
|
|
cfi_ld s1, PT_R24, \docfi
|
|
cfi_ld s2, PT_R25, \docfi
|
|
cfi_ld s3, PT_R26, \docfi
|
|
cfi_ld s4, PT_R27, \docfi
|
|
cfi_ld s5, PT_R28, \docfi
|
|
cfi_ld s6, PT_R29, \docfi
|
|
cfi_ld s7, PT_R30, \docfi
|
|
cfi_ld s8, PT_R31, \docfi
|
|
.endm
|
|
|
|
.macro RESTORE_SOME docfi=0
|
|
LONG_L a0, sp, PT_PRMD
|
|
andi a0, a0, 0x3 /* extract pplv bit */
|
|
beqz a0, 8f
|
|
cfi_ld u0, PT_R21, \docfi
|
|
8:
|
|
LONG_L a0, sp, PT_ERA
|
|
csrwr a0, LOONGARCH_CSR_ERA
|
|
LONG_L a0, sp, PT_PRMD
|
|
csrwr a0, LOONGARCH_CSR_PRMD
|
|
cfi_ld ra, PT_R1, \docfi
|
|
cfi_ld a0, PT_R4, \docfi
|
|
cfi_ld a1, PT_R5, \docfi
|
|
cfi_ld a2, PT_R6, \docfi
|
|
cfi_ld a3, PT_R7, \docfi
|
|
cfi_ld a4, PT_R8, \docfi
|
|
cfi_ld a5, PT_R9, \docfi
|
|
cfi_ld a6, PT_R10, \docfi
|
|
cfi_ld a7, PT_R11, \docfi
|
|
cfi_ld tp, PT_R2, \docfi
|
|
cfi_ld fp, PT_R22, \docfi
|
|
.endm
|
|
|
|
.macro RESTORE_SP_AND_RET docfi=0
|
|
cfi_ld sp, PT_R3, \docfi
|
|
UNWIND_HINT_FUNC
|
|
ertn
|
|
.endm
|
|
|
|
.macro RESTORE_ALL_AND_RET docfi=0
|
|
RESTORE_STATIC \docfi
|
|
RESTORE_TEMP \docfi
|
|
RESTORE_SOME \docfi
|
|
RESTORE_SP_AND_RET \docfi
|
|
.endm
|
|
|
|
#endif /* _ASM_STACKFRAME_H */
|