From 212c5fe1914a192b01f337b7392fca75a7ab4071 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Mon, 6 Nov 2023 15:00:27 +0000 Subject: hw/i386/intel_iommu: vtd_slpte_nonzero_rsvd(): assert no overflow We support only 3- and 4-level page-tables, which is firstly checked in vtd_decide_config(), then setup in vtd_init(). Than level fields are checked by vtd_is_level_supported(). So here we can't have level out from 1..4 inclusive range. Let's assert it. That also explains Coverity that we are not going to overflow the array. CID: 1487158, 1487186 Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Peter Maydell Reviewed-by: Maksim Davydov Message-id: 20231017125941.810461-2-vsementsov@yandex-team.ru Signed-off-by: Peter Maydell --- hw/i386/intel_iommu.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) (limited to 'hw/i386') diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 1c6c186..1a44ef6 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -1045,18 +1045,35 @@ static dma_addr_t vtd_get_iova_pgtbl_base(IntelIOMMUState *s, * Rsvd field masks for spte: * vtd_spte_rsvd 4k pages * vtd_spte_rsvd_large large pages + * + * We support only 3-level and 4-level page tables (see vtd_init() which + * sets only VTD_CAP_SAGAW_39bit and maybe VTD_CAP_SAGAW_48bit bits in s->cap). */ -static uint64_t vtd_spte_rsvd[5]; -static uint64_t vtd_spte_rsvd_large[5]; +#define VTD_SPTE_RSVD_LEN 5 +static uint64_t vtd_spte_rsvd[VTD_SPTE_RSVD_LEN]; +static uint64_t vtd_spte_rsvd_large[VTD_SPTE_RSVD_LEN]; static bool vtd_slpte_nonzero_rsvd(uint64_t slpte, uint32_t level) { - uint64_t rsvd_mask = vtd_spte_rsvd[level]; + uint64_t rsvd_mask; + + /* + * We should have caught a guest-mis-programmed level earlier, + * via vtd_is_level_supported. + */ + assert(level < VTD_SPTE_RSVD_LEN); + /* + * Zero level doesn't exist. The smallest level is VTD_SL_PT_LEVEL=1 and + * checked by vtd_is_last_slpte(). + */ + assert(level); if ((level == VTD_SL_PD_LEVEL || level == VTD_SL_PDP_LEVEL) && (slpte & VTD_SL_PT_PAGE_SIZE_MASK)) { /* large page */ rsvd_mask = vtd_spte_rsvd_large[level]; + } else { + rsvd_mask = vtd_spte_rsvd[level]; } return slpte & rsvd_mask; -- cgit v1.1