From patchwork Fri Apr 10 14:59:47 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andre Przywara X-Patchwork-Id: 6197491 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id A18EE9F1C4 for ; Fri, 10 Apr 2015 15:03:55 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 0F981203A0 for ; Fri, 10 Apr 2015 15:03:51 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 02FA420351 for ; Fri, 10 Apr 2015 15:03:50 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1YgaQ4-0008Tp-5o; Fri, 10 Apr 2015 15:00:32 +0000 Received: from cam-admin0.cambridge.arm.com ([217.140.96.50]) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1YgaPx-000785-34 for linux-arm-kernel@lists.infradead.org; Fri, 10 Apr 2015 15:00:27 +0000 Received: from e106785-lin.cambridge.arm.com ([10.1.203.153]) by cam-admin0.cambridge.arm.com (8.12.6/8.12.6) with ESMTP id t3AExlwo005220; Fri, 10 Apr 2015 15:59:47 +0100 (BST) From: Andre Przywara To: christoffer.dall@linaro.org, marc.zyngier@arm.com Subject: [PATCH v2] KVM: arm/arm64: avoid using kvm_run for in-kernel emulation Date: Fri, 10 Apr 2015 15:59:47 +0100 Message-Id: <1428677987-15494-1-git-send-email-andre.przywara@arm.com> X-Mailer: git-send-email 1.7.9.5 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20150410_080026_161054_FFB538A6 X-CRM114-Status: GOOD ( 14.91 ) X-Spam-Score: -5.0 (-----) Cc: kvmarm@lists.cs.columbia.edu, linux-arm-kernel@lists.infradead.org, kvm@vger.kernel.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Our in-kernel VGIC emulation still uses struct kvm_run briefly before writing back the emulation result into the guest register. Although this particular case looks safe from an exploitation perspective, we can save some unneeded copying at the end of the VGIC emulation code. Replace the usage of struct kvm_run in favour of passing separate parameters in io_mem_abort(). Since the write back is now handled for all kvm_io_bus users, we can get rid of it in the VGIC. Signed-off-by: Andre Przywara Reviewed-by: Christoffer Dall --- This one applies on top of kvmarm/queue. arch/arm/kvm/mmio.c | 65 ++++++++++++++++++++++++++++----------------------- virt/kvm/arm/vgic.c | 7 ------ 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c index 974b1c6..42004cb 100644 --- a/arch/arm/kvm/mmio.c +++ b/arch/arm/kvm/mmio.c @@ -85,6 +85,30 @@ static unsigned long mmio_read_buf(char *buf, unsigned int len) return data; } +static int kvm_writeback_mmio_data(struct kvm_vcpu *vcpu, unsigned int len, + void *data_ptr, gpa_t phys_addr) +{ + unsigned long data; + + if (len > sizeof(unsigned long)) + return -EINVAL; + + data = mmio_read_buf(data_ptr, len); + + if (vcpu->arch.mmio_decode.sign_extend && + len < sizeof(unsigned long)) { + int mask = 1U << ((len * 8) - 1); + + data = (data ^ mask) - mask; + } + + trace_kvm_mmio(KVM_TRACE_MMIO_READ, len, phys_addr, data); + data = vcpu_data_host_to_guest(vcpu, data, len); + *vcpu_reg(vcpu, vcpu->arch.mmio_decode.rt) = data; + + return 0; +} + /** * kvm_handle_mmio_return -- Handle MMIO loads after user space emulation * @vcpu: The VCPU pointer @@ -95,28 +119,10 @@ static unsigned long mmio_read_buf(char *buf, unsigned int len) */ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run) { - unsigned long data; - unsigned int len; - int mask; - - if (!run->mmio.is_write) { - len = run->mmio.len; - if (len > sizeof(unsigned long)) - return -EINVAL; - - data = mmio_read_buf(run->mmio.data, len); - - if (vcpu->arch.mmio_decode.sign_extend && - len < sizeof(unsigned long)) { - mask = 1U << ((len * 8) - 1); - data = (data ^ mask) - mask; - } - - trace_kvm_mmio(KVM_TRACE_MMIO_READ, len, run->mmio.phys_addr, - data); - data = vcpu_data_host_to_guest(vcpu, data, len); - *vcpu_reg(vcpu, vcpu->arch.mmio_decode.rt) = data; - } + if (!run->mmio.is_write) + return kvm_writeback_mmio_data(vcpu, run->mmio.len, + run->mmio.data, + run->mmio.phys_addr); return 0; } @@ -201,18 +207,19 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run, data_buf); } - /* Now prepare kvm_run for the potential return to userland. */ - run->mmio.is_write = is_write; - run->mmio.phys_addr = fault_ipa; - run->mmio.len = len; - memcpy(run->mmio.data, data_buf, len); - if (!ret) { /* We handled the access successfully in the kernel. */ - kvm_handle_mmio_return(vcpu, run); + if (!is_write) + kvm_writeback_mmio_data(vcpu, len, data_buf, fault_ipa); return 1; } + /* Now prepare the kvm_run structure for the return to userland. */ + run->mmio.is_write = is_write; + run->mmio.phys_addr = fault_ipa; + run->mmio.len = len; + memcpy(run->mmio.data, data_buf, len); run->exit_reason = KVM_EXIT_MMIO; + return 0; } diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index b70174e..e23f50d 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -803,7 +803,6 @@ static int vgic_handle_mmio_access(struct kvm_vcpu *vcpu, struct vgic_dist *dist = &vcpu->kvm->arch.vgic; struct vgic_io_device *iodev = container_of(this, struct vgic_io_device, dev); - struct kvm_run *run = vcpu->run; const struct vgic_io_range *range; struct kvm_exit_mmio mmio; bool updated_state; @@ -832,12 +831,6 @@ static int vgic_handle_mmio_access(struct kvm_vcpu *vcpu, updated_state = false; } spin_unlock(&dist->lock); - run->mmio.is_write = is_write; - run->mmio.len = len; - run->mmio.phys_addr = addr; - memcpy(run->mmio.data, val, len); - - kvm_handle_mmio_return(vcpu, run); if (updated_state) vgic_kick_vcpus(vcpu->kvm);