From patchwork Thu May 5 03:25:55 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Xu X-Patchwork-Id: 618813 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3r0gWS0Qdwz9t43 for ; Thu, 5 May 2016 13:34:28 +1000 (AEST) Received: from localhost ([::1]:51464 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ayA3S-0000ui-GC for incoming@patchwork.ozlabs.org; Wed, 04 May 2016 23:34:22 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48320) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ay9xI-0005Dk-CG for qemu-devel@nongnu.org; Wed, 04 May 2016 23:28:07 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ay9x6-0008Fb-4u for qemu-devel@nongnu.org; Wed, 04 May 2016 23:27:54 -0400 Received: from mx1.redhat.com ([209.132.183.28]:36535) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ay9x5-0008C2-TC for qemu-devel@nongnu.org; Wed, 04 May 2016 23:27:48 -0400 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id CAB3E8AE73; Thu, 5 May 2016 03:27:36 +0000 (UTC) Received: from pxdev.xzpeter.org.com (dhcp-14-147.nay.redhat.com [10.66.14.147]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u453Q5Pv016941; Wed, 4 May 2016 23:27:32 -0400 From: Peter Xu To: qemu-devel@nongnu.org Date: Thu, 5 May 2016 11:25:55 +0800 Message-Id: <1462418761-12714-21-git-send-email-peterx@redhat.com> In-Reply-To: <1462418761-12714-1-git-send-email-peterx@redhat.com> References: <1462418761-12714-1-git-send-email-peterx@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v6 20/26] intel_iommu: add SID validation for IR X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: ehabkost@redhat.com, mst@redhat.com, jasowang@redhat.com, rkrcmar@redhat.com, peterx@redhat.com, alex.williamson@redhat.com, jan.kiszka@web.de, wexu@redhat.com, pbonzini@redhat.com, marcel@redhat.com, imammedo@redhat.com, davidkiarie4@gmail.com, rth@twiddle.net Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This patch enables SID validation. Invalid interrupts will be dropped. Signed-off-by: Peter Xu --- hw/i386/intel_iommu.c | 70 +++++++++++++++++++++++++++++++++++-------- include/hw/i386/intel_iommu.h | 21 ++++++++++++- target-i386/kvm.c | 3 +- 3 files changed, 80 insertions(+), 14 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 1e57125..b8666b8 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -2002,11 +2002,15 @@ static Property vtd_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +uint16_t vtd_svt_mask[VTD_SQ_MAX] = {0xffff, 0xfffb, 0xfff9, 0xfff8}; + /* Read IRTE entry with specific index */ static int vtd_irte_get(IntelIOMMUState *iommu, uint16_t index, - VTD_IRTE *entry) + VTD_IRTE *entry, uint16_t sid) { dma_addr_t addr = 0x00; + uint16_t mask; + uint8_t bus, bus_max, bus_min; addr = iommu->intr_root + index * sizeof(*entry); if (dma_memory_read(&address_space_memory, addr, entry, @@ -2033,23 +2037,57 @@ static int vtd_irte_get(IntelIOMMUState *iommu, uint16_t index, return -VTD_FR_IR_IRTE_RSVD; } - /* - * TODO: Check Source-ID corresponds to SVT (Source Validation - * Type) bits - */ + if (sid != VTD_SID_INVALID) { + /* Validate IRTE SID */ + switch (entry->sid_vtype) { + case VTD_SVT_NONE: + VTD_DPRINTF(IR, "No SID validation for IRTE index %d", index); + break; + + case VTD_SVT_ALL: + mask = vtd_svt_mask[entry->sid_q]; + if ((entry->source_id & mask) != (sid & mask)) { + VTD_DPRINTF(GENERAL, "SID validation for IRTE index " + "%d failed (reqid 0x%04x sid 0x%04x)", index, + sid, entry->source_id); + return -VTD_FR_IR_SID_ERR; + } + break; + + case VTD_SVT_BUS: + bus_max = entry->source_id >> 8; + bus_min = entry->source_id & 0xff; + bus = sid >> 8; + if (bus > bus_max || bus < bus_min) { + VTD_DPRINTF(GENERAL, "SID validation for IRTE index %d " + "failed (bus %d outside %d-%d)", index, bus, + bus_min, bus_max); + return -VTD_FR_IR_SID_ERR; + } + break; + + default: + VTD_DPRINTF(GENERAL, "Invalid SVT bits (0x%x) in IRTE index " + "%d", entry->sid_vtype, index); + /* Take this as verification failure. */ + return -VTD_FR_IR_SID_ERR; + break; + } + } return 0; } /* Fetch IRQ information of specific IR index */ -static int vtd_remap_irq_get(IntelIOMMUState *iommu, uint16_t index, VTDIrq *irq) +static int vtd_remap_irq_get(IntelIOMMUState *iommu, uint16_t index, + VTDIrq *irq, uint16_t sid) { VTD_IRTE irte; int ret = 0; bzero(&irte, sizeof(irte)); - ret = vtd_irte_get(iommu, index, &irte); + ret = vtd_irte_get(iommu, index, &irte, sid); if (ret) { return ret; } @@ -2101,7 +2139,8 @@ static void vtd_generate_msi_message(VTDIrq *irq, MSIMessage *msg_out) /* Interrupt remapping for MSI/MSI-X entry */ static int vtd_interrupt_remap_msi(IntelIOMMUState *iommu, MSIMessage *origin, - MSIMessage *translated) + MSIMessage *translated, + uint16_t sid) { int ret = 0; VTD_IR_MSIAddress addr; @@ -2136,7 +2175,7 @@ static int vtd_interrupt_remap_msi(IntelIOMMUState *iommu, index = addr.index_h << 15 | addr.index_l; - ret = vtd_remap_irq_get(iommu, index, &irq); + ret = vtd_remap_irq_get(iommu, index, &irq, sid); if (ret) { return ret; } @@ -2180,9 +2219,10 @@ do_not_translate: return 0; } -int vtd_int_remap(void *iommu, MSIMessage *src, MSIMessage *dst) +int vtd_int_remap(void *iommu, MSIMessage *src, MSIMessage *dst, + uint16_t sid) { - return vtd_interrupt_remap_msi(iommu, src, dst); + return vtd_interrupt_remap_msi(iommu, src, dst, sid); } static MemTxResult vtd_mem_ir_read(void *opaque, hwaddr addr, @@ -2208,11 +2248,17 @@ static MemTxResult vtd_mem_ir_write(void *opaque, hwaddr addr, { int ret = 0; MSIMessage from = {0}, to = {0}; + uint16_t sid = VTD_SID_INVALID; from.address = (uint64_t) addr + VTD_INTERRUPT_ADDR_FIRST; from.data = (uint32_t) value; - ret = vtd_interrupt_remap_msi(opaque, &from, &to); + if (!attrs.unspecified) { + /* We have explicit Source ID */ + sid = attrs.requester_id; + } + + ret = vtd_interrupt_remap_msi(opaque, &from, &to, sid); if (ret) { /* TODO: report error */ VTD_DPRINTF(GENERAL, "int remap fail for addr 0x%"PRIx64 diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index c0c5819..0886cb7 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -103,6 +103,23 @@ struct VTDIOTLBEntry { bool write_flags; }; +/* VT-d Source-ID Qualifier types */ +enum { + VTD_SQ_FULL = 0x00, /* Full SID verification */ + VTD_SQ_IGN_3 = 0x01, /* Ignore bit 3 */ + VTD_SQ_IGN_2_3 = 0x02, /* Ignore bits 2 & 3 */ + VTD_SQ_IGN_1_3 = 0x03, /* Ignore bits 1-3 */ + VTD_SQ_MAX, +}; + +/* VT-d Source Validation Types */ +enum { + VTD_SVT_NONE = 0x00, /* No validation */ + VTD_SVT_ALL = 0x01, /* Do full validation */ + VTD_SVT_BUS = 0x02, /* Validate bus range */ + VTD_SVT_MAX, +}; + /* Interrupt Remapping Table Entry Definition */ union VTD_IRTE { struct { @@ -271,9 +288,11 @@ struct IntelIOMMUState { VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn); /* Get default IOMMU object */ IntelIOMMUState *vtd_iommu_get(void); -int vtd_int_remap(void *iommu, MSIMessage *src, MSIMessage *dst); +int vtd_int_remap(void *iommu, MSIMessage *src, MSIMessage *dst, uint16_t sid); /* Register IEC invalidate notifier */ void vtd_iec_register_notifier(IntelIOMMUState *s, vtd_iec_notify_fn fn, void *data); +#define VTD_SID_INVALID (0xffff) + #endif diff --git a/target-i386/kvm.c b/target-i386/kvm.c index ea5387c..6f601cb 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -3340,7 +3340,8 @@ int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route, src.address |= route->u.msi.address_lo; src.data = route->u.msi.data; - ret = vtd_int_remap(iommu, &src, &dst); + ret = vtd_int_remap(iommu, &src, &dst, dev ? pci_requester_id(dev) : + VTD_SID_INVALID); if (ret) { trace_kvm_x86_fixup_msi_error(route->gsi); return 1;