From: Christoffer Dall <christoffer.dall@linaro.org>
To: Marc Zyngier <marc.zyngier@arm.com>
Cc: linux-arm-kernel@lists.infradead.org,
Andre Przywara <andre.przywara@arm.com>,
kvmarm@lists.cs.columbia.edu, kvm@vger.kernel.org
Subject: Re: [PATCH] KVM: arm64: vgic-its: Handle errors from vgic_add_lpi
Date: Tue, 2 Aug 2016 17:08:34 +0200 [thread overview]
Message-ID: <20160802150834.GT32244@cbox> (raw)
In-Reply-To: <57A0776F.5070401@arm.com>
On Tue, Aug 02, 2016 at 11:35:27AM +0100, Marc Zyngier wrote:
> On 01/08/16 19:29, Christoffer Dall wrote:
> > During low memory conditions, we could be dereferencing a NULL pointer
> > when vgic_add_lpi fails to allocate memory.
> >
> > Consider for example this call sequence:
> >
> > vgic_its_cmd_handle_mapi
> > itte->irq = vgic_add_lpi(kvm, lpi_nr);
> > update_lpi_config(kvm, itte->irq, NULL);
> > ret = kvm_read_guest(kvm, propbase + irq->intid
> > ^^^^
> > kaboom?
> >
> > Instead, return an error pointer from vgic_add_lpi and check the return
> > value from its single caller.
> >
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > virt/kvm/arm/vgic/vgic-its.c | 42 +++++++++++++++++++++++++++++-------------
> > 1 file changed, 29 insertions(+), 13 deletions(-)
> >
> > diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
> > index 07411cf..3515bdb 100644
> > --- a/virt/kvm/arm/vgic/vgic-its.c
> > +++ b/virt/kvm/arm/vgic/vgic-its.c
> > @@ -51,7 +51,7 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid)
> >
> > irq = kzalloc(sizeof(struct vgic_irq), GFP_KERNEL);
> > if (!irq)
> > - return NULL;
> > + return ERR_PTR(-ENOMEM);
> >
> > INIT_LIST_HEAD(&irq->lpi_list);
> > INIT_LIST_HEAD(&irq->ap_list);
> > @@ -697,24 +697,33 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
> > struct its_device *device;
> > struct its_collection *collection, *new_coll = NULL;
> > int lpi_nr;
> > -
> > - device = find_its_device(its, device_id);
> > - if (!device)
> > - return E_ITS_MAPTI_UNMAPPED_DEVICE;
> > + struct vgic_irq *irq = NULL;
> > + int err = 0;
> >
> > if (its_cmd_get_command(its_cmd) == GITS_CMD_MAPTI)
> > lpi_nr = its_cmd_get_physical_id(its_cmd);
> > else
> > lpi_nr = event_id;
> > +
> > if (lpi_nr < GIC_LPI_OFFSET ||
> > lpi_nr >= max_lpis_propbaser(kvm->arch.vgic.propbaser))
> > return E_ITS_MAPTI_PHYSICALID_OOR;
> >
> > + irq = vgic_add_lpi(kvm, lpi_nr);
> > + if (IS_ERR(irq))
> > + return PTR_ERR(irq);
> > +
> > + device = find_its_device(its, device_id);
> > + if (!device) {
> > + err = E_ITS_MAPTI_UNMAPPED_DEVICE;
> > + goto out;
> > + }
> > +
> > collection = find_collection(its, coll_id);
> > if (!collection) {
> > - int ret = vgic_its_alloc_collection(its, &collection, coll_id);
> > - if (ret)
> > - return ret;
> > + err = vgic_its_alloc_collection(its, &collection, coll_id);
> > + if (err)
> > + goto out;
> > new_coll = collection;
> > }
> >
> > @@ -722,9 +731,8 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
> > if (!itte) {
> > itte = kzalloc(sizeof(struct its_itte), GFP_KERNEL);
> > if (!itte) {
> > - if (new_coll)
> > - vgic_its_free_collection(its, coll_id);
> > - return -ENOMEM;
> > + err = -ENOMEM;
> > + goto out;
> > }
> >
> > itte->event_id = event_id;
> > @@ -733,7 +741,8 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
> >
> > itte->collection = collection;
> > itte->lpi = lpi_nr;
> > - itte->irq = vgic_add_lpi(kvm, lpi_nr);
> > + vgic_get_irq_kref(irq);
> > + itte->irq = irq;
> > update_affinity_itte(kvm, itte);
> >
> > /*
> > @@ -742,8 +751,15 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
> > * the respective config data from memory here upon mapping the LPI.
> > */
> > update_lpi_config(kvm, itte->irq, NULL);
> > + new_coll = NULL;
> > + irq = NULL;
> >
> > - return 0;
> > +out:
> > + if (new_coll)
> > + vgic_its_free_collection(its, coll_id);
> > + if (irq)
> > + vgic_put_irq(kvm, irq);
>
> Ah, it took me a moment to understand why you had the
> vgic_irq_get_kref() above. Maybe a small comment?
>
actually, now I'm confused.
vgic_add_lpi returns a struct vgic_irq with a reference count for the
reference in the itte struct, right?
So we never get a reference for the irq->lpi_list/dist->lpi_list_head ?
In which case my code above is wrong and I should not be getting the
extra reference. Right?
Now, this made me think of another issue. vgic_add_lpi has a blurb in
there about racing with another vgic_add_lpi and then it returns an irq
with an additional reference. But I don't understand how this can
happen, given that the function only has a single caller which has to
run with a mutex held???
Can two different itte's point to the same struct vgic_irq ?
Thanks,
-Christoffer
WARNING: multiple messages have this Message-ID (diff)
From: christoffer.dall@linaro.org (Christoffer Dall)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH] KVM: arm64: vgic-its: Handle errors from vgic_add_lpi
Date: Tue, 2 Aug 2016 17:08:34 +0200 [thread overview]
Message-ID: <20160802150834.GT32244@cbox> (raw)
In-Reply-To: <57A0776F.5070401@arm.com>
On Tue, Aug 02, 2016 at 11:35:27AM +0100, Marc Zyngier wrote:
> On 01/08/16 19:29, Christoffer Dall wrote:
> > During low memory conditions, we could be dereferencing a NULL pointer
> > when vgic_add_lpi fails to allocate memory.
> >
> > Consider for example this call sequence:
> >
> > vgic_its_cmd_handle_mapi
> > itte->irq = vgic_add_lpi(kvm, lpi_nr);
> > update_lpi_config(kvm, itte->irq, NULL);
> > ret = kvm_read_guest(kvm, propbase + irq->intid
> > ^^^^
> > kaboom?
> >
> > Instead, return an error pointer from vgic_add_lpi and check the return
> > value from its single caller.
> >
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > virt/kvm/arm/vgic/vgic-its.c | 42 +++++++++++++++++++++++++++++-------------
> > 1 file changed, 29 insertions(+), 13 deletions(-)
> >
> > diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
> > index 07411cf..3515bdb 100644
> > --- a/virt/kvm/arm/vgic/vgic-its.c
> > +++ b/virt/kvm/arm/vgic/vgic-its.c
> > @@ -51,7 +51,7 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid)
> >
> > irq = kzalloc(sizeof(struct vgic_irq), GFP_KERNEL);
> > if (!irq)
> > - return NULL;
> > + return ERR_PTR(-ENOMEM);
> >
> > INIT_LIST_HEAD(&irq->lpi_list);
> > INIT_LIST_HEAD(&irq->ap_list);
> > @@ -697,24 +697,33 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
> > struct its_device *device;
> > struct its_collection *collection, *new_coll = NULL;
> > int lpi_nr;
> > -
> > - device = find_its_device(its, device_id);
> > - if (!device)
> > - return E_ITS_MAPTI_UNMAPPED_DEVICE;
> > + struct vgic_irq *irq = NULL;
> > + int err = 0;
> >
> > if (its_cmd_get_command(its_cmd) == GITS_CMD_MAPTI)
> > lpi_nr = its_cmd_get_physical_id(its_cmd);
> > else
> > lpi_nr = event_id;
> > +
> > if (lpi_nr < GIC_LPI_OFFSET ||
> > lpi_nr >= max_lpis_propbaser(kvm->arch.vgic.propbaser))
> > return E_ITS_MAPTI_PHYSICALID_OOR;
> >
> > + irq = vgic_add_lpi(kvm, lpi_nr);
> > + if (IS_ERR(irq))
> > + return PTR_ERR(irq);
> > +
> > + device = find_its_device(its, device_id);
> > + if (!device) {
> > + err = E_ITS_MAPTI_UNMAPPED_DEVICE;
> > + goto out;
> > + }
> > +
> > collection = find_collection(its, coll_id);
> > if (!collection) {
> > - int ret = vgic_its_alloc_collection(its, &collection, coll_id);
> > - if (ret)
> > - return ret;
> > + err = vgic_its_alloc_collection(its, &collection, coll_id);
> > + if (err)
> > + goto out;
> > new_coll = collection;
> > }
> >
> > @@ -722,9 +731,8 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
> > if (!itte) {
> > itte = kzalloc(sizeof(struct its_itte), GFP_KERNEL);
> > if (!itte) {
> > - if (new_coll)
> > - vgic_its_free_collection(its, coll_id);
> > - return -ENOMEM;
> > + err = -ENOMEM;
> > + goto out;
> > }
> >
> > itte->event_id = event_id;
> > @@ -733,7 +741,8 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
> >
> > itte->collection = collection;
> > itte->lpi = lpi_nr;
> > - itte->irq = vgic_add_lpi(kvm, lpi_nr);
> > + vgic_get_irq_kref(irq);
> > + itte->irq = irq;
> > update_affinity_itte(kvm, itte);
> >
> > /*
> > @@ -742,8 +751,15 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
> > * the respective config data from memory here upon mapping the LPI.
> > */
> > update_lpi_config(kvm, itte->irq, NULL);
> > + new_coll = NULL;
> > + irq = NULL;
> >
> > - return 0;
> > +out:
> > + if (new_coll)
> > + vgic_its_free_collection(its, coll_id);
> > + if (irq)
> > + vgic_put_irq(kvm, irq);
>
> Ah, it took me a moment to understand why you had the
> vgic_irq_get_kref() above. Maybe a small comment?
>
actually, now I'm confused.
vgic_add_lpi returns a struct vgic_irq with a reference count for the
reference in the itte struct, right?
So we never get a reference for the irq->lpi_list/dist->lpi_list_head ?
In which case my code above is wrong and I should not be getting the
extra reference. Right?
Now, this made me think of another issue. vgic_add_lpi has a blurb in
there about racing with another vgic_add_lpi and then it returns an irq
with an additional reference. But I don't understand how this can
happen, given that the function only has a single caller which has to
run with a mutex held???
Can two different itte's point to the same struct vgic_irq ?
Thanks,
-Christoffer
next prev parent reply other threads:[~2016-08-02 15:00 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-08-01 18:29 [PATCH] KVM: arm64: vgic-its: Handle errors from vgic_add_lpi Christoffer Dall
2016-08-01 18:29 ` Christoffer Dall
2016-08-02 10:35 ` Marc Zyngier
2016-08-02 10:35 ` Marc Zyngier
2016-08-02 15:08 ` Christoffer Dall [this message]
2016-08-02 15:08 ` Christoffer Dall
2016-08-02 15:18 ` Marc Zyngier
2016-08-02 15:18 ` Marc Zyngier
2016-08-02 19:49 ` Christoffer Dall
2016-08-02 19:49 ` Christoffer Dall
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20160802150834.GT32244@cbox \
--to=christoffer.dall@linaro.org \
--cc=andre.przywara@arm.com \
--cc=kvm@vger.kernel.org \
--cc=kvmarm@lists.cs.columbia.edu \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=marc.zyngier@arm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.