From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933815AbdJQHKq (ORCPT ); Tue, 17 Oct 2017 03:10:46 -0400 Received: from mx1.redhat.com ([209.132.183.28]:37464 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933796AbdJQHKk (ORCPT ); Tue, 17 Oct 2017 03:10:40 -0400 DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 84FD5C049D49 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 From: Eric Auger To: eric.auger.pro@gmail.com, eric.auger@redhat.com, linux-kernel@vger.kernel.org, kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu, marc.zyngier@arm.com, cdall@linaro.org, peter.maydell@linaro.org, andre.przywara@arm.com, wanghaibin.wang@huawei.com Cc: wu.wubin@huawei.com, drjones@redhat.com, wei@redhat.com Subject: [PATCH v4 03/11] KVM: arm/arm64: vgic-its: Improve error reporting on device table save Date: Tue, 17 Oct 2017 09:10:01 +0200 Message-Id: <1508224209-15366-4-git-send-email-eric.auger@redhat.com> In-Reply-To: <1508224209-15366-1-git-send-email-eric.auger@redhat.com> References: <1508224209-15366-1-git-send-email-eric.auger@redhat.com> X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Tue, 17 Oct 2017 07:10:40 +0000 (UTC) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 v2 -> v3: - correct kerneldoc comment --- virt/kvm/arm/vgic/vgic-its.c | 55 +++++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c index a4ff8f7..e59363e 100644 --- a/virt/kvm/arm/vgic/vgic-its.c +++ b/virt/kvm/arm/vgic/vgic-its.c @@ -687,15 +687,25 @@ static int vgic_its_cmd_handle_movi(struct kvm *kvm, struct vgic_its *its, return 0; } -/* - * 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. + * + * @its: its handle + * @baser: GITS_BASER register + * @id: id of the device/collection + * @eaddr: output gpa of the corresponding table entry + * * 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. + * + * 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) @@ -2093,9 +2112,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) -- 2.5.5 From mboxrd@z Thu Jan 1 00:00:00 1970 From: Eric Auger Subject: [PATCH v4 03/11] KVM: arm/arm64: vgic-its: Improve error reporting on device table save Date: Tue, 17 Oct 2017 09:10:01 +0200 Message-ID: <1508224209-15366-4-git-send-email-eric.auger@redhat.com> References: <1508224209-15366-1-git-send-email-eric.auger@redhat.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Cc: wu.wubin@huawei.com To: eric.auger.pro@gmail.com, eric.auger@redhat.com, linux-kernel@vger.kernel.org, kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu, marc.zyngier@arm.com, cdall@linaro.org, peter.maydell@linaro.org, andre.przywara@arm.com, wanghaibin.wang@huawei.com Return-path: In-Reply-To: <1508224209-15366-1-git-send-email-eric.auger@redhat.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: kvmarm-bounces@lists.cs.columbia.edu Sender: kvmarm-bounces@lists.cs.columbia.edu List-Id: kvm.vger.kernel.org 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 v2 -> v3: - correct kerneldoc comment --- virt/kvm/arm/vgic/vgic-its.c | 55 +++++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c index a4ff8f7..e59363e 100644 --- a/virt/kvm/arm/vgic/vgic-its.c +++ b/virt/kvm/arm/vgic/vgic-its.c @@ -687,15 +687,25 @@ static int vgic_its_cmd_handle_movi(struct kvm *kvm, struct vgic_its *its, return 0; } -/* - * 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. + * + * @its: its handle + * @baser: GITS_BASER register + * @id: id of the device/collection + * @eaddr: output gpa of the corresponding table entry + * * 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. + * + * 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) @@ -2093,9 +2112,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) -- 2.5.5