From be15c231e7e351ea8dbcabf62f952537c637343d Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Thu, 4 Jul 2019 16:06:27 +0200 Subject: [PATCH] x86/vMSI: avoid speculative out of bounds accesses Array indexes used in the MMIO read/write emulation functions are derived from guest controlled values. Restrict their ranges to limit the side effects of speculative execution. Note that the index into .msi_ad[] may also be speculatively out of bounds, by exactly one (indexes 0...3 are possible while the array has just 3 elements). This is not a problem with the current data layout, as such overrun of the array would either touch the next element of the parent array or (for the last entry of the parent array) access the subsequent acc_valid bit array. This is part of the speculative hardening effort. Signed-off-by: Jan Beulich Reviewed-by: Andrew Cooper --- xen/arch/x86/hvm/vmsi.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/xen/arch/x86/hvm/vmsi.c b/xen/arch/x86/hvm/vmsi.c index aeb5a70104..6597d9f719 100644 --- a/xen/arch/x86/hvm/vmsi.c +++ b/xen/arch/x86/hvm/vmsi.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -231,8 +232,10 @@ static int msixtbl_read(const struct hvm_io_handler *handler, { nr_entry = (address - entry->gtable) / PCI_MSIX_ENTRY_SIZE; index = offset / sizeof(uint32_t); - if ( nr_entry >= MAX_MSIX_ACC_ENTRIES || - !acc_bit(test, entry, nr_entry, index) ) + if ( nr_entry >= ARRAY_SIZE(entry->gentries) ) + goto out; + nr_entry = array_index_nospec(nr_entry, ARRAY_SIZE(entry->gentries)); + if ( !acc_bit(test, entry, nr_entry, index) ) goto out; *pval = entry->gentries[nr_entry].msi_ad[index]; if ( len == 8 ) @@ -284,14 +287,18 @@ static int msixtbl_write(struct vcpu *v, unsigned long address, entry = msixtbl_find_entry(v, address); if ( !entry ) goto out; - nr_entry = (address - entry->gtable) / PCI_MSIX_ENTRY_SIZE; + nr_entry = array_index_nospec(((address - entry->gtable) / + PCI_MSIX_ENTRY_SIZE), + MAX_MSIX_TABLE_ENTRIES); offset = address & (PCI_MSIX_ENTRY_SIZE - 1); if ( offset != PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET ) { index = offset / sizeof(uint32_t); - if ( nr_entry < MAX_MSIX_ACC_ENTRIES ) + if ( nr_entry < ARRAY_SIZE(entry->gentries) ) { + nr_entry = array_index_nospec(nr_entry, + ARRAY_SIZE(entry->gentries)); entry->gentries[nr_entry].msi_ad[index] = val; acc_bit(set, entry, nr_entry, index); if ( len == 8 && !index ) -- 2.39.5