diff mbox series

[1/3] KVM: arm64: vgic-its: Add a data length check in vgic_its_save_*

Message ID 20240620130650.1279-2-jiangkunkun@huawei.com (mailing list archive)
State New, archived
Headers show
Series KVM: arm64: vgic-its: Some fixes about vgic-its | expand

Commit Message

Kunkun Jiang June 20, 2024, 1:06 p.m. UTC
In all the vgic_its_save_*() functinos, it does not check
whether the data length is larger than 8 bytes before
calling vgic_write_guest_lock. This patch add the check.

Link: https://lore.kernel.org/kvmarm/86v82ckimh.wl-maz@kernel.org/
Signed-off-by: Kunkun Jiang <jiangkunkun@huawei.com>
---
 arch/arm64/kvm/vgic/vgic-its.c | 3 +++
 1 file changed, 3 insertions(+)

Comments

Oliver Upton June 20, 2024, 10:25 p.m. UTC | #1
Hi,

On Thu, Jun 20, 2024 at 09:06:48PM +0800, Kunkun Jiang wrote:
> In all the vgic_its_save_*() functinos, it does not check
> whether the data length is larger than 8 bytes before
> calling vgic_write_guest_lock. This patch add the check.
> 
> Link: https://lore.kernel.org/kvmarm/86v82ckimh.wl-maz@kernel.org/
> Signed-off-by: Kunkun Jiang <jiangkunkun@huawei.com>
> ---
>  arch/arm64/kvm/vgic/vgic-its.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c
> index 40bb43f20bf3..060605fba3b6 100644
> --- a/arch/arm64/kvm/vgic/vgic-its.c
> +++ b/arch/arm64/kvm/vgic/vgic-its.c
> @@ -2094,6 +2094,7 @@ static int vgic_its_save_ite(struct vgic_its *its, struct its_device *dev,
>  	       ((u64)ite->irq->intid << KVM_ITS_ITE_PINTID_SHIFT) |
>  		ite->collection->collection_id;
>  	val = cpu_to_le64(val);
> +	BUG_ON(ite_esz > sizeof(val));

Does it really make sense to blow up the kernel over this? (hint: no)

What _might_ make sense if if you bugged the VM and failed the ioctl,
i.e.

	if (KVM_BUG_ON(ite_esz != sizeof(val), kvm))
		return -EINVAL;

Also, this isn't even asserting the right thing. You want to assert that
the u64 being written to memory is *exactly* the size of a single ITE.
No more, no less.

>  	return vgic_write_guest_lock(kvm, gpa, &val, ite_esz);
>  }
>  
> @@ -2246,6 +2247,7 @@ static int vgic_its_save_dte(struct vgic_its *its, struct its_device *dev,
>  	       (itt_addr_field << KVM_ITS_DTE_ITTADDR_SHIFT) |
>  		(dev->num_eventid_bits - 1));
>  	val = cpu_to_le64(val);
> +	BUG_ON(dte_esz > sizeof(dte_esz));

Did you even test this? A bit of substitution arrives at:

	BUG_ON(8 > sizeof(unsigned int));

See the issue?

Please do not test these sort of untested patches on the list, it is a
waste of everyone's time.
Kunkun Jiang June 21, 2024, 1:43 a.m. UTC | #2
Hi Oliver,

