The handlers for accessing the virtio-mmio header tried to be very clever, by modelling the internal data structure to look exactly like the protocol header, so that address offsets can "reused". This requires using a packed structure, which creates other problems, and seems to be totally unnecessary in this case. Replace the offset-based access hacks to the structure with proper compiler visible accesses, to avoid unaligned accesses and make the code more robust. This fixes UBSAN complaints about unaligned accesses. Signed-off-by: Andre Przywara <andre.przywara@xxxxxxx> --- include/kvm/virtio-mmio.h | 2 +- virtio/mmio.c | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/include/kvm/virtio-mmio.h b/include/kvm/virtio-mmio.h index 13dcccb6..aa4cab3c 100644 --- a/include/kvm/virtio-mmio.h +++ b/include/kvm/virtio-mmio.h @@ -39,7 +39,7 @@ struct virtio_mmio_hdr { u32 interrupt_ack; u32 reserved_5[2]; u32 status; -} __attribute__((packed)); +}; struct virtio_mmio { u32 addr; diff --git a/virtio/mmio.c b/virtio/mmio.c index 3782d55a..c9ad8ee7 100644 --- a/virtio/mmio.c +++ b/virtio/mmio.c @@ -135,12 +135,22 @@ static void virtio_mmio_config_in(struct kvm_cpu *vcpu, switch (addr) { case VIRTIO_MMIO_MAGIC_VALUE: + memcpy(data, &vmmio->hdr.magic, sizeof(vmmio->hdr.magic)); + break; case VIRTIO_MMIO_VERSION: + ioport__write32(data, vmmio->hdr.version); + break; case VIRTIO_MMIO_DEVICE_ID: + ioport__write32(data, vmmio->hdr.device_id); + break; case VIRTIO_MMIO_VENDOR_ID: + ioport__write32(data, vmmio->hdr.vendor_id); + break; case VIRTIO_MMIO_STATUS: + ioport__write32(data, vmmio->hdr.status); + break; case VIRTIO_MMIO_INTERRUPT_STATUS: - ioport__write32(data, *(u32 *)(((void *)&vmmio->hdr) + addr)); + ioport__write32(data, vmmio->hdr.interrupt_state); break; case VIRTIO_MMIO_DEVICE_FEATURES: if (vmmio->hdr.host_features_sel == 0) @@ -174,9 +184,10 @@ static void virtio_mmio_config_out(struct kvm_cpu *vcpu, switch (addr) { case VIRTIO_MMIO_DEVICE_FEATURES_SEL: + vmmio->hdr.host_features_sel = ioport__read32(data); + break; case VIRTIO_MMIO_DRIVER_FEATURES_SEL: - val = ioport__read32(data); - *(u32 *)(((void *)&vmmio->hdr) + addr) = val; + vmmio->hdr.guest_features_sel = ioport__read32(data); break; case VIRTIO_MMIO_QUEUE_SEL: val = ioport__read32(data); @@ -185,7 +196,7 @@ static void virtio_mmio_config_out(struct kvm_cpu *vcpu, val, vq_count); break; } - *(u32 *)(((void *)&vmmio->hdr) + addr) = val; + vmmio->hdr.queue_sel = val; break; case VIRTIO_MMIO_STATUS: vmmio->hdr.status = ioport__read32(data); -- 2.25.1