diff mbox series

[v2] virtio-iommu: Fix the partial copy of probe request

Message ID 20220617062024.3168331-1-zhenzhong.duan@intel.com (mailing list archive)
State New, archived
Headers show
Series [v2] virtio-iommu: Fix the partial copy of probe request | expand

Commit Message

Duan, Zhenzhong June 17, 2022, 6:20 a.m. UTC
The structure of probe request doesn't include the tail, this leads
to a few field missed to be copied. Currently this isn't an issue as
those missed field belong to reserved field, just in case reserved
field will be used in the future.

Fixes: 1733eebb9e75b ("virtio-iommu: Implement RESV_MEM probe request")
Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
---
 v2: keep bugfix change and drop cleanup change

 hw/virtio/virtio-iommu.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

Comments

Eric Auger June 22, 2022, 10:20 a.m. UTC | #1
Hi,

On 6/17/22 08:20, Zhenzhong Duan wrote:
> The structure of probe request doesn't include the tail, this leads
> to a few field missed to be copied. Currently this isn't an issue as
> those missed field belong to reserved field, just in case reserved
> field will be used in the future.
>
> Fixes: 1733eebb9e75b ("virtio-iommu: Implement RESV_MEM probe request")
> Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
nice catch.

Reviewed-by: Eric Auger <eric.auger@redhat.com>

the spec is pretty confusing here though (virtio-v1.2-csd01.pdf) as it
presents the struct as follows:

struct virtio_iommu_req_probe {
struct virtio_iommu_req_head head; /* Device-readable */
le32 endpoint;
u8 reserved[64]; /* Device-writable */
u8 properties[probe_size];
struct virtio_iommu_req_tail tail;
};

Adding Jean in the loop ...

Thanks!

Eric




> ---
>  v2: keep bugfix change and drop cleanup change
>
>  hw/virtio/virtio-iommu.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
> index 7c122ab95780..195f909620ab 100644
> --- a/hw/virtio/virtio-iommu.c
> +++ b/hw/virtio/virtio-iommu.c
> @@ -708,7 +708,8 @@ static int virtio_iommu_handle_probe(VirtIOIOMMU *s,
>                                       uint8_t *buf)
>  {
>      struct virtio_iommu_req_probe req;
> -    int ret = virtio_iommu_iov_to_req(iov, iov_cnt, &req, sizeof(req));
> +    int ret = virtio_iommu_iov_to_req(iov, iov_cnt, &req,
> +                    sizeof(req) + sizeof(struct virtio_iommu_req_tail));
>  
>      return ret ? ret : virtio_iommu_probe(s, &req, buf);
>  }
Jean-Philippe Brucker June 22, 2022, 11:55 a.m. UTC | #2
Hi,

On Wed, Jun 22, 2022 at 12:20:45PM +0200, Eric Auger wrote:
> Hi,
> 
> On 6/17/22 08:20, Zhenzhong Duan wrote:
> > The structure of probe request doesn't include the tail, this leads
> > to a few field missed to be copied. Currently this isn't an issue as
> > those missed field belong to reserved field, just in case reserved
> > field will be used in the future.
> >
> > Fixes: 1733eebb9e75b ("virtio-iommu: Implement RESV_MEM probe request")
> > Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
> nice catch.
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> 
> the spec is pretty confusing here though (virtio-v1.2-csd01.pdf) as it
> presents the struct as follows:
> 
> struct virtio_iommu_req_probe {
> struct virtio_iommu_req_head head;
> /* Device-readable */
> le32 endpoint;
> u8 reserved[64];
>
> /* Device-writable */
> u8 properties[probe_size];
> struct virtio_iommu_req_tail tail;
> };

Hm, which part is confusing?  Yes it's not valid C since probe_size is
defined dynamically ('probe_size' in the device config), but I thought it
would be nicer to show the whole request layout this way. Besides, at
least virtio-blk and virtio-scsi have similar variable-sized arrays in
their definitions

