Received: by 2002:a05:6a10:6d10:0:0:0:0 with SMTP id gq16csp4623840pxb; Wed, 20 Apr 2022 07:07:19 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyuQkYTT8+5a8G9a/DP91xhdJXUSr3uLnW63/4ikzkyUiwWJBYloLjX9hw4Vjz1qr0aWImf X-Received: by 2002:a1f:1b56:0:b0:345:4d97:a2e7 with SMTP id b83-20020a1f1b56000000b003454d97a2e7mr6325955vkb.31.1650463639029; Wed, 20 Apr 2022 07:07:19 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1650463639; cv=none; d=google.com; s=arc-20160816; b=g6o50RuR3dWeBeBGkhlMFflHRqlr77LH49SQehBoF2NTlbQB94/UwI7FIYgOT36qEp 2hVMYmitgVgIxaGlyZdiafF06pBbCV9Fnq5ZTqdJToBOcKQN5lolyhjaQl9fjZJg0hGU kaU/sbq+JUROJp3c+4Lpk2DZ/w0gtFSH6pGycXQASTL3fiZ84fvZHH50QwggryipReJY pdGJcDZJts/jUr4SBqOttnD4gSbq12zXs9xXcwTEEjiNp/G19QXBkH6iK6ujihIPP3Ax oi15XJyx9eJAHyylcFhkv4EVJmaBbGit5ei2TihfaBBtYiCHx9iIq6OTExQMYDY4GgmE pKUA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=z7Ij0l/Sc6Ns+QJDF+9soPo08R+nzCG35yJXFG3L8GA=; b=1Kk6vGlPWfcNJMmD5vEJsV10e18azdOKK/czXNuGe60kCJGBadgegE7/VE3g5BJZxf H8uvm8exeteP9qu7pmGGkXuu+YFCNOzrCplASIorWV07Q/8Yj1+VrYsDtnvbDGoehiRH KFBKBglrTl7hMGG3mR4jvvKGdr+o39qvOc02gXS3ZpNIjao6qHeQqhicDJ7haIfzTzEB MxQj20+4R9orzrY+gYhUy5pwgDLhlAwGxQMN70VjWDV8DADKUXt+aqOOasCitV+oHezo QCtxxe6Qn8M3RWg5GEMJs6PKxnL0kUurept85Y6DzJ6W0du3rX3ROASYnCnDSSVswNac WnSQ== ARC-Authentication-Results: i=1; mx.google.com; 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 Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id a80-20020a1f9853000000b00340d7cfd418si162462vke.40.2022.04.20.07.06.59; Wed, 20 Apr 2022 07:07:18 -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; 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 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1358631AbiDTAqW (ORCPT + 99 others); Tue, 19 Apr 2022 20:46:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58740 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1358619AbiDTAqH (ORCPT ); Tue, 19 Apr 2022 20:46:07 -0400 Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 544E0205D3; Tue, 19 Apr 2022 17:43:22 -0700 (PDT) Received: (Authenticated sender: joao@overdrivepizza.com) by mail.gandi.net (Postfix) with ESMTPSA id 166011BF203; Wed, 20 Apr 2022 00:43:14 +0000 (UTC) From: joao@overdrivepizza.com To: linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Cc: joao@overdrivepizza.com, peterz@infradead.org, jpoimboe@redhat.com, andrew.cooper3@citrix.com, keescook@chromium.org, samitolvanen@google.com, mark.rutland@arm.com, hjl.tools@gmail.com, alyssa.milburn@linux.intel.com, ndesaulniers@google.com, gabriel.gomes@linux.intel.com, rick.p.edgecombe@intel.com Subject: [RFC PATCH 05/11] x86/text-patching: Support FineIBT text-patching Date: Tue, 19 Apr 2022 17:42:35 -0700 Message-Id: <20220420004241.2093-6-joao@overdrivepizza.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220420004241.2093-1-joao@overdrivepizza.com> References: <20220420004241.2093-1-joao@overdrivepizza.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_LOW, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE 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 From: Joao Moreira When patching a direct branch into text, consider that the target may have a FineIBT hash check sequence and then sum the respective offset to the branch target address if this is the case. This is needed to support static calls. Signed-off-by: Joao Moreira Tinkered-from-patches-by: Peter Zijlstra --- arch/x86/include/asm/text-patching.h | 92 +++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/text-patching.h b/arch/x86/include/asm/text-patching.h index d20ab0921480..a450761fae62 100644 --- a/arch/x86/include/asm/text-patching.h +++ b/arch/x86/include/asm/text-patching.h @@ -4,6 +4,7 @@ #include #include +#include #include struct paravirt_patch_site; @@ -66,6 +67,12 @@ extern void text_poke_finish(void); #define JMP8_INSN_SIZE 2 #define JMP8_INSN_OPCODE 0xEB +#define SUB_INSN_SIZE 7 +#define SUB_INSN_OPCODE 0x41 + +#define JE_INSN_SIZE 2 +#define JE_INSN_OPCODE 0x74 + #define DISP32_SIZE 4 static __always_inline int text_opcode_size(u8 opcode) @@ -96,6 +103,83 @@ union text_poke_insn { } __attribute__((packed)); }; +#ifdef CONFIG_X86_KERNEL_FINEIBT +#define FINEIBT_FIXUP 18 +// AFTER_FINEIBT = FINEIBT_FIXUP - ENDBR_LEN - XOR_LEN - JMP LEN +#define AFTER_FINEIBT FINEIBT_FIXUP - ENDBR_INSN_SIZE - 3 - 2 + +/// XXX: THIS IS *NOT* PROPERLY TESTED! +/// I did stumble on any scenario where this was needed while testing FineIBT, +/// Yet, I'm keeping this here for concept/future reference. - If we can't fix +/// the displacement, then the branch will always stumble on the FineIBT hash +/// check. To prevent that, patch the FineIBT hash check with nops. +static __always_inline +void bypass_fineibt_sequence(void *insn) { + static const char code[14] = { 0x4d, 0x31, 0xdb, 0xeb, AFTER_FINEIBT, + BYTES_NOP8, BYTES_NOP1 }; + if (unlikely(system_state == SYSTEM_BOOTING)) { + text_poke_early(insn + 4, code, 14); + text_poke_early(insn + 11, code, 14); + } + + text_poke_bp(insn + 4, code, 14, NULL); + text_poke_bp(insn + 11, code, 14, NULL); +} + +// Identify if the target address is a FineIBT instruction sequence, which +// should be: +// endbr +// sub $hash, %r11d +// je 1f +// call fineibt_handler (this will eventually be replaced with ud2) +// 1: +static __always_inline +bool __is_fineibt_sequence(const void *addr) { + union text_poke_insn text; + u32 insn; + + // the sequence starts with an endbr + if (get_kernel_nofault(insn, addr) || !(is_endbr(insn))) + return false; + + // then followed by a sub + if (get_kernel_nofault(text, addr+4) || text.opcode != SUB_INSN_OPCODE) + return false; + + // followed by a je + if (get_kernel_nofault(text, addr+11) || text.opcode != JE_INSN_OPCODE) + return false; + + // and finished with a call (which eventually will be an ud2) + if (get_kernel_nofault(text, addr+13) || + text.opcode != CALL_INSN_OPCODE) + return false; + + return true; +} + +// Verify if the branch target is a FineIBT sequence. If yes, fix the target +// to point right after the sequence, preventing crashes. +static __always_inline +void *__text_fix_fineibt_branch_target(const void *addr, void *dest, int size) { + bool fineibt; + s32 disp; + fineibt = __is_fineibt_sequence(dest); + if (!fineibt) + return dest; + + disp = (long) dest - (long) (addr + size) + FINEIBT_FIXUP; + + // if fineibt-fixed displacement doesn't fit as an operand, + // remove fineibt hash check from target. + if (size == 2 && ((disp >> 31) != (disp >> 7))) { + bypass_fineibt_sequence(dest); + return dest; + } + return dest + FINEIBT_FIXUP; +} +#endif + static __always_inline void __text_gen_insn(void *buf, u8 opcode, const void *addr, const void *dest, int size) { @@ -115,7 +199,13 @@ void __text_gen_insn(void *buf, u8 opcode, const void *addr, const void *dest, i insn->opcode = opcode; if (size > 1) { - insn->disp = (long)dest - (long)(addr + size); +#ifdef CONFIG_X86_KERNEL_FINEIBT + void *fineibt_dest = __text_fix_fineibt_branch_target(addr, + (void *) dest, size); + insn->disp = (long) fineibt_dest - (long) (addr + size); +#else + insn->disp = (long) dest - (long) (addr + size); +#endif if (size == 2) { /* * Ensure that for JMP8 the displacement -- 2.35.1