From nobody Fri Oct 3 07:39:28 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 489262288CB; Thu, 4 Sep 2025 03:46:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756957617; cv=none; b=IfMzR35Ya+s9JUoUei3LtkEtWWKtpHBAWZ+5/ZKb1WfPc+SCW2FoQDuhDcqu4TTaG8Z96b3B534+vtl71Xjl4xrlTvblpRqoLTylUNS0GD9ontpOdu0oDUrq0cLqVgzpu8bcmd/xYx8Pro5WJv2D12fDKkMrJOhPWQOercdEUfA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756957617; c=relaxed/simple; bh=gygAMbYS4/B7LWfdzKi5nAbFlKtsg4fEng11C4rHscA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=RuAaseUNNZtgsk2DO/25F1UKw/ysdoNz8Zhd1P7sll9/s1UCzJ9YeAxqA4g+WMY4WlOS3YYqKsVkQQEuTTIE3ROjFC/0YZtiesbxEJSEdZMpPJvpzCKCX1E3WPyft4etRCysuhp3m4lHJ9YlMffz1sBXpami045KVk5D667pBz8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ax77Piwh; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ax77Piwh" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D57B5C4CEFB; Thu, 4 Sep 2025 03:46:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1756957616; bh=gygAMbYS4/B7LWfdzKi5nAbFlKtsg4fEng11C4rHscA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ax77PiwhKcQSmL+erPQOSQzZtwHMjB7MlrBfQJMwgdIsaxbt+573t0SUH6yHrHkJ3 MkT+5bEPP6ahiL4X3gvDSnlCKUBMkFLF8vbl053+vkwlFs0RPik7MNgDTSwHdxm/V2 Y83JLwcOw35riFnhHzBlZ3s0oit68/A2QdGsOM7+WcdUBA2/0ouo74mLA6iAAmKXrs xjB/uwejT5g799laygAHq46UhgFrmajI57kspqGI5QtFomOny8Y4lVPFFevWIMlWXj 1gu7EPzf0cBMhXuAULqTZSIj1HcBgF8lAEGs2Fa232iAMVQcHfE0DM9Zpg0Z4GQLlp shQFx2TjNSQhQ== From: Kees Cook To: Peter Zijlstra Cc: Kees Cook , "Russell King (Oracle)" , Zhen Lei , Arnd Bergmann , =?UTF-8?q?Micha=C5=82=20Pecio?= , Sebastian Andrzej Siewior , Sami Tolvanen , linux-arm-kernel@lists.infradead.org, Nathan Chancellor , Vegard Nossum , Miguel Ojeda , Linus Walleij , Jeff Johnson , Randy Dunlap , David Woodhouse , Nick Desaulniers , Bill Wendling , Justin Stitt , Marco Elver , Przemek Kitszel , Ramon de C Valle , Jonathan Corbet , "Paul E. McKenney" , Nicolas Schier , Masahiro Yamada , Krzysztof Kozlowski , Mark Rutland , linux-kernel@vger.kernel.org, llvm@lists.linux.dev, linux-doc@vger.kernel.org, linux-kbuild@vger.kernel.org, x86@kernel.org, linux-hardening@vger.kernel.org Subject: [PATCH v2 9/9] ARM: traps: Implement KCFI trap handler for ARM32 Date: Wed, 3 Sep 2025 20:46:48 -0700 Message-Id: <20250904034656.3670313-9-kees@kernel.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250904033217.it.414-kees@kernel.org> References: <20250904033217.it.414-kees@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" X-Developer-Signature: v=1; a=openpgp-sha256; l=5332; i=kees@kernel.org; h=from:subject; bh=gygAMbYS4/B7LWfdzKi5nAbFlKtsg4fEng11C4rHscA=; b=owGbwMvMwCVmps19z/KJym7G02pJDBk7OUv3bN80e35o3zHx0myb+o8qKnZfg7IPSfIduFpVL 71eyfxERykLgxgXg6yYIkuQnXuci8fb9nD3uYowc1iZQIYwcHEKwEQ+dDD8FfttyuvjKDe7J/Di h2WqfeW1jRw+wb032a1sLxWWimQ+YPgft3Ij5+HZqmcvrGNlTr+uq1A4R/QWm9aTPZevstUHL0j hBwA= X-Developer-Key: i=kees@kernel.org; a=openpgp; fpr=A5C3F68F229DD60F723E6E138972F4DFDC6DC026 Content-Transfer-Encoding: quoted-printable ARM32 KCFI violations currently show as generic "Oops - undefined instruction" errors, making debugging CFI failures difficult. Add a proper KCFI trap handler similar to the aarch64 implementation to provide clear CFI error messages. The GCC ARM32 KCFI implementation uses UDF instructions with a specific encoding pattern: - UDF instruction format: cccc 0111 1111 imm12 1111 imm4 - 16-bit immediate reconstructed from bits 19-8 and 3-0 - KCFI encoding: 0x8000 | (type_reg_num << 5) | (target_reg_num & 31) - Bit 15: KCFI trap identifier (0x8000) - Bits 9-5: Type ID register field (0x1F when unavailable) - Bits 4-0: Target address register number When the type register field is 0x1F (unavailable due to stack spilling), the handler walks back up to 5 preceding instructions to locate the movw/movt instruction pair that loads the 32-bit type ID, similar to x86 CFI trap reconstruction. The undef_hook pattern matching includes the KCFI bit requirement to ensure the handler is only called for KCFI violations, not arbitrary UDF instructions. Signed-off-by: Kees Cook --- Cc: "Russell King (Oracle)" Cc: Zhen Lei Cc: Arnd Bergmann Cc: "Micha=C5=82 Pecio" Cc: Sebastian Andrzej Siewior Cc: Sami Tolvanen Cc: --- arch/arm/kernel/traps.c | 102 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index afbd2ebe5c39..f2e4e18541e0 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -27,6 +27,7 @@ #include #include #include +#include =20 #include #include @@ -40,6 +41,7 @@ #include #include #include +#include =20 =20 static const char *handler[]=3D { @@ -685,6 +687,106 @@ asmlinkage int arm_syscall(int no, struct pt_regs *re= gs) return 0; } =20 +#ifdef CONFIG_CFI +/* + * ARM32 KCFI trap handler. + * UDF instruction format: cccc 0111 1111 imm12 1111 imm4 + * Immediate is reconstructed from bits 19-8 (12 bits) and bits 3-0 (4 bit= s) + * KCFI immediate encoding: 0x8000 | (0x1F << 5) | (target_reg_num & 31) + * - Bit 15: KCFI trap identifier (0x8000) + * - Bits 9-5: Type ID register field (0x1F when invalid due to stack spil= ling) + * - Bits 4-0: Target address register number + */ +#define CFI_UDF_KCFI_BIT BIT(15) /* KCFI identifier bit (0x8000) */ +#define CFI_UDF_IMM_TARGET GENMASK(4, 0) /* Target register (bits 4:0) */ +#define CFI_UDF_IMM_TYPE GENMASK(9, 5) /* Type register (bits 9:5) */ + +/* UDF base pattern with KCFI bit: cond=3D0xe, 0x7f, xxxx, 1xxx, 0xf, xxxx= */ +#define CFI_UDF_IMM_BASE 0xe7f008f0 +#define CFI_UDF_IMM_MASK 0xfff008f0 /* Mask for UDF + KCFI bit matching= */ + +static int cfi_udf_handler(struct pt_regs *regs, unsigned int instr) +{ + unsigned long target; + u32 target_reg, type_reg, type, imm16; + + /* Reconstruct 16-bit immediate from bits 19-8 and 3-0 */ + imm16 =3D ((instr >> 4) & 0xfff0) | (instr & 0x0f); + + target_reg =3D FIELD_GET(CFI_UDF_IMM_TARGET, imm16); + type_reg =3D FIELD_GET(CFI_UDF_IMM_TYPE, imm16); + + if (target_reg >=3D 16) { + pr_err("CFI UDF handler: invalid target register %u\n", target_reg); + return 1; + } + + target =3D regs->uregs[target_reg]; + + /* Type register field is set to all 1s (0x1F) when invalid due to stack = spilling */ + if (type_reg =3D=3D 0x1F) { + u32 *pc =3D (u32 *)regs->ARM_pc; + int i; + + type =3D 0; + /* Walk back up to 5 instructions to find movw/movt pair for type ID */ + for (i =3D 1; i <=3D 5; i++) { + u32 instr_prev =3D __mem_to_opcode_arm(pc[-i]); + + /* Check for movw: cccc 0011 0000 imm4 Rd imm12 */ + if ((instr_prev & 0x0ff00000) =3D=3D 0x03000000) { + u32 imm16 =3D ((instr_prev >> 4) & 0xf000) | (instr_prev & 0xfff); + type |=3D imm16; + } + /* Check for movt: cccc 0011 0100 imm4 Rd imm12 */ + else if ((instr_prev & 0x0ff00000) =3D=3D 0x03400000) { + u32 imm16 =3D ((instr_prev >> 4) & 0xf000) | (instr_prev & 0xfff); + type |=3D (imm16 << 16); + } + } + if (type =3D=3D 0) + pr_err("CFI UDF handler: failed to find type value\n"); + } else { + if (type_reg >=3D 16) { + pr_err("CFI UDF handler: invalid type register %u\n", type_reg); + return 1; + } + + type =3D regs->uregs[type_reg]; + } + + switch (report_cfi_failure(regs, regs->ARM_pc, &target, type)) { + case BUG_TRAP_TYPE_BUG: + die("Oops - CFI", regs, 0); + break; + case BUG_TRAP_TYPE_WARN: + break; + default: + return 1; + } + + /* Skip the UDF instruction */ + regs->ARM_pc +=3D 4; + return 0; +} + +static struct undef_hook cfi_undef_hook =3D { + .instr_mask =3D CFI_UDF_IMM_MASK, + .instr_val =3D CFI_UDF_IMM_BASE, + .cpsr_mask =3D 0, + .cpsr_val =3D 0, + .fn =3D cfi_udf_handler, +}; + +static int __init arm_cfi_init(void) +{ + register_undef_hook(&cfi_undef_hook); + return 0; +} + +early_initcall(arm_cfi_init); +#endif /* CONFIG_CFI */ + #ifdef CONFIG_TLS_REG_EMUL =20 /* --=20 2.34.1