> 
> Adding Jean in the loop ...
> 
> Thanks!
> 
> Eric
> 
> 
> 
> 
> > ---
> >  v2: keep bugfix change and drop cleanup change
> >
> >  hw/virtio/virtio-iommu.c | 3 ++-
> >  1 file changed, 2 insertions(+), 1 deletion(-)
> >
> > diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
> > index 7c122ab95780..195f909620ab 100644
> > --- a/hw/virtio/virtio-iommu.c
> > +++ b/hw/virtio/virtio-iommu.c
> > @@ -708,7 +708,8 @@ static int virtio_iommu_handle_probe(VirtIOIOMMU *s,
> >                                       uint8_t *buf)
> >  {
> >      struct virtio_iommu_req_probe req;
> > -    int ret = virtio_iommu_iov_to_req(iov, iov_cnt, &req, sizeof(req));
> > +    int ret = virtio_iommu_iov_to_req(iov, iov_cnt, &req,
> > +                    sizeof(req) + sizeof(struct virtio_iommu_req_tail));

Not sure this is correct, because what we are doing here is reading the
device-readable part of the property from the request. That part is only
composed of fields 'head', 'endpoint' and 'reserved[64]' and its size is
indeed sizeof(struct virtio_iommu_req_probe).

The 'properties' and 'tail' fields shouldn't be read by the device here,
they are instead written later. It is virtio_iommu_handle_command() that
copies both of them into the request:

            output_size = s->config.probe_size + sizeof(tail);
            buf = g_malloc0(output_size);

            ptail = (struct virtio_iommu_req_tail *)
                        (buf + s->config.probe_size);
            ptail->status = virtio_iommu_handle_probe(s, iov, iov_cnt, buf);
	    // and virtio_iommu_probe() fills 'properties' as needed
	    ...

	// then copy the lot
        sz = iov_from_buf(elem->in_sg, elem->in_num, 0,
                          buf ? buf : &tail, output_size);

So I think the current code is correct, as all fields are accounted for

Thanks,
Jean

> >  
> >      return ret ? ret : virtio_iommu_probe(s, &req, buf);
> >  }
>
Eric Auger June 22, 2022, 12:22 p.m. UTC | #3
On 6/22/22 13:55, Jean-Philippe Brucker wrote:
> Hi,
>
> On Wed, Jun 22, 2022 at 12:20:45PM +0200, Eric Auger wrote:
>> Hi,
>>
>> On 6/17/22 08:20, Zhenzhong Duan wrote:
>>> The structure of probe request doesn't include the tail, this leads
>>> to a few field missed to be copied. Currently this isn't an issue as
>>> those missed field belong to reserved field, just in case reserved
>>> field will be used in the future.
>>>
>>> Fixes: 1733eebb9e75b ("virtio-iommu: Implement RESV_MEM probe request")
>>> Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
>> nice catch.
>>
>> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>>
>> the spec is pretty confusing here though (virtio-v1.2-csd01.pdf) as it
>> presents the struct as follows:
>>
>> struct virtio_iommu_req_probe {
>> struct virtio_iommu_req_head head;
>> /* Device-readable */
>> le32 endpoint;
>> u8 reserved[64];
>>
>> /* Device-writable */
>> u8 properties[probe_size];
>> struct virtio_iommu_req_tail tail;
>> };
> Hm, which part is confusing?  Yes it's not valid C since probe_size is
> defined dynamically ('probe_size' in the device config), but I thought it
> would be nicer to show the whole request layout this way. Besides, at
> least virtio-blk and virtio-scsi have similar variable-sized arrays in
> their definitions
the fact "struct virtio_iommu_req_tail tail;" was part of the

virtio_iommu_req_probe struct

