From patchwork Wed Nov 2 09:19:58 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: tip-bot2 for Thomas Gleixner X-Patchwork-Id: 14144 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:6687:0:0:0:0:0 with SMTP id l7csp3508706wru; Wed, 2 Nov 2022 02:25:51 -0700 (PDT) X-Google-Smtp-Source: AMsMyM6o1Fku1xL3De8lcEVQ3Nbgo95DMmFYm42Lmo3MDMFOiYyEFxsIEM9Whk+OCNB+bEkUwJPE X-Received: by 2002:aa7:d1c3:0:b0:461:c627:2a7b with SMTP id g3-20020aa7d1c3000000b00461c6272a7bmr23671361edp.231.1667381151244; Wed, 02 Nov 2022 02:25:51 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1667381151; cv=none; d=google.com; s=arc-20160816; b=IOcDhUaC0oCqR4xxtrtM7tbnMZ6NHS1uOtb9eam1V8kMwBytAtIyetmOltCmonj5cX yK1e1CWVZYIJiIh+E86zP0dD4ayDn9tGzfWGxreec/vY0kd/9S/ripE+2hNLXQM20v7/ 3nasKOX9MggW5muB1xfjJVq9ZIQqBJxLF8QGDUcIlLUK+w8BOSWykjcshRBIW+mwnhjh tGxs4hvgbyJ0xnfpWxWHnxidod2fM4q4W1icK3I5JOKRKM6xwTblRqEOL8A3dnszqxno 1NMYSdRePmtLq7VH+1i+U7fZ8OO4Cl1uYGRYebhTfTfAD4iKwW1u+wue/rzFp7BKYOqX zpjw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:robot-unsubscribe :robot-id:message-id:mime-version:references:in-reply-to:cc:subject :to:reply-to:sender:from:dkim-signature:dkim-signature:date; bh=VbDQoEBEQalCcwDd/vLZU9zQRL0nPpNFi0s6qMisUj8=; b=KKdT2pkgWJWLy/KQcPYFW25S+k/fU8YYpLcsL3MK/rkfhPg09oLrPr2Wu4lmkp7Pcn qi0Yeubf4jr04jL+iFaDSkXMBqBkegyFCEZdR3Iet+F+oy3+3htrsZB98loJyE1JWRv7 k4Nbzyh1fLt1eAldAJSbOGOkMcusdSoXVX8lHlvQQ+udLRghnodH9pX1TzJeGD/BG2EE WeeXXlpylhgauC9sK6JVwA1rLWgyI4Ptgq2ZlXa9XibBq8OjDE3pMvw2hhStInj8akbv Weww/sr+O+VRh53Rs+rHYI1bzRcPOI5l3MYeB7BxPEJFF0Rimom8LTcUfgAvPsKKufWV mH2A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linutronix.de header.s=2020 header.b=fkLJBbOi; dkim=neutral (no key) header.i=@linutronix.de; 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=NONE sp=QUARANTINE dis=NONE) header.from=linutronix.de Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id o8-20020a17090637c800b007a6ec6fb027si12347325ejc.538.2022.11.02.02.25.27; Wed, 02 Nov 2022 02:25:51 -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=@linutronix.de header.s=2020 header.b=fkLJBbOi; dkim=neutral (no key) header.i=@linutronix.de; 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=NONE sp=QUARANTINE dis=NONE) header.from=linutronix.de Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230457AbiKBJVh (ORCPT + 99 others); Wed, 2 Nov 2022 05:21:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51246 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230519AbiKBJVR (ORCPT ); Wed, 2 Nov 2022 05:21:17 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 04D2E647F; Wed, 2 Nov 2022 02:20:01 -0700 (PDT) Date: Wed, 02 Nov 2022 09:19:58 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1667380799; h=from:from:sender:sender:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=VbDQoEBEQalCcwDd/vLZU9zQRL0nPpNFi0s6qMisUj8=; b=fkLJBbOiGINc6f9ul8djcHRy9BA4lVKem1UKYqMBlQ3ZMRPVgoxfk68h9BV2rbFw3uMz30 58evs+3WmwE18Eu0LiM9L2UohCE9zeHfPEPo32vbCaHmi5rwcWBR4xr7DiYzT3mgR7CuVP DqBh5uGOSqMIEjRYsf4NOnQt40ry+EQUAyLfdLgx0Ja5hGBWMtjI83zIconaGTovA530z5 72QJRY9HjmukgUJoLntgV9P2oPmRnpyGAsH6agz/upEjEBTGBGODwfzthdc6jKBTW4S9mg PT6HskhRfHD+HkNhEiSLsD/f/aH/WClCAkPZTCqIl7MZP7VVPMJVcK3hkpQiiw== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1667380799; h=from:from:sender:sender:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=VbDQoEBEQalCcwDd/vLZU9zQRL0nPpNFi0s6qMisUj8=; b=GmFA558kIoO3Zl1nJhEI9lcVkd8Eve38ajir3KA6jYPehCnCe3XHCg0eiBEPs1tUPQBUfX ytcjuB4STz1vaBBA== From: "tip-bot2 for Peter Zijlstra" Sender: tip-bot2@linutronix.de Reply-to: linux-kernel@vger.kernel.org To: linux-tip-commits@vger.kernel.org Subject: [tip: x86/core] x86/cfi: Add boot time hash randomization Cc: Kees Cook , "Peter Zijlstra (Intel)" , x86@kernel.org, linux-kernel@vger.kernel.org In-Reply-To: <20221027092842.765195516@infradead.org> References: <20221027092842.765195516@infradead.org> MIME-Version: 1.0 Message-ID: <166738079813.7716.11159577231772690253.tip-bot2@tip-bot2> Robot-ID: Robot-Unsubscribe: Contact to get blacklisted from these emails X-Spam-Status: No, score=-4.4 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_MED,SPF_HELO_NONE, SPF_PASS 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: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1747833341601337866?= X-GMAIL-MSGID: =?utf-8?q?1748375858298986145?= The following commit has been merged into the x86/core branch of tip: Commit-ID: 0c3e806ec0f9771fa1f34c60499097d9260a8bb7 Gitweb: https://git.kernel.org/tip/0c3e806ec0f9771fa1f34c60499097d9260a8bb7 Author: Peter Zijlstra AuthorDate: Thu, 27 Oct 2022 11:28:16 +02:00 Committer: Peter Zijlstra CommitterDate: Tue, 01 Nov 2022 13:44:11 +01:00 x86/cfi: Add boot time hash randomization In order to avoid known hashes (from knowing the boot image), randomize the CFI hashes with a per-boot random seed. Suggested-by: Kees Cook Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20221027092842.765195516@infradead.org --- arch/x86/kernel/alternative.c | 120 +++++++++++++++++++++++++++++---- 1 file changed, 108 insertions(+), 12 deletions(-) diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 9d3b587..aa7f791 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -711,6 +711,24 @@ enum cfi_mode { }; static enum cfi_mode cfi_mode __ro_after_init = CFI_DEFAULT; +static bool cfi_rand __ro_after_init = true; +static u32 cfi_seed __ro_after_init; + +/* + * Re-hash the CFI hash with a boot-time seed while making sure the result is + * not a valid ENDBR instruction. + */ +static u32 cfi_rehash(u32 hash) +{ + hash ^= cfi_seed; + while (unlikely(is_endbr(hash) || is_endbr(-hash))) { + bool lsb = hash & 1; + hash >>= 1; + if (lsb) + hash ^= 0x80200003; + } + return hash; +} static __init int cfi_parse_cmdline(char *str) { @@ -728,10 +746,13 @@ static __init int cfi_parse_cmdline(char *str) cfi_mode = CFI_DEFAULT; } else if (!strcmp(str, "off")) { cfi_mode = CFI_OFF; + cfi_rand = false; } else if (!strcmp(str, "kcfi")) { cfi_mode = CFI_KCFI; } else if (!strcmp(str, "fineibt")) { cfi_mode = CFI_FINEIBT; + } else if (!strcmp(str, "norand")) { + cfi_rand = false; } else { pr_err("Ignoring unknown cfi option (%s).", str); } @@ -856,7 +877,50 @@ static int cfi_disable_callers(s32 *start, s32 *end) return 0; } +static int cfi_enable_callers(s32 *start, s32 *end) +{ + /* + * Re-enable kCFI, undo what cfi_disable_callers() did. + */ + const u8 mov[] = { 0x41, 0xba }; + s32 *s; + + for (s = start; s < end; s++) { + void *addr = (void *)s + *s; + u32 hash; + + addr -= fineibt_caller_size; + hash = decode_caller_hash(addr); + if (!hash) /* nocfi callers */ + continue; + + text_poke_early(addr, mov, 2); + } + + return 0; +} + /* .cfi_sites */ +static int cfi_rand_preamble(s32 *start, s32 *end) +{ + s32 *s; + + for (s = start; s < end; s++) { + void *addr = (void *)s + *s; + u32 hash; + + hash = decode_preamble_hash(addr); + if (WARN(!hash, "no CFI hash found at: %pS %px %*ph\n", + addr, addr, 5, addr)) + return -EINVAL; + + hash = cfi_rehash(hash); + text_poke_early(addr + 1, &hash, 4); + } + + return 0; +} + static int cfi_rewrite_preamble(s32 *start, s32 *end) { s32 *s; @@ -879,6 +943,25 @@ static int cfi_rewrite_preamble(s32 *start, s32 *end) } /* .retpoline_sites */ +static int cfi_rand_callers(s32 *start, s32 *end) +{ + s32 *s; + + for (s = start; s < end; s++) { + void *addr = (void *)s + *s; + u32 hash; + + addr -= fineibt_caller_size; + hash = decode_caller_hash(addr); + if (hash) { + hash = -cfi_rehash(hash); + text_poke_early(addr + 2, &hash, 4); + } + } + + return 0; +} + static int cfi_rewrite_callers(s32 *start, s32 *end) { s32 *s; @@ -915,31 +998,44 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, cfi_mode = CFI_FINEIBT; } - switch (cfi_mode) { - case CFI_OFF: - ret = cfi_disable_callers(start_retpoline, end_retpoline); + /* + * Rewrite the callers to not use the __cfi_ stubs, such that we might + * rewrite them. This disables all CFI. If this succeeds but any of the + * later stages fails, we're without CFI. + */ + ret = cfi_disable_callers(start_retpoline, end_retpoline); + if (ret) + goto err; + + if (cfi_rand) { + if (builtin) + cfi_seed = get_random_u32(); + + ret = cfi_rand_preamble(start_cfi, end_cfi); if (ret) goto err; + ret = cfi_rand_callers(start_retpoline, end_retpoline); + if (ret) + goto err; + } + + switch (cfi_mode) { + case CFI_OFF: if (builtin) pr_info("Disabling CFI\n"); return; case CFI_KCFI: + ret = cfi_enable_callers(start_retpoline, end_retpoline); + if (ret) + goto err; + if (builtin) pr_info("Using kCFI\n"); return; case CFI_FINEIBT: - /* - * Rewrite the callers to not use the __cfi_ stubs, such that we might - * rewrite them. This disables all CFI. If this succeeds but any of the - * later stages fails, we're without CFI. - */ - ret = cfi_disable_callers(start_retpoline, end_retpoline); - if (ret) - goto err; - ret = cfi_rewrite_preamble(start_cfi, end_cfi); if (ret) goto err;