From patchwork Mon Jul 10 18:35:49 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Sami Tolvanen X-Patchwork-Id: 118012 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:a6b2:0:b0:3e4:2afc:c1 with SMTP id c18csp4336vqm; Mon, 10 Jul 2023 11:43:54 -0700 (PDT) X-Google-Smtp-Source: APBJJlHUe1JqWWe50F5YBzmsltdE8/4A4VeQf11QOH433Zs/42erWc2VzOxN4+AhK9Fknfpi6rAf X-Received: by 2002:a17:907:7253:b0:975:63f4:46 with SMTP id ds19-20020a170907725300b0097563f40046mr14016209ejc.57.1689014634175; Mon, 10 Jul 2023 11:43:54 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1689014634; cv=none; d=google.com; s=arc-20160816; b=J4PoipBUNzA1fB32nwpseY404XJK5OtRu3FKsay125tVuAsMV0a0JfRiiNvbzcaNzN HEqBG9P637ykMpXTdGajkMjIxyVoU1QDaQ3Z6Bv+zdlxD4gL1RMQhCyEsUVbQVhcWusi 6qDPglN63cRY//YRaxcc/K96ZVzVVzWrt6+XNV10MbnGzbnAiKnGQ+m2+dGj/UAXl0SQ 16yik57iMKA8gEMVHIjbZn3zb/cNEqnMqx8hM0RZfy5lFHrOnR+DJQUYIAIFgJFbEml6 AYcxPysZyfxpNK8QaG2tX/icDDd75cG05fSQ4XwFKvttXAj1v+RbRP6gSFSGMyrYKm4W W6sQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:cc:to:from:subject :message-id:references:mime-version:in-reply-to:date:dkim-signature; bh=eswTZL14/0lbniOzURaNQN7FEq6zurstCyikDF3vkhM=; fh=AMRkecuRLh1zvQ+O0EL0q1nlRykK6pdvrtWjx39dx7s=; b=a4PFXnoF3+ntYYBwFo3uTPTGbOidbAHONzGEgaJajBepCz+wyR1aweBBmuk4P5szK1 tGFJ3BUo4uD8Hs2X5jTSVgGd4F692vSMPzCvoGPNi6GBFFtG5NjQlZu4awgBBmz9+/2Z RE8YmiFmtBan6hkO72cyjKLfZzoQLF2KMHpPm+R6FHQlgxgEULKNS9Zi0bEXZHtKUNDx 7wDF97KWqtK9jXGQACwBo1nf8Y6qgMG8CQPv5STJwFTiXgzRd+IFKteHVYDEFGAPWVw+ c5qY9+kLv5uywDHWrwj+BMgdpE4CmoAXY5rOCdvfIH8JPiAqeO3mL2Ul/wX/ooAaQSWC 3PKg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20221208 header.b=mHXw4bXu; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id b13-20020a1709063f8d00b00992671918a4si179703ejj.192.2023.07.10.11.43.30; Mon, 10 Jul 2023 11:43:54 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20221208 header.b=mHXw4bXu; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232073AbjGJSgF (ORCPT + 99 others); Mon, 10 Jul 2023 14:36:05 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47970 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233188AbjGJSf6 (ORCPT ); Mon, 10 Jul 2023 14:35:58 -0400 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5600319A for ; Mon, 10 Jul 2023 11:35:56 -0700 (PDT) Received: by mail-yb1-xb49.google.com with SMTP id 3f1490d57ef6-c704df12425so3919443276.3 for ; Mon, 10 Jul 2023 11:35:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1689014155; x=1691606155; h=content-transfer-encoding:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:from:to:cc:subject:date:message-id :reply-to; bh=eswTZL14/0lbniOzURaNQN7FEq6zurstCyikDF3vkhM=; b=mHXw4bXuQ7mteNju7x5RettqxmsL3nzNMvjatyU7cakrchbgnqgeh/uJDWKgLamt4x C4Xzhq4sjaYfzMLKVoynFKRvTwC+TjyVeUSMj6dF8hY3fuLx0WbL3+OOle9Tfo44WV62 uC16FFSOSmucbJUO5rm3e6k7swahcwOmIwsHGY/x2v88h6NoXbSMuDbDMx0AkoIQpJaA lpZ22oonYN//0xTzIYB9VViMUKAUoRlSe7xhrk7BJ+4+bA3tRjw+edYdsytGn7S6ZQTj ng9khanqFWbetv8vwXovZTsSSQ9QUGK4ZJn5Npl1DKQciIy5/MskFNwXJgk1TFpB/wIv //IQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1689014155; x=1691606155; h=content-transfer-encoding:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:x-gm-message-state:from:to:cc:subject :date:message-id:reply-to; bh=eswTZL14/0lbniOzURaNQN7FEq6zurstCyikDF3vkhM=; b=HlDk4MtuAvLYb24fftLzOrDB5WEaoTsNIvnalPtsotgB2JkEKOBwGyyDxGz9bz1kG3 zsKm3ZJFOLtgGJw4TZ9URBri8a+DIJr4OBdRorpMWpOR2XIYzf6jD7euvrc3WcfyRKzC Ep8UAp99t8RJhZ6yWVUWSSuf5aiqFUq7i4LKJsWaRlgZPznWSKwWmU+ZUsGn5KT+3zpC YCSawiXVUJLchQ/K7CLrqjxm5ajXlyGUqYtpxuuZBD5nQgKce4m89rjMeJ3fThN0qMB7 w8Oc2p56Yy+63yo0sWhkotVZDBkfQz0vSw0WvG/WqamtM9CL2B+T0roAl4C58d+fWIy4 vniA== X-Gm-Message-State: ABy/qLY+wKh/KWc3erh2sy5lI5yU9KdEoRbmQSO99HdAMLJYLzrtdRyW QliiNCHxzA5Jgobf6bm0YCSqBu+AY3VcaLQYToY= X-Received: from samitolvanen.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:4f92]) (user=samitolvanen job=sendgmr) by 2002:a5b:54b:0:b0:c4e:27df:1a0f with SMTP id r11-20020a5b054b000000b00c4e27df1a0fmr99818ybp.13.1689014155420; Mon, 10 Jul 2023 11:35:55 -0700 (PDT) Date: Mon, 10 Jul 2023 18:35:49 +0000 In-Reply-To: <20230710183544.999540-8-samitolvanen@google.com> Mime-Version: 1.0 References: <20230710183544.999540-8-samitolvanen@google.com> X-Developer-Key: i=samitolvanen@google.com; a=openpgp; fpr=35CCFB63B283D6D3AEB783944CB5F6848BBC56EE X-Developer-Signature: v=1; a=openpgp-sha256; l=9602; i=samitolvanen@google.com; h=from:subject; bh=IA2WgXxwoWMBmayegrcrafXII/0/7DYZosX7v/GLBck=; b=owEB7QES/pANAwAKAUy19oSLvFbuAcsmYgBkrE+AzDEYUQi8BUsweEAdZIzultO1gPrFhWnsI jtkRlq4AveJAbMEAAEKAB0WIQQ1zPtjsoPW0663g5RMtfaEi7xW7gUCZKxPgAAKCRBMtfaEi7xW 7ta1C/9wVoJcIYEMVHSgyqgnPHp4livqoTH2BLIv0xCc+oPtCaZ0eaH7XVR4T6q3lQycYnczBk4 1mR2GTxEkGzihjmY9K2GmbjFNVcg7LOfnEnxsmijLPOvDqY0gszNdNjdmhi8WxHWUwJFM9haa8l Yi1XnlYhUxJv3gfg4FxvLzxcg79nus3gQFVJ+IUm4elFPQi6fcoESs67OuWdDxfeQaQ1+x1ayz6 4HH80CFSL07N5Ey9CbNAqHpXEOOfIhZjRpe0J3rRRmJfKysc8TPeP7Dea5/7dlxcw6Wi7vXrAHb AURq+fs9/5rZ7vdTBg8ZEnI+gaoQoBp9jiCSN32evpWtkzj0bySSVSiREaDLYbTIVhDBTEsn/F4 AFyJRq1R0M+IGVwmydqsXPbL3KEyy+31A1uqXk+l2rWNVdEYCzH3/7gDzHVteYnzu8p3/JJPHVG xUPUsbc8EqzDDllkEN4v42pH4ZCayK8K2GXX/Qc8JCSPI7VitZX0JC9akH9JxgGau1lws= X-Mailer: git-send-email 2.41.0.255.g8b1d071c50-goog Message-ID: <20230710183544.999540-12-samitolvanen@google.com> Subject: [PATCH v2 4/6] riscv: Add CFI error handling From: Sami Tolvanen To: Paul Walmsley , Palmer Dabbelt , Albert Ou , Kees Cook Cc: Nathan Chancellor , Nick Desaulniers , Conor Dooley , linux-riscv@lists.infradead.org, llvm@lists.linux.dev, linux-kernel@vger.kernel.org, Sami Tolvanen X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF, RCVD_IN_DNSWL_BLOCKED,SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE, USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1771060208934946649 X-GMAIL-MSGID: 1771060208934946649 With CONFIG_CFI_CLANG, the compiler injects a type preamble immediately before each function and a check to validate the target function type before indirect calls: ; type preamble .word function: ... ; indirect call check lw t1, -4(a0) lui t2, addiw t2, t2, beq t1, t2, .Ltmp0 ebreak .Ltmp0: jarl a0 Implement error handling code for the ebreak traps emitted for the checks. This produces the following oops on a CFI failure (generated using lkdtm): [ 21.177245] CFI failure at lkdtm_indirect_call+0x22/0x32 [lkdtm] (target: lkdtm_increment_int+0x0/0x18 [lkdtm]; expected type: 0x3ad55aca) [ 21.178483] Kernel BUG [#1] [ 21.178671] Modules linked in: lkdtm [ 21.179037] CPU: 1 PID: 104 Comm: sh Not tainted 6.3.0-rc6-00037-g37d5ec6297ab #1 [ 21.179511] Hardware name: riscv-virtio,qemu (DT) [ 21.179818] epc : lkdtm_indirect_call+0x22/0x32 [lkdtm] [ 21.180106] ra : lkdtm_CFI_FORWARD_PROTO+0x48/0x7c [lkdtm] [ 21.180426] epc : ffffffff01387092 ra : ffffffff01386f14 sp : ff20000000453cf0 [ 21.180792] gp : ffffffff81308c38 tp : ff6000000243f080 t0 : ff20000000453b78 [ 21.181157] t1 : 000000003ad55aca t2 : 000000007e0c52a5 s0 : ff20000000453d00 [ 21.181506] s1 : 0000000000000001 a0 : ffffffff0138d170 a1 : ffffffff013870bc [ 21.181819] a2 : b5fea48dd89aa700 a3 : 0000000000000001 a4 : 0000000000000fff [ 21.182169] a5 : 0000000000000004 a6 : 00000000000000b7 a7 : 0000000000000000 [ 21.182591] s2 : ff20000000453e78 s3 : ffffffffffffffea s4 : 0000000000000012 [ 21.183001] s5 : ff600000023c7000 s6 : 0000000000000006 s7 : ffffffff013882a0 [ 21.183653] s8 : 0000000000000008 s9 : 0000000000000002 s10: ffffffff0138d878 [ 21.184245] s11: ffffffff0138d878 t3 : 0000000000000003 t4 : 0000000000000000 [ 21.184591] t5 : ffffffff8133df08 t6 : ffffffff8133df07 [ 21.184858] status: 0000000000000120 badaddr: 0000000000000000 cause: 0000000000000003 [ 21.185415] [] lkdtm_indirect_call+0x22/0x32 [lkdtm] [ 21.185772] [] lkdtm_CFI_FORWARD_PROTO+0x48/0x7c [lkdtm] [ 21.186093] [] lkdtm_do_action+0x22/0x34 [lkdtm] [ 21.186445] [] direct_entry+0x128/0x13a [lkdtm] [ 21.186817] [] full_proxy_write+0x58/0xb2 [ 21.187352] [] vfs_write+0x14c/0x33a [ 21.187644] [] ksys_write+0x64/0xd4 [ 21.187832] [] sys_write+0xe/0x1a [ 21.188171] [] ret_from_syscall+0x0/0x2 [ 21.188595] Code: 0513 0f65 a303 ffc5 53b7 7e0c 839b 2a53 0363 0073 (9002) 9582 [ 21.189178] ---[ end trace 0000000000000000 ]--- [ 21.189590] Kernel panic - not syncing: Fatal exception Reviewed-by: Kees Cook Reviewed-by: Conor Dooley # ISA bits Tested-by: Nathan Chancellor Signed-off-by: Sami Tolvanen --- arch/riscv/Kconfig | 1 + arch/riscv/include/asm/cfi.h | 22 ++++++++++ arch/riscv/include/asm/insn.h | 10 +++++ arch/riscv/kernel/Makefile | 2 + arch/riscv/kernel/cfi.c | 77 +++++++++++++++++++++++++++++++++++ arch/riscv/kernel/traps.c | 4 +- 6 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 arch/riscv/include/asm/cfi.h create mode 100644 arch/riscv/kernel/cfi.c diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index a475ef1a0c1c..29fdba9d8514 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -49,6 +49,7 @@ config RISCV select ARCH_SUPPORTS_PER_VMA_LOCK if MMU select ARCH_USE_MEMTEST select ARCH_USE_QUEUED_RWLOCKS + select ARCH_USES_CFI_TRAPS if CFI_CLANG select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT if MMU select ARCH_WANT_FRAME_POINTERS select ARCH_WANT_GENERAL_HUGETLB if !RISCV_ISA_SVNAPOT diff --git a/arch/riscv/include/asm/cfi.h b/arch/riscv/include/asm/cfi.h new file mode 100644 index 000000000000..56bf9d69d5e3 --- /dev/null +++ b/arch/riscv/include/asm/cfi.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_RISCV_CFI_H +#define _ASM_RISCV_CFI_H + +/* + * Clang Control Flow Integrity (CFI) support. + * + * Copyright (C) 2023 Google LLC + */ + +#include + +#ifdef CONFIG_CFI_CLANG +enum bug_trap_type handle_cfi_failure(struct pt_regs *regs); +#else +static inline enum bug_trap_type handle_cfi_failure(struct pt_regs *regs) +{ + return BUG_TRAP_TYPE_NONE; +} +#endif /* CONFIG_CFI_CLANG */ + +#endif /* _ASM_RISCV_CFI_H */ diff --git a/arch/riscv/include/asm/insn.h b/arch/riscv/include/asm/insn.h index 4e1505cef8aa..9c23f598434c 100644 --- a/arch/riscv/include/asm/insn.h +++ b/arch/riscv/include/asm/insn.h @@ -63,6 +63,7 @@ #define RVG_RS1_OPOFF 15 #define RVG_RS2_OPOFF 20 #define RVG_RD_OPOFF 7 +#define RVG_RS1_MASK GENMASK(4, 0) #define RVG_RD_MASK GENMASK(4, 0) /* The bit field of immediate value in RVC J instruction */ @@ -129,6 +130,7 @@ #define RVC_C2_RS1_OPOFF 7 #define RVC_C2_RS2_OPOFF 2 #define RVC_C2_RD_OPOFF 7 +#define RVC_C2_RS1_MASK GENMASK(4, 0) /* parts of opcode for RVG*/ #define RVG_OPCODE_FENCE 0x0f @@ -278,6 +280,10 @@ static __always_inline bool riscv_insn_is_branch(u32 code) #define RV_X(X, s, mask) (((X) >> (s)) & (mask)) #define RVC_X(X, s, mask) RV_X(X, s, mask) +#define RV_EXTRACT_RS1_REG(x) \ + ({typeof(x) x_ = (x); \ + (RV_X(x_, RVG_RS1_OPOFF, RVG_RS1_MASK)); }) + #define RV_EXTRACT_RD_REG(x) \ ({typeof(x) x_ = (x); \ (RV_X(x_, RVG_RD_OPOFF, RVG_RD_MASK)); }) @@ -305,6 +311,10 @@ static __always_inline bool riscv_insn_is_branch(u32 code) (RV_X(x_, RV_B_IMM_11_OPOFF, RV_B_IMM_11_MASK) << RV_B_IMM_11_OFF) | \ (RV_IMM_SIGN(x_) << RV_B_IMM_SIGN_OFF); }) +#define RVC_EXTRACT_C2_RS1_REG(x) \ + ({typeof(x) x_ = (x); \ + (RV_X(x_, RVC_C2_RS1_OPOFF, RVC_C2_RS1_MASK)); }) + #define RVC_EXTRACT_JTYPE_IMM(x) \ ({typeof(x) x_ = (x); \ (RVC_X(x_, RVC_J_IMM_3_1_OPOFF, RVC_J_IMM_3_1_MASK) << RVC_J_IMM_3_1_OFF) | \ diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index 506cc4a9a45a..6ac56af42f4a 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -91,6 +91,8 @@ obj-$(CONFIG_CRASH_CORE) += crash_core.o obj-$(CONFIG_JUMP_LABEL) += jump_label.o +obj-$(CONFIG_CFI_CLANG) += cfi.o + obj-$(CONFIG_EFI) += efi.o obj-$(CONFIG_COMPAT) += compat_syscall_table.o obj-$(CONFIG_COMPAT) += compat_signal.o diff --git a/arch/riscv/kernel/cfi.c b/arch/riscv/kernel/cfi.c new file mode 100644 index 000000000000..820158d7a291 --- /dev/null +++ b/arch/riscv/kernel/cfi.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Clang Control Flow Integrity (CFI) support. + * + * Copyright (C) 2023 Google LLC + */ +#include +#include + +/* + * Returns the target address and the expected type when regs->epc points + * to a compiler-generated CFI trap. + */ +static bool decode_cfi_insn(struct pt_regs *regs, unsigned long *target, + u32 *type) +{ + unsigned long *regs_ptr = (unsigned long *)regs; + int rs1_num; + u32 insn; + + *target = *type = 0; + + /* + * The compiler generates the following instruction sequence + * for indirect call checks: + * + *   lw t1, -4() + * lui t2, + * addiw t2, t2, + * beq t1, t2, .Ltmp1 + * ebreak ; <- regs->epc + * .Ltmp1: + * jalr + * + * We can read the expected type and the target address from the + * registers passed to the beq/jalr instructions. + */ + if (get_kernel_nofault(insn, (void *)regs->epc - 4)) + return false; + if (!riscv_insn_is_beq(insn)) + return false; + + *type = (u32)regs_ptr[RV_EXTRACT_RS1_REG(insn)]; + + if (get_kernel_nofault(insn, (void *)regs->epc) || + get_kernel_nofault(insn, (void *)regs->epc + GET_INSN_LENGTH(insn))) + return false; + + if (riscv_insn_is_jalr(insn)) + rs1_num = RV_EXTRACT_RS1_REG(insn); + else if (riscv_insn_is_c_jalr(insn)) + rs1_num = RVC_EXTRACT_C2_RS1_REG(insn); + else + return false; + + *target = regs_ptr[rs1_num]; + + return true; +} + +/* + * Checks if the ebreak trap is because of a CFI failure, and handles the trap + * if needed. Returns a bug_trap_type value similarly to report_bug. + */ +enum bug_trap_type handle_cfi_failure(struct pt_regs *regs) +{ + unsigned long target; + u32 type; + + if (!is_cfi_trap(regs->epc)) + return BUG_TRAP_TYPE_NONE; + + if (!decode_cfi_insn(regs, &target, &type)) + return report_cfi_failure_noaddr(regs, regs->epc); + + return report_cfi_failure(regs, regs->epc, &target, type); +} diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c index f910dfccbf5d..212dc20631fb 100644 --- a/arch/riscv/kernel/traps.c +++ b/arch/riscv/kernel/traps.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -271,7 +272,8 @@ void handle_break(struct pt_regs *regs) == NOTIFY_STOP) return; #endif - else if (report_bug(regs->epc, regs) == BUG_TRAP_TYPE_WARN) + else if (report_bug(regs->epc, regs) == BUG_TRAP_TYPE_WARN || + handle_cfi_failure(regs) == BUG_TRAP_TYPE_WARN) regs->epc += get_break_insn_length(regs->epc); else die(regs, "Kernel BUG");