>
>> Adding Jean in the loop ...
>>
>> Thanks!
>>
>> Eric
>>
>>
>>
>>
>>> ---
>>>  v2: keep bugfix change and drop cleanup change
>>>
>>>  hw/virtio/virtio-iommu.c | 3 ++-
>>>  1 file changed, 2 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
>>> index 7c122ab95780..195f909620ab 100644
>>> --- a/hw/virtio/virtio-iommu.c
>>> +++ b/hw/virtio/virtio-iommu.c
>>> @@ -708,7 +708,8 @@ static int virtio_iommu_handle_probe(VirtIOIOMMU *s,
>>>                                       uint8_t *buf)
>>>  {
>>>      struct virtio_iommu_req_probe req;
>>> -    int ret = virtio_iommu_iov_to_req(iov, iov_cnt, &req, sizeof(req));
>>> +    int ret = virtio_iommu_iov_to_req(iov, iov_cnt, &req,
>>> +                    sizeof(req) + sizeof(struct virtio_iommu_req_tail));
> Not sure this is correct, because what we are doing here is reading the
> device-readable part of the property from the request. That part is only
> composed of fields 'head', 'endpoint' and 'reserved[64]' and its size is
> indeed sizeof(struct virtio_iommu_req_probe).
>
> The 'properties' and 'tail' fields shouldn't be read by the device here,
> they are instead written later. It is virtio_iommu_handle_command() that
> copies both of them into the request:
>
>             output_size = s->config.probe_size + sizeof(tail);
>             buf = g_malloc0(output_size);
>
>             ptail = (struct virtio_iommu_req_tail *)
>                         (buf + s->config.probe_size);
>             ptail->status = virtio_iommu_handle_probe(s, iov, iov_cnt, buf);
> 	    // and virtio_iommu_probe() fills 'properties' as needed
> 	    ...
>
> 	// then copy the lot
>         sz = iov_from_buf(elem->in_sg, elem->in_num, 0,
>                           buf ? buf : &tail, output_size);
>
> So I think the current code is correct, as all fields are accounted for

In virtio_iommu_iov_to_req(), payload_sz is computed as

payload_sz = req_sz - sizeof(struct virtio_iommu_req_tail);

sz = iov_to_buf(iov, iov_cnt, 0, req, payload_sz);

This works for other command structs but not for probe one.

Eric


>
> Thanks,
> Jean
>
>>>  
>>>      return ret ? ret : virtio_iommu_probe(s, &req, buf);
>>>  }
Jean-Philippe Brucker June 22, 2022, 1:58 p.m. UTC | #4
On Wed, Jun 22, 2022 at 02:22:18PM +0200, Eric Auger wrote:
> >> the spec is pretty confusing here though (virtio-v1.2-csd01.pdf) as it
> >> presents the struct as follows:
> >>
> >> struct virtio_iommu_req_probe {
> >> struct virtio_iommu_req_head head;
> >> /* Device-readable */
> >> le32 endpoint;
> >> u8 reserved[64];
> >>
> >> /* Device-writable */
> >> u8 properties[probe_size];
> >> struct virtio_iommu_req_tail tail;
> >> };
> > Hm, which part is confusing?  Yes it's not valid C since probe_size is
> > defined dynamically ('probe_size' in the device config), but I thought it
> > would be nicer to show the whole request layout this way. Besides, at
> > least virtio-blk and virtio-scsi have similar variable-sized arrays in
> > their definitions
> the fact "struct virtio_iommu_req_tail tail;" was part of the
> 
> virtio_iommu_req_probe struct

Right, it would have been better to use a different name than
virtio_iommu_req_probe in virtio_iommu.h, to make the pitfall clear.

The larger problem is using C structs across the virtio spec instead of an
abstract format. Someone implementing the device in another language would
already not encounter this problem since they would read the spec as an
abstract format. For documentation purposes I do prefer displaying the
whole struct like this rather than working around limitations of C, which
may be more confusing.


