Message ID | 016c1e9cbdf726a885a406ff6baed85087ad1213.1678474914.git.jpoimboe@kernel.org |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:5915:0:0:0:0:0 with SMTP id v21csp1092293wrd; Fri, 10 Mar 2023 12:48:43 -0800 (PST) X-Google-Smtp-Source: AK7set/SQW/E/g/95whyQr9K0vAEjEbznY26gYgLR1iam7GBgdrScvngQEY7ytHZiDfZz59zfM1H X-Received: by 2002:a17:903:1105:b0:19e:2603:f25c with SMTP id n5-20020a170903110500b0019e2603f25cmr32111107plh.51.1678481323378; Fri, 10 Mar 2023 12:48:43 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1678481323; cv=none; d=google.com; s=arc-20160816; b=bYp6shOEwq9YpIiT6xPl6Bj1Z8mXgX4/b1Bqtohif1nsK5EklwYb+9R40Rox5EYOP/ p9xV4G8mKA7oKOpM08rPiIlyu38GtPezXwLB4aNLcrmt2FRN+JQqxarqM2ChyYq49zuv hjIhZokMi+64lErn32R3TVQxqxbUQZCeK5rwd5D3IZpX7p6vj7PxLtyiaCtr1EkaRo8z B0RWkFUB/yQ+529QL+AS0Dzl5UUc4lwUa5ybtQPcGKZEfhTptorz3AdruWgtvuPV1FnG M3FW/IieZZmVmvPS800xOb3r7NAvr7lQtOs8HqLX7SD2p44x49M7hfHgh34F4gguH94B 5VMw== 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 :dkim-signature; bh=j3pR90jS3RN4vmEujm8H57FBAiRTxJNH3m4SZqBkIOA=; b=n4S8kEBBPEr2qIGtcluLQexRFtu2PSrOAtk7VWPuh0aoJ9wUs5TE/rLkzWnmGwl7WD RdKYFkxDpdoLzL1rH4J44x9JwWf27y1+Z4La9Md7vpOwwuRaQ04ilAXYGuLxygiACwBM 7qwZC6qrMu9k7FA7M4Wlj0tvZ8WRqLYgyz+bbjMSLFS7B34LPXaUK6hD8ALnl5pjc7Lf tZcp8HsCaDG5nV2yxRS1bDP7gjuMHiQylNcRc59JCR2kHKMmMhvKUY3td1MHGW4gF2FO yZ60nkHmUTCYdC+yxHFXvnMsmLVRy+i9w7OuygeG8PLu61X67FVG3MHH3XSffe/z1M3Z nDwA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=nDBbjZZZ; 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=NONE dis=NONE) header.from=kernel.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id ks11-20020a170903084b00b0019ca7d56092si749743plb.63.2023.03.10.12.48.30; Fri, 10 Mar 2023 12:48:43 -0800 (PST) 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=@kernel.org header.s=k20201202 header.b=nDBbjZZZ; 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=NONE dis=NONE) header.from=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231553AbjCJUeE (ORCPT <rfc822;carlos.wei.hk@gmail.com> + 99 others); Fri, 10 Mar 2023 15:34:04 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47164 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229994AbjCJUdu (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Fri, 10 Mar 2023 15:33:50 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 95C17F76E for <linux-kernel@vger.kernel.org>; Fri, 10 Mar 2023 12:33:00 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 4562B61D4D for <linux-kernel@vger.kernel.org>; Fri, 10 Mar 2023 20:31:49 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 471BBC433A1; Fri, 10 Mar 2023 20:31:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1678480308; bh=yMo6mdBxavTxXroIIa/I0/ynsahgXKDKMHjOHkltf0k=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=nDBbjZZZOXowJzL/k0G4ozYPUDsri43IgnECnwBjCtR31RJeSMu6eKLZ2RgdXgXLL DrLuv40QCYcEUsh0eKHNR6GtyVLeK4hnXnCYXtHWXSHkqilqbKO1dEPSkecGAK4nn7 n7UcCK99cPPVeWFrkUlueiqbp2K4quxWCNPJBiayd0tBx4OCFF+/8GeVbjqgiNb3Fh H/xomz7ZxXjejGVAatuZHoCa/3Xy57oPE+sgfddt+UpL+pIUzKy8FJN6naTga3eUdi aKPlMHcoGP/hUXu/+4T/+z8sdn2vyVbc3iUdPNySwtB69TneGDD15ubvLISlC4h+gn haex9ypNqUxcw== From: Josh Poimboeuf <jpoimboe@kernel.org> To: x86@kernel.org Cc: linux-kernel@vger.kernel.org, Peter Zijlstra <peterz@infradead.org>, Mark Rutland <mark.rutland@arm.com>, Jason Baron <jbaron@akamai.com>, Steven Rostedt <rostedt@goodmis.org>, Ard Biesheuvel <ardb@kernel.org>, Christophe Leroy <christophe.leroy@csgroup.eu>, Paolo Bonzini <pbonzini@redhat.com>, Sean Christopherson <seanjc@google.com> Subject: [RFC][PATCH 1/5] static_call: Make NULL static calls consistent Date: Fri, 10 Mar 2023 12:31:13 -0800 Message-Id: <016c1e9cbdf726a885a406ff6baed85087ad1213.1678474914.git.jpoimboe@kernel.org> X-Mailer: git-send-email 2.39.2 In-Reply-To: <cover.1678474914.git.jpoimboe@kernel.org> References: <cover.1678474914.git.jpoimboe@kernel.org> MIME-Version: 1.0 Content-type: text/plain Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-4.4 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, 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: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1760015232253257385?= X-GMAIL-MSGID: =?utf-8?q?1760015232253257385?= |
Series |
Improve static call NULL handling
|
|
Commit Message
Josh Poimboeuf
March 10, 2023, 8:31 p.m. UTC
NULL static calls have inconsistent behavior. With HAVE_STATIC_CALL=y
they're a NOP, but with HAVE_STATIC_CALL=n they're a panic.
That's guaranteed to cause subtle bugs. Make the behavior consistent by
making NULL static calls a NOP with HAVE_STATIC_CALL=n.
This is probably easier than doing the reverse (making NULL static calls
panic with HAVE_STATIC_CALL=y).
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
include/linux/static_call.h | 53 +++++++------------------------------
1 file changed, 9 insertions(+), 44 deletions(-)
Comments
On Fri, Mar 10, 2023 at 12:31:13PM -0800, Josh Poimboeuf wrote: > -/* > - * This horrific hack takes care of two things: > - * > - * - it ensures the compiler will only load the function pointer ONCE, > - * which avoids a reload race. > - * > - * - it ensures the argument evaluation is unconditional, similar > - * to the HAVE_STATIC_CALL variant. > - * > - * Sadly current GCC/Clang (10 for both) do not optimize this properly > - * and will emit an indirect call for the NULL case :-( > - */ > -#define __static_call_cond(name) \ > -({ \ > - void *func = READ_ONCE(STATIC_CALL_KEY(name).func); \ > - if (!func) \ > - func = &__static_call_nop; \ > - (typeof(STATIC_CALL_TRAMP(name))*)func; \ > -}) So a sufficiently clever compiler can optimize the above to avoid the actual indirect call (and resulting CFI violation, see below), because __static_call_nop() is inline and hence visible as an empty stub function. Currently none of the compilers are that clever :/ > -#define static_call_cond(name) (void)__static_call_cond(name) > +#define static_call_cond(name) (void)static_call(name) > > static inline > void __static_call_update(struct static_call_key *key, void *tramp, void *func) > { > - WRITE_ONCE(key->func, func); > + WRITE_ONCE(key->func, func ? : (void *)__static_call_nop); > } This will break ARM64 I think, they don't HAVE_STATIC_CALL but do have CLANG_CFI, which means the above will end up being a runtime indirect call to a non-matching signature function. Now, I suppose we don't actually have this happen in current code by the simple expedient of not actually having any static_call_cond() usage outside of arch code. (/me git-grep's some and *arrrggh* trusted-keys) I really don't think we can do this though, must not promote CFI violations.
On Fri, Mar 10, 2023 at 09:59:26PM +0100, Peter Zijlstra wrote: > > -#define __static_call_cond(name) \ > > -({ \ > > - void *func = READ_ONCE(STATIC_CALL_KEY(name).func); \ > > - if (!func) \ > > - func = &__static_call_nop; \ > > - (typeof(STATIC_CALL_TRAMP(name))*)func; \ > > -}) > > So a sufficiently clever compiler can optimize the above to avoid the > actual indirect call (and resulting CFI violation, see below), because > __static_call_nop() is inline and hence visible as an empty stub > function. Currently none of the compilers are that clever :/ I won't hold my breath waiting for theoretical optimizations. > This will break ARM64 I think, they don't HAVE_STATIC_CALL but do have > CLANG_CFI, which means the above will end up being a runtime indirect > call to a non-matching signature function. > > Now, I suppose we don't actually have this happen in current code by the > simple expedient of not actually having any static_call_cond() usage > outside of arch code. > > (/me git-grep's some and *arrrggh* trusted-keys) > > I really don't think we can do this though, must not promote CFI > violations. Ouch, so static_call_cond() and __static_call_return0() are broken today on CFI_CLANG + arm64. Some ideas: 1) Implement HAVE_STATIC_CALL for arm64. IIRC, this wasn't worth the effort due to restricted branch ranges and CFI fun. 2) Create yet another "tier" of static call implementations, for arches which can have the unfortunate combo of CFI_CLANG + !HAVE_STATIC_CALL. CONFIG_ALMOST_DONT_HAVE_STATIC_CALL? The arch can define ARCH_DEFINE_STATIC_CALL_NOP() which uses inline asm to create a CFI-compliant NOP/BUG/whatever version of the function (insert lots of hand-waving). Is the kcfi hash available to inline asm at build time? 3) Use a jump label to bypass the static call instead of calling __static_call_nop(). NOTE: I couldn't figure out how to do this without angering the compiler, unless we want to change static_call() back to the old-school interface: static_call(foo, args...) Is it Friday yet?
On Fri, Mar 10, 2023 at 05:20:04PM -0800, Josh Poimboeuf wrote: > On Fri, Mar 10, 2023 at 09:59:26PM +0100, Peter Zijlstra wrote: > > > -#define __static_call_cond(name) \ > > > -({ \ > > > - void *func = READ_ONCE(STATIC_CALL_KEY(name).func); \ > > > - if (!func) \ > > > - func = &__static_call_nop; \ > > > - (typeof(STATIC_CALL_TRAMP(name))*)func; \ > > > -}) > > > > So a sufficiently clever compiler can optimize the above to avoid the > > actual indirect call (and resulting CFI violation, see below), because > > __static_call_nop() is inline and hence visible as an empty stub > > function. Currently none of the compilers are that clever :/ > > I won't hold my breath waiting for theoretical optimizations. Well, I'm thinking the clang folks might like this option to unbreak the arm64 build. At least here they have a fighting chance of actually doing the right thing. Let me Cc some actual compiler folks. > > This will break ARM64 I think, they don't HAVE_STATIC_CALL but do have > > CLANG_CFI, which means the above will end up being a runtime indirect > > call to a non-matching signature function. > > > > Now, I suppose we don't actually have this happen in current code by the > > simple expedient of not actually having any static_call_cond() usage > > outside of arch code. > > > > (/me git-grep's some and *arrrggh* trusted-keys) > > > > I really don't think we can do this though, must not promote CFI > > violations. > > Ouch, so static_call_cond() and __static_call_return0() are broken today > on CFI_CLANG + arm64. Yes. Now __static_call_return0() should really only happen when HAVE_STATIC_CALL per the definition only being available in that case. And static_call_cond() as implemented today *might* just be fixable by the compiler. > Some ideas: > > 1) Implement HAVE_STATIC_CALL for arm64. IIRC, this wasn't worth the > effort due to restricted branch ranges and CFI fun. The powerpc32 thing did it, iirc a similar approach could work for arm. But this would basically mandate HAVE_STATIC_CALL for CFI_CLANG. > > 2) Create yet another "tier" of static call implementations, for > arches which can have the unfortunate combo of CFI_CLANG + > !HAVE_STATIC_CALL. CONFIG_ALMOST_DONT_HAVE_STATIC_CALL? > > The arch can define ARCH_DEFINE_STATIC_CALL_NOP() which uses inline > asm to create a CFI-compliant NOP/BUG/whatever version of the > function (insert lots of hand-waving). Is the kcfi hash available > to inline asm at build time? Yes, clang creates magic symbol for everything it sees a declaration for. This symbols can be referenced from asm, linking will make it all work. And yes, C sucks, you can't actually create a function definition from a type :/ Otherwise this could be trivially fixable. > 3) Use a jump label to bypass the static call instead of calling > __static_call_nop(). NOTE: I couldn't figure out how to do this > without angering the compiler, unless we want to change > static_call() back to the old-school interface: > > static_call(foo, args...) > > Is it Friday yet? Always right :-) And yes, the whole premise of all this is that we let the compiler generate the actuall CALL and then have objtool scan the output and report the locations of them. There is no way to intercept this at the compiler level.
On Sun, Mar 12, 2023, Peter Zijlstra wrote: > On Fri, Mar 10, 2023 at 05:20:04PM -0800, Josh Poimboeuf wrote: > > On Fri, Mar 10, 2023 at 09:59:26PM +0100, Peter Zijlstra wrote: > > > > -#define __static_call_cond(name) \ > > > > -({ \ > > > > - void *func = READ_ONCE(STATIC_CALL_KEY(name).func); \ > > > > - if (!func) \ > > > > - func = &__static_call_nop; \ > > > > - (typeof(STATIC_CALL_TRAMP(name))*)func; \ > > > > -}) > > > > > > So a sufficiently clever compiler can optimize the above to avoid the > > > actual indirect call (and resulting CFI violation, see below), because > > > __static_call_nop() is inline and hence visible as an empty stub > > > function. Currently none of the compilers are that clever :/ > > > > I won't hold my breath waiting for theoretical optimizations. > > Well, I'm thinking the clang folks might like this option to unbreak the > arm64 build. At least here they have a fighting chance of actually doing > the right thing. > > Let me Cc some actual compiler folks. +Will and Kees too for the arm64+CFI mess. https://lore.kernel.org/all/YfrQzoIWyv9lNljh@google.com > > > This will break ARM64 I think, they don't HAVE_STATIC_CALL but do have > > > CLANG_CFI, which means the above will end up being a runtime indirect > > > call to a non-matching signature function. > > > > > > Now, I suppose we don't actually have this happen in current code by the > > > simple expedient of not actually having any static_call_cond() usage > > > outside of arch code. > > > > > > (/me git-grep's some and *arrrggh* trusted-keys) > > > > > > I really don't think we can do this though, must not promote CFI > > > violations. > > > > Ouch, so static_call_cond() and __static_call_return0() are broken today > > on CFI_CLANG + arm64. > > Yes. Now __static_call_return0() should really only happen when > HAVE_STATIC_CALL per the definition only being available in that case. > > And static_call_cond() as implemented today *might* just be fixable by > the compiler. > > > Some ideas: > > > > 1) Implement HAVE_STATIC_CALL for arm64. IIRC, this wasn't worth the > > effort due to restricted branch ranges and CFI fun. > > The powerpc32 thing did it, iirc a similar approach could work for arm. > But this would basically mandate HAVE_STATIC_CALL for CFI_CLANG. > > > > > 2) Create yet another "tier" of static call implementations, for > > arches which can have the unfortunate combo of CFI_CLANG + > > !HAVE_STATIC_CALL. CONFIG_ALMOST_DONT_HAVE_STATIC_CALL? > > > > The arch can define ARCH_DEFINE_STATIC_CALL_NOP() which uses inline > > asm to create a CFI-compliant NOP/BUG/whatever version of the > > function (insert lots of hand-waving). Is the kcfi hash available > > to inline asm at build time? > > Yes, clang creates magic symbol for everything it sees a declaration > for. This symbols can be referenced from asm, linking will make it all > work. > > And yes, C sucks, you can't actually create a function definition from a > type :/ Otherwise this could be trivially fixable. > > > 3) Use a jump label to bypass the static call instead of calling > > __static_call_nop(). NOTE: I couldn't figure out how to do this > > without angering the compiler, unless we want to change > > static_call() back to the old-school interface: > > > > static_call(foo, args...) > > > > Is it Friday yet? > > Always right :-) > > And yes, the whole premise of all this is that we let the compiler > generate the actuall CALL and then have objtool scan the output and > report the locations of them. There is no way to intercept this at the > compiler level.
On Sun, Mar 12, 2023 at 8:17 AM Peter Zijlstra <peterz@infradead.org> wrote: > > On Fri, Mar 10, 2023 at 05:20:04PM -0800, Josh Poimboeuf wrote: > > 2) Create yet another "tier" of static call implementations, for > > arches which can have the unfortunate combo of CFI_CLANG + > > !HAVE_STATIC_CALL. CONFIG_ALMOST_DONT_HAVE_STATIC_CALL? > > > > The arch can define ARCH_DEFINE_STATIC_CALL_NOP() which uses inline > > asm to create a CFI-compliant NOP/BUG/whatever version of the > > function (insert lots of hand-waving). Is the kcfi hash available > > to inline asm at build time? > > Yes, clang creates magic symbol for everything it sees a declaration > for. This symbols can be referenced from asm, linking will make it all > work. > > And yes, C sucks, you can't actually create a function definition from a > type :/ Otherwise this could be trivially fixable. Wouldn't creating a separate inline assembly nop function that references the CFI hash of another function with the correct type potentially solve this issue like Josh suggested? Sami
On Mon, Mar 13, 2023 at 10:48:58AM -0700, Sami Tolvanen wrote: > On Sun, Mar 12, 2023 at 8:17 AM Peter Zijlstra <peterz@infradead.org> wrote: > > > > On Fri, Mar 10, 2023 at 05:20:04PM -0800, Josh Poimboeuf wrote: > > > 2) Create yet another "tier" of static call implementations, for > > > arches which can have the unfortunate combo of CFI_CLANG + > > > !HAVE_STATIC_CALL. CONFIG_ALMOST_DONT_HAVE_STATIC_CALL? > > > > > > The arch can define ARCH_DEFINE_STATIC_CALL_NOP() which uses inline > > > asm to create a CFI-compliant NOP/BUG/whatever version of the > > > function (insert lots of hand-waving). Is the kcfi hash available > > > to inline asm at build time? > > > > Yes, clang creates magic symbol for everything it sees a declaration > > for. This symbols can be referenced from asm, linking will make it all > > work. > > > > And yes, C sucks, you can't actually create a function definition from a > > type :/ Otherwise this could be trivially fixable. > > Wouldn't creating a separate inline assembly nop function that > references the CFI hash of another function with the correct type > potentially solve this issue like Josh suggested? Right, I was thinking something like this, where the nop function gets generated by DEFINE_STATIC_CALL(). Completely untested of course... #define STATIC_CALL_NOP_PREFIX __SCN__ #define STATIC_CALL_NOP(name) __PASTE(STATIC_CALL_NOP_PREFIX, name) #define STATIC_CALL_NOP_STR(name) __stringify(STATIC_CALL_NOP(name)) #define ARCH_DEFINE_STATIC_CALL_NOP(name, func) \ asm(".align 4 \n" \ ".word __kcfi_typeid_" STATIC_CALL_NOP_STR(name) " \n" \ ".globl " STATIC_CALL_NOP_STR(name) " \n" \ STATIC_CALL_NOP_STR(name) ": \n" \ "bti c \n" \ "mov x0, xzr \n" \ "ret \n" \ ".type " STATIC_CALL_NOP_STR(name) ", @function \n" \ ".size " STATIC_CALL_NOP_STR(name) ", . - " STATIC_CALL_NOP_STR(name) " \n") #define DECLARE_STATIC_CALL(name, func) \ extern struct static_call_key STATIC_CALL_KEY(name); \ extern typeof(func) STATIC_CALL_TRAMP(name) \ extern typeof(func) STATIC_CALL_NOP(name) #define DEFINE_STATIC_CALL(name, _func, _func_init) \ DECLARE_STATIC_CALL(name, _func); \ ARCH_DEFINE_STATIC_CALL_NOP(name); \ struct static_call_key STATIC_CALL_KEY(name) = { \ .func = _func_init, \ }
On Mon, Mar 13, 2023 at 06:58:36PM -0700, Josh Poimboeuf wrote: > On Mon, Mar 13, 2023 at 10:48:58AM -0700, Sami Tolvanen wrote: > > On Sun, Mar 12, 2023 at 8:17 AM Peter Zijlstra <peterz@infradead.org> wrote: > > > > > > On Fri, Mar 10, 2023 at 05:20:04PM -0800, Josh Poimboeuf wrote: > > > > 2) Create yet another "tier" of static call implementations, for > > > > arches which can have the unfortunate combo of CFI_CLANG + > > > > !HAVE_STATIC_CALL. CONFIG_ALMOST_DONT_HAVE_STATIC_CALL? > > > > > > > > The arch can define ARCH_DEFINE_STATIC_CALL_NOP() which uses inline > > > > asm to create a CFI-compliant NOP/BUG/whatever version of the > > > > function (insert lots of hand-waving). Is the kcfi hash available > > > > to inline asm at build time? > > > > > > Yes, clang creates magic symbol for everything it sees a declaration > > > for. This symbols can be referenced from asm, linking will make it all > > > work. > > > > > > And yes, C sucks, you can't actually create a function definition from a > > > type :/ Otherwise this could be trivially fixable. > > > > Wouldn't creating a separate inline assembly nop function that > > references the CFI hash of another function with the correct type > > potentially solve this issue like Josh suggested? Yes it would, and the below looks about right. It's just a shame the C language itself cannot sanely express that. Also, having a ton of silly little nop functions is daft, but alas. > Right, I was thinking something like this, where the nop function gets > generated by DEFINE_STATIC_CALL(). > > Completely untested of course... > > #define STATIC_CALL_NOP_PREFIX __SCN__ > #define STATIC_CALL_NOP(name) __PASTE(STATIC_CALL_NOP_PREFIX, name) > #define STATIC_CALL_NOP_STR(name) __stringify(STATIC_CALL_NOP(name)) > > #define ARCH_DEFINE_STATIC_CALL_NOP(name, func) \ > asm(".align 4 \n" \ IIRC arm64 just changed (or is about to) their alignment muck. I think you can write this like: ".balign " __stringify(CONFIG_FUNCTION_ALIGNMENT) " \n" \ or somesuch... > ".word __kcfi_typeid_" STATIC_CALL_NOP_STR(name) " \n" \ > ".globl " STATIC_CALL_NOP_STR(name) " \n" \ > STATIC_CALL_NOP_STR(name) ": \n" \ > "bti c \n" \ > "mov x0, xzr \n" \ > "ret \n" \ > ".type " STATIC_CALL_NOP_STR(name) ", @function \n" \ > ".size " STATIC_CALL_NOP_STR(name) ", . - " STATIC_CALL_NOP_STR(name) " \n") > > #define DECLARE_STATIC_CALL(name, func) \ > extern struct static_call_key STATIC_CALL_KEY(name); \ > extern typeof(func) STATIC_CALL_TRAMP(name) \ > extern typeof(func) STATIC_CALL_NOP(name) > > #define DEFINE_STATIC_CALL(name, _func, _func_init) \ > DECLARE_STATIC_CALL(name, _func); \ > ARCH_DEFINE_STATIC_CALL_NOP(name); \ > struct static_call_key STATIC_CALL_KEY(name) = { \ > .func = _func_init, \ > } > -- > Josh
diff --git a/include/linux/static_call.h b/include/linux/static_call.h index 141e6b176a1b..8b12216da0da 100644 --- a/include/linux/static_call.h +++ b/include/linux/static_call.h @@ -65,20 +65,12 @@ * * Notes on NULL function pointers: * - * Static_call()s support NULL functions, with many of the caveats that - * regular function pointers have. + * A static_call() to a NULL function pointer is a NOP. * - * Clearly calling a NULL function pointer is 'BAD', so too for - * static_call()s (although when HAVE_STATIC_CALL it might not be immediately - * fatal). A NULL static_call can be the result of: + * A NULL static call can be the result of: * * DECLARE_STATIC_CALL_NULL(my_static_call, void (*)(int)); * - * which is equivalent to declaring a NULL function pointer with just a - * typename: - * - * void (*my_func_ptr)(int arg1) = NULL; - * * or using static_call_update() with a NULL function. In both cases the * HAVE_STATIC_CALL implementation will patch the trampoline with a RET * instruction, instead of an immediate tail-call JMP. HAVE_STATIC_CALL_INLINE @@ -92,13 +84,6 @@ * * where the argument evaludation also depends on the pointer value. * - * When calling a static_call that can be NULL, use: - * - * static_call_cond(name)(arg1); - * - * which will include the required value tests to avoid NULL-pointer - * dereferences. - * * To query which function is currently set to be called, use: * * func = static_call_query(name); @@ -106,7 +91,7 @@ * * DEFINE_STATIC_CALL_RET0 / __static_call_return0: * - * Just like how DEFINE_STATIC_CALL_NULL() / static_call_cond() optimize the + * Just like how DEFINE_STATIC_CALL_NULL() optimizes the * conditional void function call, DEFINE_STATIC_CALL_RET0 / * __static_call_return0 optimize the do nothing return 0 function. * @@ -279,10 +264,12 @@ extern long __static_call_return0(void); #define EXPORT_STATIC_CALL_TRAMP_GPL(name) \ EXPORT_SYMBOL_GPL(STATIC_CALL_TRAMP(name)) -#else /* Generic implementation */ +#else /* !CONFIG_HAVE_STATIC_CALL */ static inline int static_call_init(void) { return 0; } +static inline void __static_call_nop(void) { } + static inline long __static_call_return0(void) { return 0; @@ -298,39 +285,17 @@ static inline long __static_call_return0(void) __DEFINE_STATIC_CALL(name, _func, _func) #define DEFINE_STATIC_CALL_NULL(name, _func) \ - __DEFINE_STATIC_CALL(name, _func, NULL) + __DEFINE_STATIC_CALL(name, _func, __static_call_nop) #define DEFINE_STATIC_CALL_RET0(name, _func) \ __DEFINE_STATIC_CALL(name, _func, __static_call_return0) -static inline void __static_call_nop(void) { } - -/* - * This horrific hack takes care of two things: - * - * - it ensures the compiler will only load the function pointer ONCE, - * which avoids a reload race. - * - * - it ensures the argument evaluation is unconditional, similar - * to the HAVE_STATIC_CALL variant. - * - * Sadly current GCC/Clang (10 for both) do not optimize this properly - * and will emit an indirect call for the NULL case :-( - */ -#define __static_call_cond(name) \ -({ \ - void *func = READ_ONCE(STATIC_CALL_KEY(name).func); \ - if (!func) \ - func = &__static_call_nop; \ - (typeof(STATIC_CALL_TRAMP(name))*)func; \ -}) - -#define static_call_cond(name) (void)__static_call_cond(name) +#define static_call_cond(name) (void)static_call(name) static inline void __static_call_update(struct static_call_key *key, void *tramp, void *func) { - WRITE_ONCE(key->func, func); + WRITE_ONCE(key->func, func ? : (void *)__static_call_nop); } static inline int static_call_text_reserved(void *start, void *end)