Add the following tests:

1. A test with an (unimportant) ldimm64 (16 byte insn) and a
   Spectre-v4--induced nospec that clarifies and serves as a basic
   Spectre v4 test.

2. Make sure a Spectre v4 nospec_result does not prevent a Spectre v1
   nospec from being added before the dangerous instruction (tests that
   [1] is fixed).

3. Combine the two, which is the combination that triggers the warning
   in [2]. This is because the unanalyzed stack write has nospec_result
   set, but the ldimm64 (which was just analyzed) had incremented
   insn_idx by 2. That violates the assertion that nospec_result is only
   used after insns that increment insn_idx by 1 (i.e., stack writes).

[1] 
https://lore.kernel.org/bpf/4266fd5de04092aa4971cbef14f1b4b96961f432.ca...@gmail.com/
[2] https://lore.kernel.org/bpf/685b3c1b.050a0220.2303ee.0010....@google.com/

Signed-off-by: Luis Gerhorst <luis.gerho...@fau.de>
---
 tools/testing/selftests/bpf/progs/bpf_misc.h  |   4 +
 .../selftests/bpf/progs/verifier_unpriv.c     | 149 ++++++++++++++++++
 2 files changed, 153 insertions(+)

diff --git a/tools/testing/selftests/bpf/progs/bpf_misc.h 
b/tools/testing/selftests/bpf/progs/bpf_misc.h
index a678463e972c..be7d9bfa8390 100644
--- a/tools/testing/selftests/bpf/progs/bpf_misc.h
+++ b/tools/testing/selftests/bpf/progs/bpf_misc.h
@@ -235,4 +235,8 @@
 #define SPEC_V1
 #endif
 
+#if defined(__TARGET_ARCH_x86)
+#define SPEC_V4
+#endif
+
 #endif
diff --git a/tools/testing/selftests/bpf/progs/verifier_unpriv.c 
b/tools/testing/selftests/bpf/progs/verifier_unpriv.c
index 4470541b5e71..28b4f7035ceb 100644
--- a/tools/testing/selftests/bpf/progs/verifier_unpriv.c
+++ b/tools/testing/selftests/bpf/progs/verifier_unpriv.c
@@ -801,4 +801,153 @@ l2_%=:                                                    
\
        : __clobber_all);
 }
 
