x86/nospec: Use always_inline to fix code gen for evaluate_nospec
authorAndrew Cooper <andrew.cooper3@citrix.com>
Tue, 15 Oct 2019 09:14:51 +0000 (10:14 +0100)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Wed, 30 Oct 2019 13:07:25 +0000 (13:07 +0000)
commit8a74707a7c75d1eccfaeff6e71fe957c85976736
tree1fbcdf6181773e9203e457cb591d0b416d75c0ca
parentf51d4a19427674491eaecef85c551613450188c5
x86/nospec: Use always_inline to fix code gen for evaluate_nospec

evaluate_nospec() is incredibly fragile, and this is one giant bodge.

To correctly protect jumps, the generated code needs to be of the form:

    cmp/test <cond>
    jcc 1f
    lfence
    ...
 1: lfence
    ...

Critically, the lfence must be at the head of both basic blocks, later in the
instruction stream than the conditional jump in need of protection.

When the compiler chooses to out-of-line the condition calculation (e.g. by
not inlining a predicate), the code layout can end up as:

 pred:
    lfence
    <calculate cond>
    ret

    call pred
    cmp $0, %eax
    jcc 1f
    ...
 1: ...

which breaks the speculative safety, as the lfences are earlier in the
instruction stream than the jump in need of protection.

Any use of evaluate_nospec() needs all static inline predicates which use it
to be declared always_inline to prevent the optimiser having the flexibility
to generate unsafe code.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
Release-acked-by: Juergen Gross <jgross@suse.com>
xen/arch/x86/domain.c
xen/arch/x86/pv/mm.h
xen/include/asm-x86/event.h
xen/include/asm-x86/guest_pt.h
xen/include/asm-x86/hvm/nestedhvm.h
xen/include/asm-x86/paging.h
xen/include/xen/sched.h