summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '0050-x86-nospec-Fix-evaluate_nospec-code-generation-under.patch')
-rw-r--r--0050-x86-nospec-Fix-evaluate_nospec-code-generation-under.patch101
1 files changed, 101 insertions, 0 deletions
diff --git a/0050-x86-nospec-Fix-evaluate_nospec-code-generation-under.patch b/0050-x86-nospec-Fix-evaluate_nospec-code-generation-under.patch
new file mode 100644
index 0000000..14a8e14
--- /dev/null
+++ b/0050-x86-nospec-Fix-evaluate_nospec-code-generation-under.patch
@@ -0,0 +1,101 @@
+From 90320fd05991d7817cea85e1d45674b757abf03c Mon Sep 17 00:00:00 2001
+From: Andrew Cooper <andrew.cooper3@citrix.com>
+Date: Fri, 31 Mar 2023 08:39:32 +0200
+Subject: [PATCH 50/61] x86/nospec: Fix evaluate_nospec() code generation under
+ Clang
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+It turns out that evaluate_nospec() code generation is not safe under Clang.
+Given:
+
+ void eval_nospec_test(int x)
+ {
+ if ( evaluate_nospec(x) )
+ asm volatile ("nop #true" ::: "memory");
+ else
+ asm volatile ("nop #false" ::: "memory");
+ }
+
+Clang emits:
+
+ <eval_nospec_test>:
+ 0f ae e8 lfence
+ 85 ff test %edi,%edi
+ 74 02 je <eval_nospec_test+0x9>
+ 90 nop
+ c3 ret
+ 90 nop
+ c3 ret
+
+which is not safe because the lfence has been hoisted above the conditional
+jump. Clang concludes that both barrier_nospec_true()'s have identical side
+effects and can safely be merged.
+
+Clang can be persuaded that the side effects are different if there are
+different comments in the asm blocks. This is fragile, but no more fragile
+that other aspects of this construct.
+
+Introduce barrier_nospec_false() with a separate internal comment to prevent
+Clang merging it with barrier_nospec_true() despite the otherwise-identical
+content. The generated code now becomes:
+
+ <eval_nospec_test>:
+ 85 ff test %edi,%edi
+ 74 05 je <eval_nospec_test+0x9>
+ 0f ae e8 lfence
+ 90 nop
+ c3 ret
+ 0f ae e8 lfence
+ 90 nop
+ c3 ret
+
+which has the correct number of lfence's, and in the correct place.
+
+Link: https://github.com/llvm/llvm-project/issues/55084
+Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
+Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
+Reviewed-by: Jan Beulich <jbeulich@suse.com>
+master commit: bc3c133841435829ba5c0a48427e2a77633502ab
+master date: 2023-03-24 12:16:31 +0000
+---
+ xen/include/asm-x86/nospec.h | 15 +++++++++++++--
+ 1 file changed, 13 insertions(+), 2 deletions(-)
+
+diff --git a/xen/include/asm-x86/nospec.h b/xen/include/asm-x86/nospec.h
+index 5312ae4c6f..7150e76b87 100644
+--- a/xen/include/asm-x86/nospec.h
++++ b/xen/include/asm-x86/nospec.h
+@@ -10,15 +10,26 @@
+ static always_inline bool barrier_nospec_true(void)
+ {
+ #ifdef CONFIG_SPECULATIVE_HARDEN_BRANCH
+- alternative("lfence", "", X86_FEATURE_SC_NO_BRANCH_HARDEN);
++ alternative("lfence #nospec-true", "", X86_FEATURE_SC_NO_BRANCH_HARDEN);
+ #endif
+ return true;
+ }
+
++static always_inline bool barrier_nospec_false(void)
++{
++#ifdef CONFIG_SPECULATIVE_HARDEN_BRANCH
++ alternative("lfence #nospec-false", "", X86_FEATURE_SC_NO_BRANCH_HARDEN);
++#endif
++ return false;
++}
++
+ /* Allow to protect evaluation of conditionals with respect to speculation */
+ static always_inline bool evaluate_nospec(bool condition)
+ {
+- return condition ? barrier_nospec_true() : !barrier_nospec_true();
++ if ( condition )
++ return barrier_nospec_true();
++ else
++ return barrier_nospec_false();
+ }
+
+ /* Allow to block speculative execution in generic code */
+--
+2.40.0
+