From: Marco Elver <elver@google.com>
To: peterz@infradead.org
Cc: Borislav Petkov <bp@alien8.de>,
Dave Hansen <dave.hansen@linux.intel.com>,
fenghua.yu@intel.com, "H. Peter Anvin" <hpa@zytor.com>,
LKML <linux-kernel@vger.kernel.org>,
Ingo Molnar <mingo@redhat.com>,
syzkaller-bugs <syzkaller-bugs@googlegroups.com>,
Thomas Gleixner <tglx@linutronix.de>,
"Luck, Tony" <tony.luck@intel.com>,
the arch/x86 maintainers <x86@kernel.org>,
yu-cheng.yu@intel.com, jgross@suse.com, sdeep@vmware.com,
virtualization@lists.linux-foundation.org,
kasan-dev <kasan-dev@googlegroups.com>,
syzbot <syzbot+8db9e1ecde74e590a657@syzkaller.appspotmail.com>
Subject: Re: [PATCH] x86/paravirt: Add missing noinstr to arch_local*() helpers
Date: Thu, 6 Aug 2020 15:17:02 +0200 [thread overview]
Message-ID: <20200806131702.GA3029162@elver.google.com> (raw)
In-Reply-To: <20200806113236.GZ2674@hirez.programming.kicks-ass.net>
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 <linux/bug.h>
#include <linux/delay.h>
#include <linux/export.h>
+#include <linux/ftrace.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/list.h>
@@ -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);
/*
next prev parent reply other threads:[~2020-08-06 17:25 UTC|newest]
Thread overview: 55+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-08-05 7:19 upstream test error: WARNING in __local_bh_enable_ip syzbot
2020-08-05 13:26 ` [PATCH] x86/paravirt: Add missing noinstr to arch_local*() helpers Marco Elver
2020-08-05 13:42 ` peterz
2020-08-05 13:42 ` peterz
2020-08-05 13:59 ` Marco Elver
2020-08-05 14:12 ` peterz
2020-08-05 14:12 ` peterz
2020-08-05 14:17 ` Jürgen Groß
2020-08-05 14:17 ` Jürgen Groß
2020-08-05 14:17 ` peterz
2020-08-05 14:17 ` peterz
2020-08-05 14:36 ` Marco Elver
2020-08-05 17:31 ` Marco Elver
2020-08-06 7:47 ` Marco Elver
2020-08-06 11:32 ` peterz
2020-08-06 11:32 ` peterz
2020-08-06 13:17 ` Marco Elver [this message]
2020-08-06 16:06 ` Marco Elver
2020-08-07 9:01 ` Marco Elver
2020-08-07 9:24 ` Jürgen Groß
2020-08-07 9:24 ` Jürgen Groß
2020-08-07 9:50 ` Marco Elver
2020-08-07 10:35 ` Jürgen Groß
2020-08-07 10:35 ` Jürgen Groß
2020-08-07 11:38 ` Marco Elver
2020-08-07 12:04 ` Jürgen Groß
2020-08-07 12:04 ` Jürgen Groß
2020-08-07 12:08 ` Marco Elver
2020-08-07 15:19 ` Marco Elver
2020-08-11 7:00 ` Marco Elver
2020-08-11 7:04 ` Jürgen Groß
2020-08-11 7:04 ` Jürgen Groß
2020-08-11 7:41 ` Peter Zijlstra
2020-08-11 7:41 ` Peter Zijlstra
2020-08-11 7:57 ` Jürgen Groß
2020-08-11 7:57 ` Jürgen Groß
2020-08-11 8:12 ` Peter Zijlstra
2020-08-11 8:12 ` Peter Zijlstra
2020-08-11 8:18 ` Jürgen Groß
2020-08-11 8:18 ` Jürgen Groß
2020-08-11 8:38 ` Jürgen Groß
2020-08-11 8:38 ` Jürgen Groß
2020-08-11 9:20 ` peterz
2020-08-11 9:20 ` peterz
2020-08-11 9:46 ` peterz
2020-08-11 9:46 ` peterz
2020-08-11 20:17 ` peterz
2020-08-11 20:17 ` peterz
2020-08-12 8:06 ` Marco Elver
2020-08-12 8:18 ` peterz
2020-08-12 8:18 ` peterz
2020-08-12 8:57 ` peterz
2020-08-12 8:57 ` peterz
2020-08-06 21:02 ` kernel test robot
2020-08-06 21:02 ` kernel test robot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200806131702.GA3029162@elver.google.com \
--to=elver@google.com \
--cc=bp@alien8.de \
--cc=dave.hansen@linux.intel.com \
--cc=fenghua.yu@intel.com \
--cc=hpa@zytor.com \
--cc=jgross@suse.com \
--cc=kasan-dev@googlegroups.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=peterz@infradead.org \
--cc=sdeep@vmware.com \
--cc=syzbot+8db9e1ecde74e590a657@syzkaller.appspotmail.com \
--cc=syzkaller-bugs@googlegroups.com \
--cc=tglx@linutronix.de \
--cc=tony.luck@intel.com \
--cc=virtualization@lists.linux-foundation.org \
--cc=x86@kernel.org \
--cc=yu-cheng.yu@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.