> >>> diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
> >>> index 7c122ab95780..195f909620ab 100644
> >>> --- a/hw/virtio/virtio-iommu.c
> >>> +++ b/hw/virtio/virtio-iommu.c
> >>> @@ -708,7 +708,8 @@ static int virtio_iommu_handle_probe(VirtIOIOMMU *s,
> >>>                                       uint8_t *buf)
> >>>  {
> >>>      struct virtio_iommu_req_probe req;
> >>> -    int ret = virtio_iommu_iov_to_req(iov, iov_cnt, &req, sizeof(req));
> >>> +    int ret = virtio_iommu_iov_to_req(iov, iov_cnt, &req,
> >>> +                    sizeof(req) + sizeof(struct virtio_iommu_req_tail));
> > Not sure this is correct, because what we are doing here is reading the
> > device-readable part of the property from the request. That part is only
> > composed of fields 'head', 'endpoint' and 'reserved[64]' and its size is
> > indeed sizeof(struct virtio_iommu_req_probe).
> >
> > The 'properties' and 'tail' fields shouldn't be read by the device here,
> > they are instead written later. It is virtio_iommu_handle_command() that
> > copies both of them into the request:
> >
> >             output_size = s->config.probe_size + sizeof(tail);
> >             buf = g_malloc0(output_size);
> >
> >             ptail = (struct virtio_iommu_req_tail *)
> >                         (buf + s->config.probe_size);
> >             ptail->status = virtio_iommu_handle_probe(s, iov, iov_cnt, buf);
> > 	    // and virtio_iommu_probe() fills 'properties' as needed
> > 	    ...
> >
> > 	// then copy the lot
> >         sz = iov_from_buf(elem->in_sg, elem->in_num, 0,
> >                           buf ? buf : &tail, output_size);
> >
> > So I think the current code is correct, as all fields are accounted for
> 
> In virtio_iommu_iov_to_req(), payload_sz is computed as
> 
> payload_sz = req_sz - sizeof(struct virtio_iommu_req_tail);
> 
> sz = iov_to_buf(iov, iov_cnt, 0, req, payload_sz);
> 
> This works for other command structs but not for probe one.

Aah right sorry. The resulting code may be less confusing if we moved
"- sizeof(struct virtio_iommu_req_tail)" to virtio_iommu_handle_req()

Thanks,
Jean
Duan, Zhenzhong June 23, 2022, 1:40 a.m. UTC | #5
>-----Original Message-----
>From: Jean-Philippe Brucker <jean-philippe@linaro.org>
>Sent: Wednesday, June 22, 2022 9:58 PM
>To: Eric Auger <eric.auger@redhat.com>
>Cc: Duan, Zhenzhong <zhenzhong.duan@intel.com>; qemu-
>devel@nongnu.org; mst@redhat.com
>Subject: Re: [PATCH v2] virtio-iommu: Fix the partial copy of probe request
>
>On Wed, Jun 22, 2022 at 02:22:18PM +0200, Eric Auger wrote:
>> >> the spec is pretty confusing here though (virtio-v1.2-csd01.pdf) as
>> >> it presents the struct as follows:
>> >>
>> >> struct virtio_iommu_req_probe {
>> >> struct virtio_iommu_req_head head;
>> >> /* Device-readable */
>> >> le32 endpoint;
>> >> u8 reserved[64];
>> >>
>> >> /* Device-writable */
>> >> u8 properties[probe_size];
>> >> struct virtio_iommu_req_tail tail;
>> >> };
>> > Hm, which part is confusing?  Yes it's not valid C since probe_size
>> > is defined dynamically ('probe_size' in the device config), but I
>> > thought it would be nicer to show the whole request layout this way.
>> > Besides, at least virtio-blk and virtio-scsi have similar
>> > variable-sized arrays in their definitions
>> the fact "struct virtio_iommu_req_tail tail;" was part of the
>>
>> virtio_iommu_req_probe struct
>
>Right, it would have been better to use a different name than
>virtio_iommu_req_probe in virtio_iommu.h, to make the pitfall clear.
>
Maybe virtio_iommu_req_probe_no_tail?

>The larger problem is using C structs across the virtio spec instead of an
>abstract format. Someone implementing the device in another language
>would already not encounter this problem since they would read the spec as
>an abstract format. For documentation purposes I do prefer displaying the
>whole struct like this rather than working around limitations of C, which may
>be more confusing.
>
>
>> >>> diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
>> >>> index 7c122ab95780..195f909620ab 100644
>> >>> --- a/hw/virtio/virtio-iommu.c
>> >>> +++ b/hw/virtio/virtio-iommu.c
>> >>> @@ -708,7 +708,8 @@ static int
>virtio_iommu_handle_probe(VirtIOIOMMU *s,
>> >>>                                       uint8_t *buf)  {
>> >>>      struct virtio_iommu_req_probe req;
>> >>> -    int ret = virtio_iommu_iov_to_req(iov, iov_cnt, &req, sizeof(req));
>> >>> +    int ret = virtio_iommu_iov_to_req(iov, iov_cnt, &req,
>> >>> +                    sizeof(req) + sizeof(struct
>> >>> + virtio_iommu_req_tail));
>> > Not sure this is correct, because what we are doing here is reading
>> > the device-readable part of the property from the request. That part
>> > is only composed of fields 'head', 'endpoint' and 'reserved[64]' and
>> > its size is indeed sizeof(struct virtio_iommu_req_probe).
>> >
>> > The 'properties' and 'tail' fields shouldn't be read by the device
>> > here, they are instead written later. It is
>> > virtio_iommu_handle_command() that copies both of them into the
>request:
>> >
>> >             output_size = s->config.probe_size + sizeof(tail);
>> >             buf = g_malloc0(output_size);
>> >
>> >             ptail = (struct virtio_iommu_req_tail *)
>> >                         (buf + s->config.probe_size);
>> >             ptail->status = virtio_iommu_handle_probe(s, iov, iov_cnt, buf);
>> > 	    // and virtio_iommu_probe() fills 'properties' as needed
>> > 	    ...
>> >
>> > 	// then copy the lot
>> >         sz = iov_from_buf(elem->in_sg, elem->in_num, 0,
>> >                           buf ? buf : &tail, output_size);
>> >
>> > So I think the current code is correct, as all fields are accounted
>> > for
>>
>> In virtio_iommu_iov_to_req(), payload_sz is computed as
>>
>> payload_sz = req_sz - sizeof(struct virtio_iommu_req_tail);
>>
>> sz = iov_to_buf(iov, iov_cnt, 0, req, payload_sz);
>>
>> This works for other command structs but not for probe one.
>
>Aah right sorry. The resulting code may be less confusing if we moved
>"- sizeof(struct virtio_iommu_req_tail)" to virtio_iommu_handle_req()
>
Looks better, thanks. Will send v3.

Zhenzhong
Jean-Philippe Brucker June 23, 2022, 8:41 a.m. UTC | #6
On Thu, Jun 23, 2022 at 01:40:58AM +0000, Duan, Zhenzhong wrote:
> 
> 
> >-----Original Message-----
> >From: Jean-Philippe Brucker <jean-philippe@linaro.org>
> >Sent: Wednesday, June 22, 2022 9:58 PM
> >To: Eric Auger <eric.auger@redhat.com>
> >Cc: Duan, Zhenzhong <zhenzhong.duan@intel.com>; qemu-
> >devel@nongnu.org; mst@redhat.com
> >Subject: Re: [PATCH v2] virtio-iommu: Fix the partial copy of probe request
> >
> >On Wed, Jun 22, 2022 at 02:22:18PM +0200, Eric Auger wrote:
> >> >> the spec is pretty confusing here though (virtio-v1.2-csd01.pdf) as
> >> >> it presents the struct as follows:
> >> >>
> >> >> struct virtio_iommu_req_probe {
> >> >> struct virtio_iommu_req_head head;
> >> >> /* Device-readable */
> >> >> le32 endpoint;
> >> >> u8 reserved[64];
> >> >>
> >> >> /* Device-writable */
> >> >> u8 properties[probe_size];
> >> >> struct virtio_iommu_req_tail tail;
> >> >> };
> >> > Hm, which part is confusing?  Yes it's not valid C since probe_size
> >> > is defined dynamically ('probe_size' in the device config), but I
> >> > thought it would be nicer to show the whole request layout this way.
> >> > Besides, at least virtio-blk and virtio-scsi have similar
> >> > variable-sized arrays in their definitions
> >> the fact "struct virtio_iommu_req_tail tail;" was part of the
> >>
> >> virtio_iommu_req_probe struct
> >
> >Right, it would have been better to use a different name than
> >virtio_iommu_req_probe in virtio_iommu.h, to make the pitfall clear.
> >
> Maybe virtio_iommu_req_probe_no_tail?

Yes, we can't change the probe struct anymore since it's API, but we could
use the no_tail prefix on future structs

Thanks,
Jean
Eric Auger June 23, 2022, 9:28 a.m. UTC | #7
On 6/23/22 10:41, Jean-Philippe Brucker wrote:
> On Thu, Jun 23, 2022 at 01:40:58AM +0000, Duan, Zhenzhong wrote:
>>
>>> -----Original Message-----
>>> From: Jean-Philippe Brucker <jean-philippe@linaro.org>
>>> Sent: Wednesday, June 22, 2022 9:58 PM
>>> To: Eric Auger <eric.auger@redhat.com>
>>> Cc: Duan, Zhenzhong <zhenzhong.duan@intel.com>; qemu-
>>> devel@nongnu.org; mst@redhat.com
>>> Subject: Re: [PATCH v2] virtio-iommu: Fix the partial copy of probe request
>>>
>>> On Wed, Jun 22, 2022 at 02:22:18PM +0200, Eric Auger wrote:
>>>>>> the spec is pretty confusing here though (virtio-v1.2-csd01.pdf) as
>>>>>> it presents the struct as follows:
>>>>>>
>>>>>> struct virtio_iommu_req_probe {
>>>>>> struct virtio_iommu_req_head head;
>>>>>> /* Device-readable */
>>>>>> le32 endpoint;
>>>>>> u8 reserved[64];
>>>>>>
>>>>>> /* Device-writable */
>>>>>> u8 properties[probe_size];
>>>>>> struct virtio_iommu_req_tail tail;
>>>>>> };
>>>>> Hm, which part is confusing?  Yes it's not valid C since probe_size
>>>>> is defined dynamically ('probe_size' in the device config), but I
>>>>> thought it would be nicer to show the whole request layout this way.
>>>>> Besides, at least virtio-blk and virtio-scsi have similar
>>>>> variable-sized arrays in their definitions
>>>> the fact "struct virtio_iommu_req_tail tail;" was part of the
>>>>
>>>> virtio_iommu_req_probe struct
>>> Right, it would have been better to use a different name than
>>> virtio_iommu_req_probe in virtio_iommu.h, to make the pitfall clear.
>>>
>> Maybe virtio_iommu_req_probe_no_tail?
> Yes, we can't change the probe struct anymore since it's API, but we could
> use the no_tail prefix on future structs

agreed

Eric
>
> Thanks,
> Jean
>
diff mbox series

Patch

diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
index 7c122ab95780..195f909620ab 100644
--- a/hw/virtio/virtio-iommu.c
+++ b/hw/virtio/virtio-iommu.c
@@ -708,7 +708,8 @@  static int virtio_iommu_handle_probe(VirtIOIOMMU *s,
                                      uint8_t *buf)
 {
     struct virtio_iommu_req_probe req;
-    int ret = virtio_iommu_iov_to_req(iov, iov_cnt, &req, sizeof(req));
+    int ret = virtio_iommu_iov_to_req(iov, iov_cnt, &req,
+                    sizeof(req) + sizeof(struct virtio_iommu_req_tail));
 
     return ret ? ret : virtio_iommu_probe(s, &req, buf);
 }