@@ -729,4 +729,61 @@ l0_%=: r0 = 0; \
729
729
" ::: __clobber_all );
730
730
}
731
731
732
+ SEC ("socket" )
733
+ __description ("unpriv: Spectre v1 path-based type confusion of scalar as stack-ptr" )
734
+ __success __success_unpriv __retval (0 )
735
+ #ifdef SPEC_V1
736
+ __xlated_unpriv ("if r0 != 0x1 goto pc+2" )
737
+ /* This nospec prevents the exploit because it forces the mispredicted (not
738
+ * taken) `if r0 != 0x0 goto l0_%=` to resolve before using r6 as a pointer.
739
+ * This causes the CPU to realize that `r6 = r9` should have never executed. It
740
+ * ensures that r6 always contains a readable stack slot ptr when the insn after
741
+ * the nospec executes.
742
+ */
743
+ __xlated_unpriv ("nospec" )
744
+ __xlated_unpriv ("r9 = *(u8 *)(r6 +0)" )
745
+ #endif
746
+ __naked void unpriv_spec_v1_type_confusion (void )
747
+ {
748
+ asm volatile (" \
749
+ r1 = 0; \
750
+ *(u64*)(r10 - 8) = r1; \
751
+ r2 = r10; \
752
+ r2 += -8; \
753
+ r1 = %[map_hash_8b] ll; \
754
+ call %[bpf_map_lookup_elem]; \
755
+ if r0 == 0 goto l2_%=; \
756
+ /* r0: pointer to a map array entry */ \
757
+ r2 = r10; \
758
+ r2 += -8; \
759
+ r1 = %[map_hash_8b] ll; \
760
+ /* r1, r2: prepared call args */ \
761
+ r6 = r10; \
762
+ r6 += -8; \
763
+ /* r6: pointer to readable stack slot */ \
764
+ r9 = 0xffffc900; \
765
+ r9 <<= 32; \
766
+ /* r9: scalar controlled by attacker */ \
767
+ r0 = *(u64 *)(r0 + 0); /* cache miss */ \
768
+ if r0 != 0x0 goto l0_%=; \
769
+ r6 = r9; \
770
+ l0_%=: if r0 != 0x1 goto l1_%=; \
771
+ r9 = *(u8 *)(r6 + 0); \
772
+ l1_%=: /* leak r9 */ \
773
+ r9 &= 1; \
774
+ r9 <<= 9; \
775
+ *(u64*)(r10 - 8) = r9; \
776
+ call %[bpf_map_lookup_elem]; \
777
+ if r0 == 0 goto l2_%=; \
778
+ /* leak secret into is_cached(map[0|512]): */ \
779
+ r0 = *(u64 *)(r0 + 0); \
780
+ l2_%=: \
781
+ r0 = 0; \
782
+ exit; \
783
+ " :
784
+ : __imm (bpf_map_lookup_elem ),
785
+ __imm_addr (map_hash_8b )
786
+ : __clobber_all );
787
+ }
788
+
732
789
char _license [] SEC ("license" ) = "GPL" ;
0 commit comments