]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
arm64/traps: Handle GCS exceptions
authorMark Brown <broonie@kernel.org>
Tue, 1 Oct 2024 22:58:58 +0000 (23:58 +0100)
committerCatalin Marinas <catalin.marinas@arm.com>
Fri, 4 Oct 2024 11:04:37 +0000 (12:04 +0100)
A new exception code is defined for GCS specific faults other than
standard load/store faults, for example GCS token validation failures,
add handling for this. These faults are reported to userspace as
segfaults with code SEGV_CPERR (protection error), mirroring the
reporting for x86 shadow stack errors.

GCS faults due to memory load/store operations generate data aborts with
a flag set, these will be handled separately as part of the data abort
handling.

Since we do not currently enable GCS for EL1 we should not get any faults
there but while we're at it we wire things up there, treating any GCS
fault as fatal.

Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/r/20241001-arm64-gcs-v13-19-222b78d87eee@kernel.org
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
arch/arm64/include/asm/esr.h
arch/arm64/include/asm/exception.h
arch/arm64/kernel/entry-common.c
arch/arm64/kernel/traps.c

index da6d2c1c0b030c426151dfbd4157a651026ed3e5..d1b1a33f9a8b0d4d85e4630a42e25938a7178edf 100644 (file)
@@ -51,7 +51,8 @@
 #define ESR_ELx_EC_FP_EXC32    UL(0x28)
 /* Unallocated EC: 0x29 - 0x2B */
 #define ESR_ELx_EC_FP_EXC64    UL(0x2C)
-/* Unallocated EC: 0x2D - 0x2E */
+#define ESR_ELx_EC_GCS         UL(0x2D)
+/* Unallocated EC:  0x2E */
 #define ESR_ELx_EC_SERROR      UL(0x2F)
 #define ESR_ELx_EC_BREAKPT_LOW UL(0x30)
 #define ESR_ELx_EC_BREAKPT_CUR UL(0x31)
 #define ESR_ELx_MOPS_ISS_SRCREG(esr)   (((esr) & (UL(0x1f) << 5)) >> 5)
 #define ESR_ELx_MOPS_ISS_SIZEREG(esr)  (((esr) & (UL(0x1f) << 0)) >> 0)
 
+/* ISS field definitions for GCS */
+#define ESR_ELx_ExType_SHIFT   (20)
+#define ESR_ELx_ExType_MASK            GENMASK(23, 20)
+#define ESR_ELx_Raddr_SHIFT            (10)
+#define ESR_ELx_Raddr_MASK             GENMASK(14, 10)
+#define ESR_ELx_Rn_SHIFT               (5)
+#define ESR_ELx_Rn_MASK                        GENMASK(9, 5)
+#define ESR_ELx_Rvalue_SHIFT           5
+#define ESR_ELx_Rvalue_MASK            GENMASK(9, 5)
+#define ESR_ELx_IT_SHIFT               (0)
+#define ESR_ELx_IT_MASK                        GENMASK(4, 0)
+
+#define ESR_ELx_ExType_DATA_CHECK      0
+#define ESR_ELx_ExType_EXLOCK          1
+#define ESR_ELx_ExType_STR             2
+
+#define ESR_ELx_IT_RET                 0
+#define ESR_ELx_IT_GCSPOPM             1
+#define ESR_ELx_IT_RET_KEYA            2
+#define ESR_ELx_IT_RET_KEYB            3
+#define ESR_ELx_IT_GCSSS1              4
+#define ESR_ELx_IT_GCSSS2              5
+#define ESR_ELx_IT_GCSPOPCX            6
+#define ESR_ELx_IT_GCSPOPX             7
+
 #ifndef __ASSEMBLY__
 #include <asm/types.h>
 
index f296662590c7f8bcc2c0806da155c2cacca00bc3..674518464718ff5e2e7ad37ee4373c65e62a8e99 100644 (file)
@@ -57,6 +57,8 @@ void do_el0_undef(struct pt_regs *regs, unsigned long esr);
 void do_el1_undef(struct pt_regs *regs, unsigned long esr);
 void do_el0_bti(struct pt_regs *regs);
 void do_el1_bti(struct pt_regs *regs, unsigned long esr);
