From patchwork Wed Sep 27 13:28:33 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Auger X-Patchwork-Id: 9974085 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 7A8AC6037F for ; Wed, 27 Sep 2017 13:32:08 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 69E6628EEC for ; Wed, 27 Sep 2017 13:32:08 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 685BE28FA7; Wed, 27 Sep 2017 13:32:08 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id EEBCA291FC for ; Wed, 27 Sep 2017 13:31:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753199AbdI0N3E (ORCPT ); Wed, 27 Sep 2017 09:29:04 -0400 Received: from mx1.redhat.com ([209.132.183.28]:34210 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753097AbdI0N3C (ORCPT ); Wed, 27 Sep 2017 09:29:02 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 40C27C047B6D; Wed, 27 Sep 2017 13:29:02 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 40C27C047B6D Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=eric.auger@redhat.com Received: from localhost.localdomain.com (ovpn-116-163.ams2.redhat.com [10.36.116.163]) by smtp.corp.redhat.com (Postfix) with ESMTP id C360C8176D; Wed, 27 Sep 2017 13:28:59 +0000 (UTC) From: Eric Auger To: eric.auger.pro@gmail.com, eric.auger@redhat.com, linux-kernel@vger.kernel.org, kvm@vger.kernel.org, marc.zyngier@arm.com, cdall@linaro.org, peter.maydell@linaro.org, andre.przywara@arm.com, wanghaibin.wang@huawei.com Cc: wu.wubin@huawei.com Subject: [PATCH v2 03/10] KVM: arm/arm64: vgic-its: Improve error reporting on device table save Date: Wed, 27 Sep 2017 15:28:33 +0200 Message-Id: <1506518920-18571-4-git-send-email-eric.auger@redhat.com> In-Reply-To: <1506518920-18571-1-git-send-email-eric.auger@redhat.com> References: <1506518920-18571-1-git-send-email-eric.auger@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Wed, 27 Sep 2017 13:29:02 +0000 (UTC) Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP At the moment the device table save() returns -EINVAL if vgic_its_check_id() fails to return the gpa of the entry associated to the device/collection id. Let vgic_its_check_id() return an int instead of a bool and return a more precised error value: - EINVAL in case the id is out of range - EFAULT if the gpa is not provisionned or is not valid We also check first the GITS_BASER Valid bit is set. This allows the userspace to discriminate failure reasons. Signed-off-by: Eric Auger --- need to CC stable --- virt/kvm/arm/vgic/vgic-its.c | 53 ++++++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c index 76bed2d..c1f7972 100644 --- a/virt/kvm/arm/vgic/vgic-its.c +++ b/virt/kvm/arm/vgic/vgic-its.c @@ -688,14 +688,24 @@ static int vgic_its_cmd_handle_movi(struct kvm *kvm, struct vgic_its *its, } /* - * Check whether an ID can be stored into the corresponding guest table. + * vgic_its_check_id - Check whether an ID can be stored into + * the corresponding guest table. + * * For a direct table this is pretty easy, but gets a bit nasty for * indirect tables. We check whether the resulting guest physical address * is actually valid (covered by a memslot and guest accessible). * For this we have to read the respective first level entry. + * + * @its: its handle + * @baser: GITS_BASER register + * @id: id of the device/collection + * @eaddr: output gpa of the corresponding table entry + * + * Return: 0 on success, -EINVAL if @id is out of range, -EFAULT if + * the address cannot be computed or is not valid */ -static bool vgic_its_check_id(struct vgic_its *its, u64 baser, u32 id, - gpa_t *eaddr) +static int vgic_its_check_id(struct vgic_its *its, u64 baser, u32 id, + gpa_t *eaddr) { int l1_tbl_size = GITS_BASER_NR_PAGES(baser) * SZ_64K; u64 indirect_ptr, type = GITS_BASER_TYPE(baser); @@ -703,50 +713,56 @@ static bool vgic_its_check_id(struct vgic_its *its, u64 baser, u32 id, int index; gfn_t gfn; + if (!(baser & GITS_BASER_VALID)) + return -EFAULT; + switch (type) { case GITS_BASER_TYPE_DEVICE: if (id >= BIT_ULL(VITS_TYPER_DEVBITS)) - return false; + return -EINVAL; break; case GITS_BASER_TYPE_COLLECTION: /* as GITS_TYPER.CIL == 0, ITS supports 16-bit collection ID */ if (id >= BIT_ULL(16)) - return false; + return -EINVAL; break; default: - return false; + return -EINVAL; } if (!(baser & GITS_BASER_INDIRECT)) { phys_addr_t addr; if (id >= (l1_tbl_size / esz)) - return false; + return -EINVAL; addr = BASER_ADDRESS(baser) + id * esz; gfn = addr >> PAGE_SHIFT; if (eaddr) *eaddr = addr; - return kvm_is_visible_gfn(its->dev->kvm, gfn); + if (kvm_is_visible_gfn(its->dev->kvm, gfn)) + return 0; + else + return -EFAULT; } /* calculate and check the index into the 1st level */ index = id / (SZ_64K / esz); if (index >= (l1_tbl_size / sizeof(u64))) - return false; + return -EINVAL; /* Each 1st level entry is represented by a 64-bit value. */ if (kvm_read_guest(its->dev->kvm, BASER_ADDRESS(baser) + index * sizeof(indirect_ptr), &indirect_ptr, sizeof(indirect_ptr))) - return false; + return -EFAULT; indirect_ptr = le64_to_cpu(indirect_ptr); /* check the valid bit of the first level entry */ if (!(indirect_ptr & BIT_ULL(63))) - return false; + return -EFAULT; /* * Mask the guest physical address and calculate the frame number. @@ -762,7 +778,10 @@ static bool vgic_its_check_id(struct vgic_its *its, u64 baser, u32 id, if (eaddr) *eaddr = indirect_ptr; - return kvm_is_visible_gfn(its->dev->kvm, gfn); + if (kvm_is_visible_gfn(its->dev->kvm, gfn)) + return 0; + else + return -EFAULT; } static int vgic_its_alloc_collection(struct vgic_its *its, @@ -771,7 +790,7 @@ static int vgic_its_alloc_collection(struct vgic_its *its, { struct its_collection *collection; - if (!vgic_its_check_id(its, its->baser_coll_table, coll_id, NULL)) + if (vgic_its_check_id(its, its->baser_coll_table, coll_id, NULL)) return E_ITS_MAPC_COLLECTION_OOR; collection = kzalloc(sizeof(*collection), GFP_KERNEL); @@ -943,7 +962,7 @@ static int vgic_its_cmd_handle_mapd(struct kvm *kvm, struct vgic_its *its, gpa_t itt_addr = its_cmd_get_ittaddr(its_cmd); struct its_device *device; - if (!vgic_its_check_id(its, its->baser_device_table, device_id, NULL)) + if (vgic_its_check_id(its, its->baser_device_table, device_id, NULL)) return E_ITS_MAPD_DEVICE_OOR; if (valid && num_eventid_bits > VITS_TYPER_IDBITS) @@ -2060,9 +2079,9 @@ static int vgic_its_save_device_tables(struct vgic_its *its) int ret; gpa_t eaddr; - if (!vgic_its_check_id(its, baser, - dev->device_id, &eaddr)) - return -EINVAL; + ret = vgic_its_check_id(its, baser, dev->device_id, &eaddr); + if (ret) + return ret; ret = vgic_its_save_itt(its, dev); if (ret)