Message ID | 20230615193722.127844423@infradead.org |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:994d:0:b0:3d9:f83d:47d9 with SMTP id k13csp881839vqr; Thu, 15 Jun 2023 12:58:37 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ7rPdcxmUxyvtcoco9732082HGdeb8Ls3ZaMDasJxBtvEdi4N1sNjcm4j48HvTe7f3A8zXQ X-Received: by 2002:a17:907:7248:b0:974:61dc:107c with SMTP id ds8-20020a170907724800b0097461dc107cmr87010ejc.44.1686859117407; Thu, 15 Jun 2023 12:58:37 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1686859117; cv=none; d=google.com; s=arc-20160816; b=t12HVR/JUIxtWFss+pMGFM2WgFAYCpm6LDDn+STkODHiqIPD9YtZDekxbRHbvU1sG6 ZvTWGHU51x078FW0WrwOUbyTC/0WkrNoMLGH3Dgervk2fijNFquoCiMtRkr5WjWoH3PX 16QqrILJwMGTWhQqZeez802iq/OxSiCXIkmnk8XOBw5ddBcZhBS0n+aS76TQIjYbhrMv xzXDoSnwflNZHzuED4/f6A5h8DcuVyZnME+FYTzvLjc59u7Kjrp2YJwa72sKHZE27SDe HlHc0gMCpC6i83Qu5m6jQOyLqUaHyfZjpMVJwyZVX6CG7xuJQ/T9WFzApvfmYiIhu1Ln axoQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:mime-version:references:subject:cc:to:from:date :user-agent:message-id:dkim-signature; bh=BhX7pkXejcd+7jOdak4TeKh4gofIP/p6FvONT7yMD5Q=; b=qhFo0pmXLjKnbNmbdRZBk55KFNEXQMHeFlolFenUgrJyjBzHsQ2rww0eknmDEdQxQi DrZyji5a6bGgwOp/GUyja72xq+V1RRM1Agp5rqmANVohPSllTMiKj5WpkprEd6183xRW +PyC11c+5mKTzc0868zdUkxnXCRLIkyJ+ZtOw7i8rtP8xTpUrtwbEIon9RqZRlWNIpvY MiTmroo0tcMS2VEV9kmIRZxo7hpWc39baOfjoDjgszjW1ckR+ykFRp4KfaeVWsz0K94X LzfEWEL+A5It2KBWtYVjPmiUJ22wbrLi4PWY8xsgeyl8OxBpaUjG96XORJXUYPcfs6nd 8fkg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@infradead.org header.s=desiato.20200630 header.b="Luncf/CU"; 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: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id i21-20020a170906251500b0094f93169acdsi9519509ejb.181.2023.06.15.12.58.12; Thu, 15 Jun 2023 12:58:37 -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=@infradead.org header.s=desiato.20200630 header.b="Luncf/CU"; 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 S230355AbjFOTkr (ORCPT <rfc822;maxin.john@gmail.com> + 99 others); Thu, 15 Jun 2023 15:40:47 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56828 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229694AbjFOTkn (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Thu, 15 Jun 2023 15:40:43 -0400 Received: from desiato.infradead.org (desiato.infradead.org [IPv6:2001:8b0:10b:1:d65d:64ff:fe57:4e05]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6C66B2954 for <linux-kernel@vger.kernel.org>; Thu, 15 Jun 2023 12:40:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Content-Type:MIME-Version:References: Subject:Cc:To:From:Date:Message-ID:Sender:Reply-To:Content-Transfer-Encoding: Content-ID:Content-Description:In-Reply-To; bh=BhX7pkXejcd+7jOdak4TeKh4gofIP/p6FvONT7yMD5Q=; b=Luncf/CUiCXEJyaixzGv2qhSHY FpBEa0sP9GHb+kSvFbCdnhUAl6ex0IbnWIihLc+vrU5Pw52VWmVi1dYIF5rgUcq/yBbQ5fnBT7C0I 3wroRla56ysNYuNVj7s6Ut8oxsy9oQhuc+xhs6KBlF8eUg6x7JKUC0cX1ZsK5DDlHv12G98EZjay1 cpv9C9FULKKGfXA4bevZK24nVZmoUtTU5Yo4WNZjwGTMnKbQQWdG5EqCJVOkajdE1H0p+FBVsmvSu YWvrH7dT6MjxhkaDEfbxUFnp+PZROLzB6Mfn5k5SkMpHhbmSh+wE8JWtqmXcPcMz3ZWUAJUMwTP2D mPoNrRow==; Received: from j130084.upc-j.chello.nl ([24.132.130.84] helo=noisy.programming.kicks-ass.net) by desiato.infradead.org with esmtpsa (Exim 4.96 #2 (Red Hat Linux)) id 1q9spY-00BtUT-1s; Thu, 15 Jun 2023 19:40:29 +0000 Received: from hirez.programming.kicks-ass.net (hirez.programming.kicks-ass.net [192.168.1.225]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by noisy.programming.kicks-ass.net (Postfix) with ESMTPS id 1018830031B; Thu, 15 Jun 2023 21:40:27 +0200 (CEST) Received: by hirez.programming.kicks-ass.net (Postfix, from userid 0) id E847C245F1E4B; Thu, 15 Jun 2023 21:40:26 +0200 (CEST) Message-ID: <20230615193722.127844423@infradead.org> User-Agent: quilt/0.66 Date: Thu, 15 Jun 2023 21:35:47 +0200 From: Peter Zijlstra <peterz@infradead.org> To: x86@kernel.org, alyssa.milburn@linux.intel.com Cc: linux-kernel@vger.kernel.org, peterz@infradead.org, samitolvanen@google.com, keescook@chromium.org, jpoimboe@kernel.org, joao@overdrivepizza.com, tim.c.chen@linux.intel.com Subject: [PATCH 1/2] x86/cfi: Fix ret_from_fork indirect calls References: <20230615193546.949657149@infradead.org> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 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_NONE,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: <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?1768799985959414203?= X-GMAIL-MSGID: =?utf-8?q?1768799985959414203?= |
Series |
x86/cfi: Fix FineIBT
|
|
Commit Message
Peter Zijlstra
June 15, 2023, 7:35 p.m. UTC
The ret_from_fork stub does an indirect call to the kthread function,
but only knows about Retpolines. Instead of making the asm more
complicated, punt to C and let the compiler figure it out.
Specifically, this makes it a proper kCFI indirect call when needed (in
fact, it is nearly impossible to code a kCFI indirect call in asm).
This was the only callsite that was still calling func()+0 on regular
indirect functions.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
---
arch/x86/entry/entry_64.S | 6 ++++--
arch/x86/include/asm/switch_to.h | 2 ++
arch/x86/kernel/process_64.c | 5 +++++
3 files changed, 11 insertions(+), 2 deletions(-)
Comments
On Thu, Jun 15, 2023 at 09:35:47PM +0200, Peter Zijlstra wrote: > The ret_from_fork stub does an indirect call to the kthread function, > but only knows about Retpolines. Instead of making the asm more > complicated, punt to C and let the compiler figure it out. > > Specifically, this makes it a proper kCFI indirect call when needed (in > fact, it is nearly impossible to code a kCFI indirect call in asm). > > This was the only callsite that was still calling func()+0 on regular > indirect functions. > > Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> I worry this creates a calling gadget, but I don't think it really counts since it's just converting between two prototypes. Regardless: Acked-by: Kees Cook <keescook@chromium.org>
On Tue, Jun 20, 2023 at 02:56:22PM -0700, Kees Cook wrote: > On Thu, Jun 15, 2023 at 09:35:47PM +0200, Peter Zijlstra wrote: > > The ret_from_fork stub does an indirect call to the kthread function, > > but only knows about Retpolines. Instead of making the asm more > > complicated, punt to C and let the compiler figure it out. > > > > Specifically, this makes it a proper kCFI indirect call when needed (in > > fact, it is nearly impossible to code a kCFI indirect call in asm). > > > > This was the only callsite that was still calling func()+0 on regular > > indirect functions. > > > > Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> > > I worry this creates a calling gadget, but I don't think it really > counts since it's just converting between two prototypes. Regardless: Ah, since this will never be indirectly called, I should be able to annotate this so it never can be. Let me see what I can get the compiler to do.
On Wed, Jun 21, 2023 at 10:52:17AM +0200, Peter Zijlstra wrote: > On Tue, Jun 20, 2023 at 02:56:22PM -0700, Kees Cook wrote: > > On Thu, Jun 15, 2023 at 09:35:47PM +0200, Peter Zijlstra wrote: > > > The ret_from_fork stub does an indirect call to the kthread function, > > > but only knows about Retpolines. Instead of making the asm more > > > complicated, punt to C and let the compiler figure it out. > > > > > > Specifically, this makes it a proper kCFI indirect call when needed (in > > > fact, it is nearly impossible to code a kCFI indirect call in asm). > > > > > > This was the only callsite that was still calling func()+0 on regular > > > indirect functions. > > > > > > Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> > > > > I worry this creates a calling gadget, but I don't think it really > > counts since it's just converting between two prototypes. Regardless: > > Ah, since this will never be indirectly called, I should be able to > annotate this so it never can be. Let me see what I can get the compiler > to do. I can't seem to manage to have it clobber it's __cfi hash value. Ideally we'd have an attribute to force the thing to 0 or something. Best I can do is add __noendbr, which will inhibit the ENDBR. Alternatively, I *can* write the thing in asm by hard-coding the hash value, but that's not nice: mov %rbx,%r11 mov %r12,%rdi #ifdef CONFIG_CFI_CLANG mov $0x76049ec3,%r10d add -0xf(%r11),%r10d je 1f ud2 1: #endif CALL_NOSPEC r11 should work.. but if ever that hash function changes we're in trouble. --- Subject: x86/cfi: Fix ret_from_fork() indirect calls From: Peter Zijlstra <peterz@infradead.org> Date: Thu, 15 Jun 2023 21:35:47 +0200 The ret_from_fork() stub does an indirect call to the kthread function, but only knows about Retpolines. Instead of making the asm more complicated, punt to C and let the compiler figure it out. Specifically, this makes it a proper kCFI indirect call when needed (in fact, it is nearly impossible to code a kCFI indirect call in asm). This was the only callsite that was still calling func()+0 on regular indirect functions. Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Sami Tolvanen <samitolvanen@google.com> Link: https://lore.kernel.org/r/20230615193722.127844423@infradead.org --- arch/x86/entry/entry_64.S | 6 ++++-- arch/x86/include/asm/switch_to.h | 2 ++ arch/x86/kernel/process_64.c | 5 +++++ 3 files changed, 11 insertions(+), 2 deletions(-) --- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S @@ -304,8 +304,10 @@ SYM_CODE_START_NOALIGN(ret_from_fork) 1: /* kernel thread */ UNWIND_HINT_END_OF_STACK - movq %r12, %rdi - CALL_NOSPEC rbx + movq %rbx, %rdi + movq %r12, %rsi + call kthread_from_fork + /* * A kernel thread is allowed to return here after successfully * calling kernel_execve(). Exit to userspace to complete the execve() --- a/arch/x86/include/asm/switch_to.h +++ b/arch/x86/include/asm/switch_to.h @@ -74,6 +74,8 @@ static inline void update_task_stack(str #endif } +extern __noendbr void kthread_from_fork(int (*fn)(void *), void *arg); + static inline void kthread_frame_init(struct inactive_task_frame *frame, int (*fun)(void *), void *arg) { --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -544,6 +544,11 @@ void compat_start_thread(struct pt_regs } #endif +__visible __noendbr void kthread_from_fork(int (*fn)(void *), void *arg) +{ + fn(arg); +} + /* * switch_to(x,y) should switch tasks from x to y. *
On Wed, Jun 21, 2023 at 11:27:59AM +0200, Peter Zijlstra wrote: > On Wed, Jun 21, 2023 at 10:52:17AM +0200, Peter Zijlstra wrote: > > On Tue, Jun 20, 2023 at 02:56:22PM -0700, Kees Cook wrote: > > > On Thu, Jun 15, 2023 at 09:35:47PM +0200, Peter Zijlstra wrote: > > > > The ret_from_fork stub does an indirect call to the kthread function, > > > > but only knows about Retpolines. Instead of making the asm more > > > > complicated, punt to C and let the compiler figure it out. > > > > > > > > Specifically, this makes it a proper kCFI indirect call when needed (in > > > > fact, it is nearly impossible to code a kCFI indirect call in asm). > > > > > > > > This was the only callsite that was still calling func()+0 on regular > > > > indirect functions. > > > > > > > > Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> > > > > > > I worry this creates a calling gadget, but I don't think it really > > > counts since it's just converting between two prototypes. Regardless: > > > > Ah, since this will never be indirectly called, I should be able to > > annotate this so it never can be. Let me see what I can get the compiler > > to do. Ah yeah, it should be direct-called only. I keep forgetting about the endbr removal pass. > I can't seem to manage to have it clobber it's __cfi hash value. Ideally > we'd have an attribute to force the thing to 0 or something. Doesn't objtool have logic to figure out this is only ever direct-called?
On Wed, Jun 21, 2023 at 11:08:46AM -0700, Kees Cook wrote: > Ah yeah, it should be direct-called only. I keep forgetting about the > endbr removal pass. > > > I can't seem to manage to have it clobber it's __cfi hash value. Ideally > > we'd have an attribute to force the thing to 0 or something. > > Doesn't objtool have logic to figure out this is only ever > direct-called? It does; let me also use that same thing to clobber the kCFI hashes for these functions.
On Wed, Jun 21, 2023 at 08:16:59PM +0200, Peter Zijlstra wrote: > On Wed, Jun 21, 2023 at 11:08:46AM -0700, Kees Cook wrote: > > > Ah yeah, it should be direct-called only. I keep forgetting about the > > endbr removal pass. > > > > > I can't seem to manage to have it clobber it's __cfi hash value. Ideally > > > we'd have an attribute to force the thing to 0 or something. > > > > Doesn't objtool have logic to figure out this is only ever > > direct-called? > > It does; let me also use that same thing to clobber the kCFI hashes for > these functions. Completely untested... gotta go put the kids to bed. I'll try later. --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -778,6 +778,8 @@ void __init_or_module noinline apply_ret #ifdef CONFIG_X86_KERNEL_IBT +static void poison_hash(void *addr); + static void __init_or_module poison_endbr(void *addr, bool warn) { u32 endbr, poison = gen_endbr_poison(); @@ -802,6 +804,9 @@ static void __init_or_module poison_endb /* * Generated by: objtool --ibt + * + * Seal the functions for indirect calls by clobbering the ENDBR instructions + * and the kCFI hash value. */ void __init_or_module noinline apply_ibt_endbr(s32 *start, s32 *end) { @@ -812,7 +817,7 @@ void __init_or_module noinline apply_ibt poison_endbr(addr, true); if (IS_ENABLED(CONFIG_FINEIBT)) - poison_endbr(addr - 16, false); + poison_hash(addr - 16); } } @@ -1193,6 +1198,38 @@ static void __apply_fineibt(s32 *start_r pr_err("Something went horribly wrong trying to rewrite the CFI implementation.\n"); } +static inline void __poison_hash(void *addr) +{ + *(u32 *)hash = 0; +} + +static void poison_hash(void *addr) +{ + switch (cfi_mode) { + case CFI_FINEIBT: + /* + * __cfi_\func: + * osp nopl (%rax) + * subl $0, %r10d + * jz 1f + * ud2 + * 1: nop + */ + poison_endbr(addr, false); + __poison_hash(addr + 7); + break; + + case CFI_KCFI: + /* + * __cfi_\func: + * movl $0, %eax + * .skip 11, 0x90 + */ + __poison_hash(addr + 1); + break; + } +} + #else static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, @@ -1200,6 +1237,8 @@ static void __apply_fineibt(s32 *start_r { } +static void poison_hash(void *addr) { } + #endif void apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
On Wed, Jun 21, 2023 at 08:33:56PM +0200, Peter Zijlstra wrote: > On Wed, Jun 21, 2023 at 08:16:59PM +0200, Peter Zijlstra wrote: > > On Wed, Jun 21, 2023 at 11:08:46AM -0700, Kees Cook wrote: > > > > > Ah yeah, it should be direct-called only. I keep forgetting about the > > > endbr removal pass. > > > > > > > I can't seem to manage to have it clobber it's __cfi hash value. Ideally > > > > we'd have an attribute to force the thing to 0 or something. > > > > > > Doesn't objtool have logic to figure out this is only ever > > > direct-called? > > > > It does; let me also use that same thing to clobber the kCFI hashes for > > these functions. > > Completely untested... gotta go put the kids to bed. I'll try later. With a few minor edits it seems to actually boot too. I'll go write up a Changelog tomorrow. Now I've got to discover how Drizzt's adventure continues ;-)
On Thu, Jun 15, 2023 at 3:56 PM Peter Zijlstra <peterz@infradead.org> wrote: > > The ret_from_fork stub does an indirect call to the kthread function, > but only knows about Retpolines. Instead of making the asm more > complicated, punt to C and let the compiler figure it out. > > Specifically, this makes it a proper kCFI indirect call when needed (in > fact, it is nearly impossible to code a kCFI indirect call in asm). > > This was the only callsite that was still calling func()+0 on regular > indirect functions. > > Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> > --- > arch/x86/entry/entry_64.S | 6 ++++-- > arch/x86/include/asm/switch_to.h | 2 ++ > arch/x86/kernel/process_64.c | 5 +++++ > 3 files changed, 11 insertions(+), 2 deletions(-) > > --- a/arch/x86/entry/entry_64.S > +++ b/arch/x86/entry/entry_64.S > @@ -304,8 +304,10 @@ SYM_CODE_START_NOALIGN(ret_from_fork) > 1: > /* kernel thread */ > UNWIND_HINT_END_OF_STACK > - movq %r12, %rdi > - CALL_NOSPEC rbx > + movq %rbx, %rdi > + movq %r12, %rsi > + call kthread_from_fork > + > /* > * A kernel thread is allowed to return here after successfully > * calling kernel_execve(). Exit to userspace to complete the execve() > --- a/arch/x86/include/asm/switch_to.h > +++ b/arch/x86/include/asm/switch_to.h > @@ -74,6 +74,8 @@ static inline void update_task_stack(str > #endif > } > > +extern void kthread_from_fork(int (*fn)(void *), void *); > + > static inline void kthread_frame_init(struct inactive_task_frame *frame, > int (*fun)(void *), void *arg) > { > --- a/arch/x86/kernel/process_64.c > +++ b/arch/x86/kernel/process_64.c > @@ -544,6 +544,11 @@ void compat_start_thread(struct pt_regs > } > #endif > > +__visible noinstr void kthread_from_fork(int (*fn)(void *), void *arg) > +{ > + fn(arg); > +} > + > /* > * switch_to(x,y) should switch tasks from x to y. > * I think this makes a case for converting all of ret_from_fork() to C (other than some minimal asm glue). Patches coming soon. Brian Gerst
--- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S @@ -304,8 +304,10 @@ SYM_CODE_START_NOALIGN(ret_from_fork) 1: /* kernel thread */ UNWIND_HINT_END_OF_STACK - movq %r12, %rdi - CALL_NOSPEC rbx + movq %rbx, %rdi + movq %r12, %rsi + call kthread_from_fork + /* * A kernel thread is allowed to return here after successfully * calling kernel_execve(). Exit to userspace to complete the execve() --- a/arch/x86/include/asm/switch_to.h +++ b/arch/x86/include/asm/switch_to.h @@ -74,6 +74,8 @@ static inline void update_task_stack(str #endif } +extern void kthread_from_fork(int (*fn)(void *), void *); + static inline void kthread_frame_init(struct inactive_task_frame *frame, int (*fun)(void *), void *arg) { --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -544,6 +544,11 @@ void compat_start_thread(struct pt_regs } #endif +__visible noinstr void kthread_from_fork(int (*fn)(void *), void *arg) +{ + fn(arg); +} + /* * switch_to(x,y) should switch tasks from x to y. *