linux/arch/loongarch/include/asm/stackframe.h
Youling Tang a45728fd41 LoongArch: Enable HAVE_ARCH_STACKLEAK
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>
2025-05-30 21:45:42 +08:00

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 */