Received: by 2002:a05:6a10:a0d1:0:0:0:0 with SMTP id j17csp1567819pxa; Thu, 6 Aug 2020 10:26:59 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwa0gLxFCAtATzZSnQbuiBWCS8HviMBHWs8CZhImfJRBZaqH1o2YfloXPhJdnhWT0Ls9BXO X-Received: by 2002:a17:907:7255:: with SMTP id ds21mr5718427ejc.44.1596734819719; Thu, 06 Aug 2020 10:26:59 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1596734819; cv=none; d=google.com; s=arc-20160816; b=qtM+L/hmFotL3f8Oh2LxPnnJUFq+6efdRs9C0f85RMZVNTA7OzGzFCyllGxsNhFyyU 1AKSwSRdZdx+h29rMQvddobDKX7+16+7QxSFzcENOMFz9gy82Rre9rVICnjqm7/WobRN gIYMAV0NA6yOojPUf7B6KKiNkzd8ClzKeMhQkFf5EwHqF6+GkA6KhI5Xse0hpsbwDOdg 1V3VQ5zxwn5ytTPgafbBRW0cb+lbg8Sk+N4vM0yFyEMTW8afns03NtYc+4szQLj+aXFc BD8TUQAXiW9RrxkfeqbBvolvBvhUUKHksNfNXOaahE5XpzOu26lq9klIxgVeennaBF5U e2hg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:user-agent:in-reply-to :content-disposition:mime-version:references:message-id:subject:cc :to:from:date:dkim-signature; bh=C+eYpjO9tZjVIJJgZzQi1cMIXwcXEBDu4nry89JkOG4=; b=tAvAkvN7qCRWNqwlDiFZ2tXKBa2dQv0513Po6BCnxv+sB2LOghral68fa5twinLSub pDyzycoP7WKfbeHV7EpM2XZxD+ZDaj72m96Ux2NBRSufs9kVvGD4yU2fovLGMjXOiEDR 2FOn1eVe15zgyH8x7CZQ5XDzCd+Z7pMQXa3pE+P4V8abOqSf/3mnRhuTLLIvy2xwZ7VG LVfisRDz2gXVABUZ8E/w+gONRRdJfjif30Iw7usYnRQPHJesVaoiI00Mi75RrUELrILu SdvW13HgcPnBIeFGnp4Fb0JoUnDkdFkAY+xyJm6XpV1fXAUQYBYvfiHNqDPiDSgdT/wk 76ng== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=kBP+hi0Q; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id y16si3910493edq.189.2020.08.06.10.26.37; Thu, 06 Aug 2020 10:26:59 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=kBP+hi0Q; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 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 S1730273AbgHFRZo (ORCPT + 99 others); Thu, 6 Aug 2020 13:25:44 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44992 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729447AbgHFRC7 (ORCPT ); Thu, 6 Aug 2020 13:02:59 -0400 Received: from mail-wr1-x442.google.com (mail-wr1-x442.google.com [IPv6:2a00:1450:4864:20::442]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C7C6CC034614 for ; Thu, 6 Aug 2020 06:17:11 -0700 (PDT) Received: by mail-wr1-x442.google.com with SMTP id y3so43975387wrl.4 for ; Thu, 06 Aug 2020 06:17:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to:user-agent; bh=C+eYpjO9tZjVIJJgZzQi1cMIXwcXEBDu4nry89JkOG4=; b=kBP+hi0Qq1lASdndGc9TwGlcTEsQtMAruql90jWjNa+KHWlJxz9VyPAtY3r4xk2shA HAaNxAH8ofgwSMfVludF/QCMr+gtDr+RHY9GNu8atIJ8pFmIGK5RIQB97t9koh2j7bea B2SwMjl08xCkBRFrvj1jlrGiJp/xH7Fnw3e0UociQxDltXfqZxAdMBMcJpZf+NlwUeHl cHSW94hBu+08pE46xwr/rTNJQ207g7CI262swiSxflzYBqcrrApHipL1PnxFAVThjhZr u/Y9C49mfU7x07rVohPN2X0dDpnVxgGzND6EvSu1+X/2uTUzk4sPjmIQsGJiNeGesE+Q DWNQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to:user-agent; bh=C+eYpjO9tZjVIJJgZzQi1cMIXwcXEBDu4nry89JkOG4=; b=O9jqoIpGIAz3aIJfqV1cK9Gek7td9FQa3W5rPUo8Xm3EFybLQamKFq3e6b4+8+7p7s rmyTAhansd3mywX9+mIbTHKNttnU11fy9AldlDi/g/LnBXiOoZ3xX7XvpiHOxfS1+ZQt ZRoi+LrKOsZ+NyvgE/FI1D2dcNfUF42RM/aUpgjxHvU5UqSbUDMyVmdSHaIOnetrACMm F7BwkQRgaIJt0IFyat1x4JAxrL0Fir/lkOIPxafwB4i4Ji3mRLTH+PP0sIU6XQJ///H2 0GLc+A2iy3RzxwsNCs/FoVvU2FVFbPgbfnCV61/Ldp6pv/py+AcrfGDa7BWaoQYDv22P OFlQ== X-Gm-Message-State: AOAM530LFwXon5e8ZlfPqwMgtgn8x9XVcZcOrX4Jcuw5iwk0gBUbxJkI ilxGd4PsGGOaBnnly89Mby5ODA== X-Received: by 2002:a5d:5682:: with SMTP id f2mr7283059wrv.248.1596719829770; Thu, 06 Aug 2020 06:17:09 -0700 (PDT) Received: from elver.google.com ([100.105.32.75]) by smtp.gmail.com with ESMTPSA id a10sm6529088wrx.15.2020.08.06.06.17.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 06 Aug 2020 06:17:07 -0700 (PDT) Date: Thu, 6 Aug 2020 15:17:02 +0200 From: Marco Elver To: peterz@infradead.org Cc: Borislav Petkov , Dave Hansen , fenghua.yu@intel.com, "H. Peter Anvin" , LKML , Ingo Molnar , syzkaller-bugs , Thomas Gleixner , "Luck, Tony" , the arch/x86 maintainers , yu-cheng.yu@intel.com, jgross@suse.com, sdeep@vmware.com, virtualization@lists.linux-foundation.org, kasan-dev , syzbot Subject: Re: [PATCH] x86/paravirt: Add missing noinstr to arch_local*() helpers Message-ID: <20200806131702.GA3029162@elver.google.com> References: <0000000000007d3b2d05ac1c303e@google.com> <20200805132629.GA87338@elver.google.com> <20200805134232.GR2674@hirez.programming.kicks-ass.net> <20200805135940.GA156343@elver.google.com> <20200805141237.GS2674@hirez.programming.kicks-ass.net> <20200805141709.GD35926@hirez.programming.kicks-ass.net> <20200806074723.GA2364872@elver.google.com> <20200806113236.GZ2674@hirez.programming.kicks-ass.net> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20200806113236.GZ2674@hirez.programming.kicks-ass.net> User-Agent: Mutt/1.14.4 (2020-06-18) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Thu, Aug 06, 2020 at 01:32PM +0200, peterz@infradead.org wrote: > On Thu, Aug 06, 2020 at 09:47:23AM +0200, Marco Elver wrote: > > Testing my hypothesis that raw then nested non-raw > > local_irq_save/restore() breaks IRQ state tracking -- see the reproducer > > below. This is at least 1 case I can think of that we're bound to hit. ... > > /me goes ponder things... > > How's something like this then? > > --- > include/linux/sched.h | 3 --- > kernel/kcsan/core.c | 62 ++++++++++++++++++++++++++++++++++++--------------- > 2 files changed, 44 insertions(+), 21 deletions(-) Thank you! That approach seems to pass syzbot (also with CONFIG_PARAVIRT) and kcsan-test tests. I had to modify it some, so that report.c's use of the restore logic works and not mess up the IRQ trace printed on KCSAN reports (with CONFIG_KCSAN_VERBOSE). I still need to fully convince myself all is well now and we don't end up with more fixes. :-) If it passes further testing, I'll send it as a real patch (I want to add you as Co-developed-by, but would need your Signed-off-by for the code you pasted, I think.) Thanks, -- Marco ------ >8 ------ diff --git a/kernel/kcsan/core.c b/kernel/kcsan/core.c index 9147ff6a12e5..b1d5dca10aa5 100644 --- a/kernel/kcsan/core.c +++ b/kernel/kcsan/core.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -291,13 +292,28 @@ static inline unsigned int get_delay(void) 0); } -void kcsan_save_irqtrace(struct task_struct *task) -{ +/* + * KCSAN instrumentation is everywhere, which means we must treat the hooks + * NMI-like for interrupt tracing. In order to present a 'normal' as possible + * context to the code called by KCSAN when reporting errors we need to update + * the IRQ-tracing state. + * + * Save and restore the IRQ state trace touched by KCSAN, since KCSAN's + * runtime is entered for every memory access, and potentially useful + * information is lost if dirtied by KCSAN. + */ + +struct kcsan_irq_state { + unsigned long flags; #ifdef CONFIG_TRACE_IRQFLAGS - task->kcsan_save_irqtrace = task->irqtrace; + int hardirqs; #endif -} +}; +/* + * This is also called by the reporting task for the other task, to generate the + * right report with CONFIG_KCSAN_VERBOSE. No harm in restoring more than once. + */ void kcsan_restore_irqtrace(struct task_struct *task) { #ifdef CONFIG_TRACE_IRQFLAGS @@ -305,6 +321,34 @@ void kcsan_restore_irqtrace(struct task_struct *task) #endif } +static void kcsan_irq_save(struct kcsan_irq_state *irq_state) { +#ifdef CONFIG_TRACE_IRQFLAGS + current->kcsan_save_irqtrace = current->irqtrace; + irq_state->hardirqs = lockdep_hardirqs_enabled(); +#endif + if (!kcsan_interrupt_watcher) { + raw_local_irq_save(irq_state->flags); + kcsan_disable_current(); /* Lockdep might WARN. */ + lockdep_hardirqs_off(CALLER_ADDR0); + kcsan_enable_current(); + } +} + +static void kcsan_irq_restore(struct kcsan_irq_state *irq_state) { + if (!kcsan_interrupt_watcher) { +#ifdef CONFIG_TRACE_IRQFLAGS + if (irq_state->hardirqs) { + kcsan_disable_current(); /* Lockdep might WARN. */ + lockdep_hardirqs_on_prepare(CALLER_ADDR0); + lockdep_hardirqs_on(CALLER_ADDR0); + kcsan_enable_current(); + } +#endif + raw_local_irq_restore(irq_state->flags); + } + kcsan_restore_irqtrace(current); +} + /* * Pull everything together: check_access() below contains the performance * critical operations; the fast-path (including check_access) functions should @@ -350,11 +394,13 @@ static noinline void kcsan_found_watchpoint(const volatile void *ptr, flags = user_access_save(); if (consumed) { - kcsan_save_irqtrace(current); + struct kcsan_irq_state irqstate; + + kcsan_irq_save(&irqstate); kcsan_report(ptr, size, type, KCSAN_VALUE_CHANGE_MAYBE, KCSAN_REPORT_CONSUMED_WATCHPOINT, watchpoint - watchpoints); - kcsan_restore_irqtrace(current); + kcsan_irq_restore(&irqstate); } else { /* * The other thread may not print any diagnostics, as it has @@ -387,7 +433,7 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type) unsigned long access_mask; enum kcsan_value_change value_change = KCSAN_VALUE_CHANGE_MAYBE; unsigned long ua_flags = user_access_save(); - unsigned long irq_flags = 0; + struct kcsan_irq_state irqstate; /* * Always reset kcsan_skip counter in slow-path to avoid underflow; see @@ -412,14 +458,7 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type) goto out; } - /* - * Save and restore the IRQ state trace touched by KCSAN, since KCSAN's - * runtime is entered for every memory access, and potentially useful - * information is lost if dirtied by KCSAN. - */ - kcsan_save_irqtrace(current); - if (!kcsan_interrupt_watcher) - local_irq_save(irq_flags); + kcsan_irq_save(&irqstate); watchpoint = insert_watchpoint((unsigned long)ptr, size, is_write); if (watchpoint == NULL) { @@ -559,9 +598,7 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type) remove_watchpoint(watchpoint); kcsan_counter_dec(KCSAN_COUNTER_USED_WATCHPOINTS); out_unlock: - if (!kcsan_interrupt_watcher) - local_irq_restore(irq_flags); - kcsan_restore_irqtrace(current); + kcsan_irq_restore(&irqstate); out: user_access_restore(ua_flags); } diff --git a/kernel/kcsan/kcsan.h b/kernel/kcsan/kcsan.h index 29480010dc30..6eb35a9514d8 100644 --- a/kernel/kcsan/kcsan.h +++ b/kernel/kcsan/kcsan.h @@ -24,9 +24,8 @@ extern unsigned int kcsan_udelay_interrupt; extern bool kcsan_enabled; /* - * Save/restore IRQ flags state trace dirtied by KCSAN. + * Restore IRQ flags state trace dirtied by KCSAN. */ -void kcsan_save_irqtrace(struct task_struct *task); void kcsan_restore_irqtrace(struct task_struct *task); /*