+SEC("socket")
+__description("unpriv: ldimm64 before Spectre v4 barrier")
+__success __success_unpriv
+__retval(0)
+#ifdef SPEC_V4
+__xlated_unpriv("r1 = 0x2020200005642020") /* should not matter */
+__xlated_unpriv("*(u64 *)(r10 -8) = r1")
+__xlated_unpriv("nospec")
+#endif
+__naked void unpriv_ldimm64_spectre_v4(void)
+{
+       asm volatile ("                                 \
+       r1 = 0x2020200005642020 ll;                     \
+       *(u64 *)(r10 -8) = r1;                          \
+       r0 = 0;                                         \
+       exit;                                           \
+"      ::: __clobber_all);
+}
+
+SEC("socket")
+__description("unpriv: Spectre v1 and v4 barrier")
+__success __success_unpriv
+__retval(0)
+#ifdef SPEC_V1
+#ifdef SPEC_V4
+/* starts with r0 == r8 == r9 == 0 */
+__xlated_unpriv("if r8 != 0x0 goto pc+1")
+__xlated_unpriv("goto pc+2")
+__xlated_unpriv("if r9 == 0x0 goto pc+4")
+__xlated_unpriv("r2 = r0")
+/* Following nospec required to prevent following dangerous `*(u64 *)(NOT_FP 
-64)
+ * = r1` iff `if r9 == 0 goto pc+4` was mispredicted because of Spectre v1. The
+ * test therefore ensures the Spectre-v4--induced nospec does not prevent the
+ * Spectre-v1--induced speculative path from being fully analyzed.
+ */
+__xlated_unpriv("nospec") /* Spectre v1 */
+__xlated_unpriv("*(u64 *)(r2 -64) = r1") /* could be used to leak r2 */
+__xlated_unpriv("nospec") /* Spectre v4 */
+#endif
+#endif
+__naked void unpriv_spectre_v1_and_v4(void)
+{
+       asm volatile ("                                 \
+       r1 = 0;                                         \
+       *(u64*)(r10 - 8) = r1;                          \
+       r2 = r10;                                       \
+       r2 += -8;                                       \
+       r1 = %[map_hash_8b] ll;                         \
+       call %[bpf_map_lookup_elem];                    \
+       r8 = r0;                                        \
+       r2 = r10;                                       \
+       r2 += -8;                                       \
+       r1 = %[map_hash_8b] ll;                         \
+       call %[bpf_map_lookup_elem];                    \
+       r9 = r0;                                        \
+       r0 = r10;                                       \
+       r1 = 0;                                         \
+       r2 = r10;                                       \
+       if r8 != 0 goto l0_%=;                          \
+       if r9 != 0 goto l0_%=;                          \
+       r0 = 0;                                         \
+l0_%=: if r8 != 0 goto l1_%=;                          \
+       goto l2_%=;                                     \
+l1_%=: if r9 == 0 goto l3_%=;                          \
+       r2 = r0;                                        \
+l2_%=: *(u64 *)(r2 -64) = r1;                          \
+l3_%=: r0 = 0;                                         \
+       exit;                                           \
+"      :
+       : __imm(bpf_map_lookup_elem),
+         __imm_addr(map_hash_8b)
+       : __clobber_all);
+}
+
+SEC("socket")
+__description("unpriv: Spectre v1 and v4 barrier (simple)")
+__success __success_unpriv
+__retval(0)
+#ifdef SPEC_V1
+#ifdef SPEC_V4
+__xlated_unpriv("if r8 != 0x0 goto pc+1")
+__xlated_unpriv("goto pc+2")
+__xlated_unpriv("goto pc-1") /* if r9 == 0 goto l3_%= */
+__xlated_unpriv("goto pc-1") /* r2 = r0 */
+__xlated_unpriv("nospec")
+__xlated_unpriv("*(u64 *)(r2 -64) = r1")
+__xlated_unpriv("nospec")
+#endif
+#endif
+__naked void unpriv_spectre_v1_and_v4_simple(void)
+{
+       asm volatile ("                                 \
+       r8 = 0;                                         \
+       r9 = 0;                                         \
+       r0 = r10;                                       \
+       r1 = 0;                                         \
+       r2 = r10;                                       \
+       if r8 != 0 goto l0_%=;                          \
+       if r9 != 0 goto l0_%=;                          \
+       r0 = 0;                                         \
+l0_%=: if r8 != 0 goto l1_%=;                          \
+       goto l2_%=;                                     \
+l1_%=: if r9 == 0 goto l3_%=;                          \
+       r2 = r0;                                        \
+l2_%=: *(u64 *)(r2 -64) = r1;                          \
+l3_%=: r0 = 0;                                         \
+       exit;                                           \
+"      ::: __clobber_all);
+}
+
+SEC("socket")
+__description("unpriv: ldimm64 before Spectre v1 and v4 barrier (simple)")
+__success __success_unpriv
+__retval(0)
+#ifdef SPEC_V1
+#ifdef SPEC_V4
+__xlated_unpriv("if r8 != 0x0 goto pc+1")
+__xlated_unpriv("goto pc+4")
+__xlated_unpriv("goto pc-1") /* if r9 == 0 goto l3_%= */
+__xlated_unpriv("goto pc-1") /* r2 = r0 */
+__xlated_unpriv("goto pc-1") /* r1 = 0x2020200005642020 ll */
+__xlated_unpriv("goto pc-1") /* second part of ldimm64 */
+__xlated_unpriv("nospec")
+__xlated_unpriv("*(u64 *)(r2 -64) = r1")
+__xlated_unpriv("nospec")
+#endif
+#endif
+__naked void unpriv_ldimm64_spectre_v1_and_v4_simple(void)
+{
+       asm volatile ("                                 \
+       r8 = 0;                                         \
+       r9 = 0;                                         \
+       r0 = r10;                                       \
+       r1 = 0;                                         \
+       r2 = r10;                                       \
+       if r8 != 0 goto l0_%=;                          \
+       if r9 != 0 goto l0_%=;                          \
+       r0 = 0;                                         \
+l0_%=: if r8 != 0 goto l1_%=;                          \
+       goto l2_%=;                                     \
+l1_%=: if r9 == 0 goto l3_%=;                          \
+       r2 = r0;                                        \
+       r1 = 0x2020200005642020 ll;                     \
+l2_%=: *(u64 *)(r2 -64) = r1;                          \
+l3_%=: r0 = 0;                                         \
+       exit;                                           \
+"      ::: __clobber_all);
+}
+
 char _license[] SEC("license") = "GPL";
-- 
2.49.0


Reply via email to