+void do_el0_gcs(struct pt_regs *regs, unsigned long esr);
+void do_el1_gcs(struct pt_regs *regs, unsigned long esr);
 void do_debug_exception(unsigned long addr_if_watchpoint, unsigned long esr,
                        struct pt_regs *regs);
 void do_fpsimd_acc(unsigned long esr, struct pt_regs *regs);
index 3fcd9d080bf2a9086ebe6a596e73dee63fd2cb7e..fe74813009bd4c4301d84f94dad733ab97984aed 100644 (file)
@@ -463,6 +463,15 @@ static void noinstr el1_bti(struct pt_regs *regs, unsigned long esr)
        exit_to_kernel_mode(regs);
 }
 
+static void noinstr el1_gcs(struct pt_regs *regs, unsigned long esr)
+{
+       enter_from_kernel_mode(regs);
+       local_daif_inherit(regs);
+       do_el1_gcs(regs, esr);
+       local_daif_mask();
+       exit_to_kernel_mode(regs);
+}
+
 static void noinstr el1_dbg(struct pt_regs *regs, unsigned long esr)
 {
        unsigned long far = read_sysreg(far_el1);
@@ -505,6 +514,9 @@ asmlinkage void noinstr el1h_64_sync_handler(struct pt_regs *regs)
        case ESR_ELx_EC_BTI:
                el1_bti(regs, esr);
                break;
+       case ESR_ELx_EC_GCS:
+               el1_gcs(regs, esr);
+               break;
        case ESR_ELx_EC_BREAKPT_CUR:
        case ESR_ELx_EC_SOFTSTP_CUR:
        case ESR_ELx_EC_WATCHPT_CUR:
@@ -684,6 +696,14 @@ static void noinstr el0_mops(struct pt_regs *regs, unsigned long esr)
        exit_to_user_mode(regs);
 }
 
+static void noinstr el0_gcs(struct pt_regs *regs, unsigned long esr)
+{
+       enter_from_user_mode(regs);
+       local_daif_restore(DAIF_PROCCTX);
+       do_el0_gcs(regs, esr);
+       exit_to_user_mode(regs);
+}
+
 static void noinstr el0_inv(struct pt_regs *regs, unsigned long esr)
 {
        enter_from_user_mode(regs);
@@ -766,6 +786,9 @@ asmlinkage void noinstr el0t_64_sync_handler(struct pt_regs *regs)
        case ESR_ELx_EC_MOPS:
                el0_mops(regs, esr);
                break;
+       case ESR_ELx_EC_GCS:
+               el0_gcs(regs, esr);
+               break;
        case ESR_ELx_EC_BREAKPT_LOW:
        case ESR_ELx_EC_SOFTSTP_LOW:
        case ESR_ELx_EC_WATCHPT_LOW:
index 563cbce11126960a810d22b1cac024787f283a4e..fdbcf047108cfba9b555318dd982e25ba38566d2 100644 (file)
@@ -506,6 +506,16 @@ void do_el1_bti(struct pt_regs *regs, unsigned long esr)
        die("Oops - BTI", regs, esr);
 }
 
+void do_el0_gcs(struct pt_regs *regs, unsigned long esr)
+{
+       force_signal_inject(SIGSEGV, SEGV_CPERR, regs->pc, 0);
+}
+
+void do_el1_gcs(struct pt_regs *regs, unsigned long esr)
+{
+       die("Oops - GCS", regs, esr);
+}
+
 void do_el0_fpac(struct pt_regs *regs, unsigned long esr)
 {
        force_signal_inject(SIGILL, ILL_ILLOPN, regs->pc, esr);
@@ -852,6 +862,7 @@ static const char *esr_class_str[] = {
        [ESR_ELx_EC_MOPS]               = "MOPS",
        [ESR_ELx_EC_FP_EXC32]           = "FP (AArch32)",
        [ESR_ELx_EC_FP_EXC64]           = "FP (AArch64)",
+       [ESR_ELx_EC_GCS]                = "Guarded Control Stack",
        [ESR_ELx_EC_SERROR]             = "SError",
        [ESR_ELx_EC_BREAKPT_LOW]        = "Breakpoint (lower EL)",
        [ESR_ELx_EC_BREAKPT_CUR]        = "Breakpoint (current EL)",