On Tue, 11 Jul 2023 at 00:04, Michael S. Tsirkin <m...@redhat.com> wrote:
>
> From: Eric Auger <eric.au...@redhat.com>
>
> When running on a 64kB page size host and protecting a VFIO device
> with the virtio-iommu, qemu crashes with this kind of message:
>
> qemu-kvm: virtio-iommu page mask 0xfffffffffffff000 is incompatible
> with mask 0x20010000
> qemu: hardware error: vfio: DMA mapping failed, unable to continue
>
> This is due to the fact the IOMMU MR corresponding to the VFIO device
> is enabled very late on domain attach, after the machine init.
> The device reports a minimal 64kB page size but it is too late to be
> applied. virtio_iommu_set_page_size_mask() fails and this causes
> vfio_listener_region_add() to end up with hw_error();
>
> To work around this issue, we transiently enable the IOMMU MR on
> machine init to collect the page size requirements and then restore
> the bypass state.
>
> Fixes: 90519b9053 ("virtio-iommu: Add bypass mode support to assigned device")
> Signed-off-by: Eric Auger <eric.au...@redhat.com>

Hi; Coverity complains about this change (CID 1517772):

> +static void virtio_iommu_freeze_granule(Notifier *notifier, void *data)
> +{
> +    VirtIOIOMMU *s = container_of(notifier, VirtIOIOMMU, machine_done);
> +    int granule;
> +
> +    if (likely(s->config.bypass)) {
> +        /*
> +         * Transient IOMMU MR enable to collect page_size_mask requirements
> +         * through memory_region_iommu_set_page_size_mask() called by
> +         * VFIO region_add() callback
> +         */
> +         s->config.bypass = false;
> +         virtio_iommu_switch_address_space_all(s);
> +         /* restore default */
> +         s->config.bypass = true;
> +         virtio_iommu_switch_address_space_all(s);
> +    }
> +    s->granule_frozen = true;
> +    granule = ctz64(s->config.page_size_mask);
> +    trace_virtio_iommu_freeze_granule(BIT(granule));

Specifically, in this code, it thinks that ctz64() can
return 64, in which case BIT(granule) is shifting off
the end of the value, which is undefined behaviour.
This can happen if s->config.page_size_mask is 0 -- are
there assertions/checks that that can't happen elsewhere?

Secondly, BIT() only works for values up to 32, since
it works on type unsigned long, which might be a 32-bit
type on some hosts. Since you used ctz64()
you probably want BIT_ULL() which uses the ULL type
which definitely has 64 bits.

thanks
-- PMM

Reply via email to