On 2024/6/21 6:25, Oliver Upton wrote:
> Hi,
>
> On Thu, Jun 20, 2024 at 09:06:48PM +0800, Kunkun Jiang wrote:
>> In all the vgic_its_save_*() functinos, it does not check
>> whether the data length is larger than 8 bytes before
>> calling vgic_write_guest_lock. This patch add the check.
>>
>> Link: https://lore.kernel.org/kvmarm/86v82ckimh.wl-maz@kernel.org/
>> Signed-off-by: Kunkun Jiang <jiangkunkun@huawei.com>
>> ---
>>   arch/arm64/kvm/vgic/vgic-its.c | 3 +++
>>   1 file changed, 3 insertions(+)
>>
>> diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c
>> index 40bb43f20bf3..060605fba3b6 100644
>> --- a/arch/arm64/kvm/vgic/vgic-its.c
>> +++ b/arch/arm64/kvm/vgic/vgic-its.c
>> @@ -2094,6 +2094,7 @@ static int vgic_its_save_ite(struct vgic_its *its, struct its_device *dev,
>>   	       ((u64)ite->irq->intid << KVM_ITS_ITE_PINTID_SHIFT) |
>>   		ite->collection->collection_id;
>>   	val = cpu_to_le64(val);
>> +	BUG_ON(ite_esz > sizeof(val));
> Does it really make sense to blow up the kernel over this? (hint: no)
>
> What _might_ make sense if if you bugged the VM and failed the ioctl,
> i.e.
>
> 	if (KVM_BUG_ON(ite_esz != sizeof(val), kvm))
> 		return -EINVAL;
>
> Also, this isn't even asserting the right thing. You want to assert that
> the u64 being written to memory is *exactly* the size of a single ITE.
> No more, no less.
This makes sense. I will modify it in the next version.

> static int vgic_its_restore_cte(struct vgic_its *its, gpa_t gpa, int esz)
> {
>         struct its_collection *collection;
>         struct kvm *kvm = its->dev->kvm;
>         u32 target_addr, coll_id;
>         u64 val;
>         int ret;
>
>         BUG_ON(esz > sizeof(val));
>         ret = kvm_read_guest_lock(kvm, gpa, &val, esz);
It should also be modified synchronously, right?
>>   	return vgic_write_guest_lock(kvm, gpa, &val, ite_esz);
>>   }
>>   
>> @@ -2246,6 +2247,7 @@ static int vgic_its_save_dte(struct vgic_its *its, struct its_device *dev,
>>   	       (itt_addr_field << KVM_ITS_DTE_ITTADDR_SHIFT) |
>>   		(dev->num_eventid_bits - 1));
>>   	val = cpu_to_le64(val);
>> +	BUG_ON(dte_esz > sizeof(dte_esz));
> Did you even test this? A bit of substitution arrives at:
>
> 	BUG_ON(8 > sizeof(unsigned int));
>
> See the issue?
>
> Please do not test these sort of untested patches on the list, it is a
> waste of everyone's time.
Sorry, there is a problem here. I will pay attention to it in the future.
Thank you for your correction.

Thanks,
Kunkun Jiang
Oliver Upton June 21, 2024, 6:39 a.m. UTC | #3
On Fri, Jun 21, 2024 at 09:43:05AM +0800, Kunkun Jiang wrote:
> > static int vgic_its_restore_cte(struct vgic_its *its, gpa_t gpa, int esz)
> > {
> >         struct its_collection *collection;
> >         struct kvm *kvm = its->dev->kvm;
> >         u32 target_addr, coll_id;
> >         u64 val;
> >         int ret;
> > 
> >         BUG_ON(esz > sizeof(val));
> >         ret = kvm_read_guest_lock(kvm, gpa, &val, esz);
> It should also be modified synchronously, right?

Do you mean replacing the other BUG_ON()'s in the ITS code with the
pattern I'd recommended earlier?

That'd be great if you could do that.

> > >   	return vgic_write_guest_lock(kvm, gpa, &val, ite_esz);
> > >   }
> > > @@ -2246,6 +2247,7 @@ static int vgic_its_save_dte(struct vgic_its *its, struct its_device *dev,
> > >   	       (itt_addr_field << KVM_ITS_DTE_ITTADDR_SHIFT) |
> > >   		(dev->num_eventid_bits - 1));
> > >   	val = cpu_to_le64(val);
> > > +	BUG_ON(dte_esz > sizeof(dte_esz));
> > Did you even test this? A bit of substitution arrives at:
> > 
> > 	BUG_ON(8 > sizeof(unsigned int));
> > 
> > See the issue?
> > 
> > Please do not test these sort of untested patches on the list, it is a
> > waste of everyone's time.
> Sorry, there is a problem here. I will pay attention to it in the future.
> Thank you for your correction.

Apologies for being firm on this, but outside of RFCs the expectation is
that the author test changes before posting to the list.

In that spirit, a reproducer for the issue you observe in KVM selftests
would be great. We have some minimal support for dealing with an ITS
over there now.
diff mbox series

Patch

diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c
index 40bb43f20bf3..060605fba3b6 100644
--- a/arch/arm64/kvm/vgic/vgic-its.c
+++ b/arch/arm64/kvm/vgic/vgic-its.c
@@ -2094,6 +2094,7 @@  static int vgic_its_save_ite(struct vgic_its *its, struct its_device *dev,
 	       ((u64)ite->irq->intid << KVM_ITS_ITE_PINTID_SHIFT) |
 		ite->collection->collection_id;
 	val = cpu_to_le64(val);
+	BUG_ON(ite_esz > sizeof(val));
 	return vgic_write_guest_lock(kvm, gpa, &val, ite_esz);
 }
 
@@ -2246,6 +2247,7 @@  static int vgic_its_save_dte(struct vgic_its *its, struct its_device *dev,
 	       (itt_addr_field << KVM_ITS_DTE_ITTADDR_SHIFT) |
 		(dev->num_eventid_bits - 1));
 	val = cpu_to_le64(val);
+	BUG_ON(dte_esz > sizeof(dte_esz));
 	return vgic_write_guest_lock(kvm, ptr, &val, dte_esz);
 }
 
@@ -2433,6 +2435,7 @@  static int vgic_its_save_cte(struct vgic_its *its,
 	       ((u64)collection->target_addr << KVM_ITS_CTE_RDBASE_SHIFT) |
 	       collection->collection_id);
 	val = cpu_to_le64(val);
+	BUG_ON(esz > sizeof(val));
 	return vgic_write_guest_lock(its->dev->kvm, gpa, &val, esz);
 }