File 5b8d5832-x86-assorted-array_index_nospec-insertions.patch of Package xen.10697
# Commit 3f2002614af51dfd507168a1696658bac91155ce
# Date 2018-09-03 17:50:10 +0200
# Author Jan Beulich <jbeulich@suse.com>
# Committer Jan Beulich <jbeulich@suse.com>
x86: assorted array_index_nospec() insertions
Don't chance having Spectre v1 (including BCBS) gadgets. In some of the
cases the insertions are more of precautionary nature rather than there
provably being a gadget, but I think we should err on the safe (secure)
side here.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Paul Durrant <paul.durrant@citrix.com>
Acked-by: Razvan Cojocaru <rcojocaru@bitdefender.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -31,6 +31,7 @@
#include <xen/domain_page.h>
#include <xen/hypercall.h>
#include <xen/guest_access.h>
+#include <xen/nospec.h>
#include <xen/event.h>
#include <xen/paging.h>
#include <xen/cpu.h>
@@ -3898,9 +3899,16 @@ int hvm_do_hypercall(struct cpu_user_reg
if ( (eax & 0x80000000) && is_viridian_domain(curr->domain) )
return viridian_hypercall(regs);
- if ( (eax >= NR_hypercalls) ||
- (is_pvh_vcpu(curr) ? !pvh_hypercall64_table[eax]
- : !hvm_hypercall32_table[eax]) )
+ if ( eax >= NR_hypercalls )
+ {
+ regs->eax = -ENOSYS;
+ return HVM_HCALL_completed;
+ }
+
+ eax = array_index_nospec(eax, NR_hypercalls);
+
+ if ( is_pvh_vcpu(curr) ? !pvh_hypercall64_table[eax]
+ : !hvm_hypercall32_table[eax] )
{
regs->eax = -ENOSYS;
return HVM_HCALL_completed;
@@ -4771,6 +4779,7 @@ long do_hvm_op(unsigned long op, XEN_GUE
{
struct xen_hvm_set_mem_type a;
struct domain *d;
+ unsigned int mem_type;
/* Interface types to internal p2m types */
static const p2m_type_t memtype[] = {
@@ -4800,7 +4809,8 @@ long do_hvm_op(unsigned long op, XEN_GUE
((a.first_pfn + a.nr - 1) > domain_get_maximum_gpfn(d)) )
goto param_fail4;
- if ( a.hvmmem_type >= ARRAY_SIZE(memtype) )
+ mem_type = array_index_nospec(a.hvmmem_type, ARRAY_SIZE(memtype));
+ if ( mem_type >= ARRAY_SIZE(memtype) )
goto param_fail4;
while ( a.nr )
@@ -4824,21 +4834,21 @@ long do_hvm_op(unsigned long op, XEN_GUE
goto param_fail4;
}
if ( !p2m_is_ram(t) &&
- (!p2m_is_hole(t) || a.hvmmem_type != HVMMEM_mmio_dm) )
+ (!p2m_is_hole(t) || mem_type != HVMMEM_mmio_dm) )
{
put_gfn(d, pfn);
goto param_fail4;
}
else
{
- nt = p2m_change_type(d, pfn, t, memtype[a.hvmmem_type]);
+ nt = p2m_change_type(d, pfn, t, memtype[mem_type]);
if ( nt != t )
{
put_gfn(d, pfn);
gdprintk(XENLOG_WARNING,
"type of pfn %#lx changed from %d to %d while "
"we were trying to change it to %d\n",
- pfn, t, nt, memtype[a.hvmmem_type]);
+ pfn, t, nt, memtype[mem_type]);
goto param_fail4;
}
}
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -30,6 +30,7 @@
#include <asm/p2m.h>
#include <asm/hvm/vmx/vmx.h> /* ept_p2m_init() */
#include <xen/iommu.h>
+#include <xen/nospec.h>
#include <asm/mem_event.h>
#include <public/mem_event.h>
#include <asm/mem_sharing.h>
@@ -1423,6 +1424,7 @@ long p2m_set_mem_access(struct domain *d
if ( (unsigned) access >= HVMMEM_access_default )
return -EINVAL;
+ access = array_index_nospec(access, ARRAY_SIZE(memaccess));
a = memaccess[access];
/* If request to set default access */
--- a/xen/arch/x86/x86_64/compat/entry.S
+++ b/xen/arch/x86/x86_64/compat/entry.S
@@ -31,12 +31,13 @@ UNLIKELY_END(msi_check)
cmpl $NR_hypercalls,%eax
jae compat_bad_hypercall
+ sbbl %r8d,%r8d /* array_index_mask_nospec() */
+ andl %r8d,%eax
#ifndef NDEBUG
/* Deliberately corrupt parameter regs not used by this hypercall. */
pushq UREGS_rbx(%rsp); pushq %rcx; pushq %rdx; pushq %rsi; pushq %rdi
pushq UREGS_rbp+5*8(%rsp)
leaq compat_hypercall_args_table(%rip),%r10
- movl %eax,%eax
movl $6,%ecx
subb (%r10,%rax,1),%cl
movq %rsp,%rdi
@@ -51,7 +52,6 @@ UNLIKELY_END(msi_check)
#define SHADOW_BYTES 16 /* Shadow EIP + shadow hypercall # */
#else
/* Relocate argument registers and zero-extend to 64 bits. */
- movl %eax,%eax /* Hypercall # */
xchgl %ecx,%esi /* Arg 2, Arg 4 */
movl %edx,%edx /* Arg 3 */
movl %edi,%r8d /* Arg 5 */
@@ -61,6 +61,7 @@ UNLIKELY_END(msi_check)
#endif
cmpb $0,tb_init_done(%rip)
UNLIKELY_START(ne, compat_trace)
+ movl %eax,UREGS_rax+SHADOW_BYTES(%rsp) /* Hypercall # */
call __trace_hypercall_entry
/* Restore the registers that __trace_hypercall_entry clobbered. */
movl UREGS_rax+SHADOW_BYTES(%rsp),%eax /* Hypercall # */
--- a/xen/arch/x86/x86_64/entry.S
+++ b/xen/arch/x86/x86_64/entry.S
@@ -210,6 +210,8 @@ ENTRY(syscall_enter)
LOAD_C_CLOBBERED cx=0
cmpq $NR_hypercalls,%rax
jae bad_hypercall
+ sbbq %r10,%r10 /* array_index_mask_nospec() */
+ andq %r10,%rax
#ifndef NDEBUG
/* Deliberately corrupt parameter regs not used by this hypercall. */
pushq %rdi; pushq %rsi; pushq %rdx; pushq %rcx; pushq %r8 ; pushq %r9
@@ -229,6 +231,7 @@ ENTRY(syscall_enter)
#endif
cmpb $0,tb_init_done(%rip)
UNLIKELY_START(ne, trace)
+ movq %rax,UREGS_rax+SHADOW_BYTES(%rsp) /* Hypercall # */
call __trace_hypercall_entry
/* Restore the registers that __trace_hypercall_entry clobbered. */
movq UREGS_rax+SHADOW_BYTES(%rsp),%rax /* Hypercall # */