diff mbox series

[v3,3/9] hw/usb: reorder fields in UASStatus

Message ID 20201105221905.1350-4-dbuono@linux.vnet.ibm.com
State New
Headers show
Series Add support for Control-Flow Integrity | expand

Commit Message

Daniele Buono Nov. 5, 2020, 10:18 p.m. UTC
The UASStatus data structure has a variable sized field inside of type uas_iu,
that however is not placed at the end of the data structure.

This placement triggers a warning with clang 11, and while not a bug right now,
(the status is never a uas_iu_command, which is the variable-sized case),
it could become one in the future.

../qemu-base/hw/usb/dev-uas.c:157:31: error: field 'status' with variable sized type 'uas_iu' not at the end of a struct or class is a GNU extension [-Werror,-Wgnu-variable-sized-type-not-at-end]
    uas_iu                    status;
                              ^
1 error generated.

Fix this by moving uas_iu at the end of the struct

Signed-off-by: Daniele Buono <dbuono@linux.vnet.ibm.com>
---
 hw/usb/dev-uas.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Comments

Philippe Mathieu-Daudé Nov. 6, 2020, 2:28 p.m. UTC | #1
On 11/5/20 11:18 PM, Daniele Buono wrote:
> The UASStatus data structure has a variable sized field inside of type uas_iu,

> that however is not placed at the end of the data structure.

> 

> This placement triggers a warning with clang 11, and while not a bug right now,

> (the status is never a uas_iu_command, which is the variable-sized case),

> it could become one in the future.


The problem is uas_iu_command::add_cdb, indeed.

> 

> ../qemu-base/hw/usb/dev-uas.c:157:31: error: field 'status' with variable sized type 'uas_iu' not at the end of a struct or class is a GNU extension [-Werror,-Wgnu-variable-sized-type-not-at-end]


If possible remove the "../qemu-base/" as it does not provide
any useful information.

>     uas_iu                    status;

>                               ^

> 1 error generated.

> 

> Fix this by moving uas_iu at the end of the struct


Your patch silents the warning, but the problem is the same.
It would be safer/cleaner to make 'status' a pointer on the heap IMO.

> 

> Signed-off-by: Daniele Buono <dbuono@linux.vnet.ibm.com>

> ---

>  hw/usb/dev-uas.c | 2 +-

>  1 file changed, 1 insertion(+), 1 deletion(-)

> 

> diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c

> index cec071d96c..5ef3f4fec9 100644

> --- a/hw/usb/dev-uas.c

> +++ b/hw/usb/dev-uas.c

> @@ -154,9 +154,9 @@ struct UASRequest {

>  

>  struct UASStatus {

>      uint32_t                  stream;

> -    uas_iu                    status;

>      uint32_t                  length;

>      QTAILQ_ENTRY(UASStatus)   next;

> +    uas_iu                    status;

>  };

>  

>  /* --------------------------------------------------------------------- */

>
Daniele Buono Nov. 19, 2020, 4:16 p.m. UTC | #2
Hi Philippe,

On 11/6/2020 9:28 AM, Philippe Mathieu-Daudé wrote:
> On 11/5/20 11:18 PM, Daniele Buono wrote:

>> The UASStatus data structure has a variable sized field inside of type uas_iu,

>> that however is not placed at the end of the data structure.

>>

>> This placement triggers a warning with clang 11, and while not a bug right now,

>> (the status is never a uas_iu_command, which is the variable-sized case),

>> it could become one in the future.

> 

> The problem is uas_iu_command::add_cdb, indeed.

> 

>>

>> ../qemu-base/hw/usb/dev-uas.c:157:31: error: field 'status' with variable sized type 'uas_iu' not at the end of a struct or class is a GNU extension [-Werror,-Wgnu-variable-sized-type-not-at-end]

> 

> If possible remove the "../qemu-base/" as it does not provide

> any useful information.

> 

Sure, will do at the next cycle
>>      uas_iu                    status;

>>                                ^

>> 1 error generated.

>>

>> Fix this by moving uas_iu at the end of the struct

> 

> Your patch silents the warning, but the problem is the same.

> It would be safer/cleaner to make 'status' a pointer on the heap IMO.


I'm thinking of moving 'status' in a pointer with the following code
changes:

UASStatus is allocated in `usb_uas_alloc_status`, which currently does
not take a type or size for the union field. I'm thinking of adding
requested size for the status, like this:

static UASStatus *usb_uas_alloc_status(UASDevice *uas, uint8_t id,
uint16_t tag, size_t size);

and the common call would be
usb_uas_alloc_status([...],sizeof(uas_iu));

Also we'd need a double free when the object is freed. Right now
it's handled in the code when the object is not used anymore with a
`g_free(st);`.
I'd have to replace it with
`g_free(st->status); g_free(st);`. Would you suggest doing it place
or by adding a usb_uas_dealloc_status() function?

---

However, I am confused by the use of that variable-lenght field.
I'm looking at what seems the only place where a command is
parsed, in `usb_uas_handle_data`.

uas_iu iu;
[...]
     switch (p->ep->nr) {
     case UAS_PIPE_ID_COMMAND:
         length = MIN(sizeof(iu), p->iov.size);
         usb_packet_copy(p, &iu, length);
         [...]
         break;
[...]

It would seem that the copy is limited to at most sizeof(uas_iu),
so even if we had anything in add_cdb[], that wouldn't be copied
here?

Is this intended?

> 

>>

>> Signed-off-by: Daniele Buono <dbuono@linux.vnet.ibm.com>

>> ---

>>   hw/usb/dev-uas.c | 2 +-

>>   1 file changed, 1 insertion(+), 1 deletion(-)

>>

>> diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c

>> index cec071d96c..5ef3f4fec9 100644

>> --- a/hw/usb/dev-uas.c

>> +++ b/hw/usb/dev-uas.c

>> @@ -154,9 +154,9 @@ struct UASRequest {

>>   

>>   struct UASStatus {

>>       uint32_t                  stream;

>> -    uas_iu                    status;

>>       uint32_t                  length;

>>       QTAILQ_ENTRY(UASStatus)   next;

>> +    uas_iu                    status;

>>   };

>>   

>>   /* --------------------------------------------------------------------- */

>>

>
Marc-André Lureau Jan. 14, 2021, 8:17 a.m. UTC | #3
Hi

On Thu, Nov 19, 2020 at 8:19 PM Daniele Buono <dbuono@linux.vnet.ibm.com>
wrote:

> Hi Philippe,

>

> On 11/6/2020 9:28 AM, Philippe Mathieu-Daudé wrote:

> > On 11/5/20 11:18 PM, Daniele Buono wrote:

> >> The UASStatus data structure has a variable sized field inside of type

> uas_iu,

> >> that however is not placed at the end of the data structure.

> >>

> >> This placement triggers a warning with clang 11, and while not a bug

> right now,

> >> (the status is never a uas_iu_command, which is the variable-sized

> case),

> >> it could become one in the future.

> >

> > The problem is uas_iu_command::add_cdb, indeed.

> >

> >>

> >> ../qemu-base/hw/usb/dev-uas.c:157:31: error: field 'status' with

> variable sized type 'uas_iu' not at the end of a struct or class is a GNU

> extension [-Werror,-Wgnu-variable-sized-type-not-at-end]

> >

> > If possible remove the "../qemu-base/" as it does not provide

> > any useful information.

> >

> Sure, will do at the next cycle

> >>      uas_iu                    status;

> >>                                ^

> >> 1 error generated.

> >>

> >> Fix this by moving uas_iu at the end of the struct

> >

> > Your patch silents the warning, but the problem is the same.

> > It would be safer/cleaner to make 'status' a pointer on the heap IMO.

>

> I'm thinking of moving 'status' in a pointer with the following code

> changes:

>

> UASStatus is allocated in `usb_uas_alloc_status`, which currently does

> not take a type or size for the union field. I'm thinking of adding

> requested size for the status, like this:

>

> static UASStatus *usb_uas_alloc_status(UASDevice *uas, uint8_t id,

> uint16_t tag, size_t size);

>

> and the common call would be

> usb_uas_alloc_status([...],sizeof(uas_iu));

>

> Also we'd need a double free when the object is freed. Right now

> it's handled in the code when the object is not used anymore with a

> `g_free(st);`.

> I'd have to replace it with

> `g_free(st->status); g_free(st);`. Would you suggest doing it place

> or by adding a usb_uas_dealloc_status() function?

>

> ---

>

> However, I am confused by the use of that variable-lenght field.

> I'm looking at what seems the only place where a command is

> parsed, in `usb_uas_handle_data`.

>

> uas_iu iu;

> [...]

>      switch (p->ep->nr) {

>      case UAS_PIPE_ID_COMMAND:

>          length = MIN(sizeof(iu), p->iov.size);

>          usb_packet_copy(p, &iu, length);

>          [...]

>          break;

> [...]

>

> It would seem that the copy is limited to at most sizeof(uas_iu),

> so even if we had anything in add_cdb[], that wouldn't be copied

> here?

>

> Is this intended?

>

>

Any update on this patch?
thanks


-- 
Marc-André Lureau
<div dir="ltr"><div dir="ltr">Hi<br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Nov 19, 2020 at 8:19 PM Daniele Buono &lt;<a href="mailto:dbuono@linux.vnet.ibm.com">dbuono@linux.vnet.ibm.com</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Hi Philippe,<br>
<br>
On 11/6/2020 9:28 AM, Philippe Mathieu-Daudé wrote:<br>
&gt; On 11/5/20 11:18 PM, Daniele Buono wrote:<br>
&gt;&gt; The UASStatus data structure has a variable sized field inside of type uas_iu,<br>
&gt;&gt; that however is not placed at the end of the data structure.<br>
&gt;&gt;<br>
&gt;&gt; This placement triggers a warning with clang 11, and while not a bug right now,<br>
&gt;&gt; (the status is never a uas_iu_command, which is the variable-sized case),<br>
&gt;&gt; it could become one in the future.<br>
&gt; <br>
&gt; The problem is uas_iu_command::add_cdb, indeed.<br>
&gt; <br>
&gt;&gt;<br>
&gt;&gt; ../qemu-base/hw/usb/dev-uas.c:157:31: error: field &#39;status&#39; with variable sized type &#39;uas_iu&#39; not at the end of a struct or class is a GNU extension [-Werror,-Wgnu-variable-sized-type-not-at-end]<br>
&gt; <br>
&gt; If possible remove the &quot;../qemu-base/&quot; as it does not provide<br>
&gt; any useful information.<br>
&gt; <br>
Sure, will do at the next cycle<br>
&gt;&gt;      uas_iu                    status;<br>
&gt;&gt;                                ^<br>
&gt;&gt; 1 error generated.<br>
&gt;&gt;<br>
&gt;&gt; Fix this by moving uas_iu at the end of the struct<br>
&gt; <br>
&gt; Your patch silents the warning, but the problem is the same.<br>
&gt; It would be safer/cleaner to make &#39;status&#39; a pointer on the heap IMO.<br>
<br>
I&#39;m thinking of moving &#39;status&#39; in a pointer with the following code<br>
changes:<br>
<br>
UASStatus is allocated in `usb_uas_alloc_status`, which currently does<br>
not take a type or size for the union field. I&#39;m thinking of adding<br>
requested size for the status, like this:<br>
<br>
static UASStatus *usb_uas_alloc_status(UASDevice *uas, uint8_t id,<br>
uint16_t tag, size_t size);<br>
<br>
and the common call would be<br>
usb_uas_alloc_status([...],sizeof(uas_iu));<br>
<br>
Also we&#39;d need a double free when the object is freed. Right now<br>
it&#39;s handled in the code when the object is not used anymore with a<br>
`g_free(st);`.<br>
I&#39;d have to replace it with<br>
`g_free(st-&gt;status); g_free(st);`. Would you suggest doing it place<br>
or by adding a usb_uas_dealloc_status() function?<br>
<br>
---<br>
<br>
However, I am confused by the use of that variable-lenght field.<br>
I&#39;m looking at what seems the only place where a command is<br>
parsed, in `usb_uas_handle_data`.<br>
<br>
uas_iu iu;<br>
[...]<br>
     switch (p-&gt;ep-&gt;nr) {<br>
     case UAS_PIPE_ID_COMMAND:<br>
         length = MIN(sizeof(iu), p-&gt;iov.size);<br>
         usb_packet_copy(p, &amp;iu, length);<br>
         [...]<br>
         break;<br>
[...]<br>
<br>
It would seem that the copy is limited to at most sizeof(uas_iu),<br>
so even if we had anything in add_cdb[], that wouldn&#39;t be copied<br>
here?<br>
<br>
Is this intended?<br>
<br></blockquote><div><br></div><div>Any update on this patch?</div><div>thanks</div><div></div></div><br clear="all"><br>-- <br><div dir="ltr" class="gmail_signature">Marc-André Lureau<br></div></div>
Daniele Buono Jan. 14, 2021, 7:33 p.m. UTC | #4
On 1/14/2021 3:17 AM, Marc-André Lureau wrote:
> 

> Any update on this patch?

> thanks


Hi,
I had been waiting for a feedback on my previous message.
I don't know the UAS subsystem that well, but can't find where the
variable-sized field that is causing the issue is actually used.

If it helps, I can send an RFC for converting

struct UASStatus {
     uint32_t                  stream;
     uas_iu                    status;
     uint32_t                  length;
     QTAILQ_ENTRY(UASStatus)   next;
};

to

struct UASStatus {
     uint32_t                  stream;
     uas_iu                    *status;
     uint32_t                  length;
     QTAILQ_ENTRY(UASStatus)   next;
};

And discuss it at that point.

Thanks,
Daniele
Philippe Mathieu-Daudé Jan. 18, 2021, 11:38 a.m. UTC | #5
On 11/19/20 5:16 PM, Daniele Buono wrote:
> Hi Philippe,

> 

> On 11/6/2020 9:28 AM, Philippe Mathieu-Daudé wrote:

>> On 11/5/20 11:18 PM, Daniele Buono wrote:

>>> The UASStatus data structure has a variable sized field inside of

>>> type uas_iu,

>>> that however is not placed at the end of the data structure.

>>>

>>> This placement triggers a warning with clang 11, and while not a bug

>>> right now,

>>> (the status is never a uas_iu_command, which is the variable-sized

>>> case),

>>> it could become one in the future.

>>

>> The problem is uas_iu_command::add_cdb, indeed.

>>

>>>

>>> ../qemu-base/hw/usb/dev-uas.c:157:31: error: field 'status' with

>>> variable sized type 'uas_iu' not at the end of a struct or class is a

>>> GNU extension [-Werror,-Wgnu-variable-sized-type-not-at-end]

>>

>> If possible remove the "../qemu-base/" as it does not provide

>> any useful information.

>>

> Sure, will do at the next cycle

>>>      uas_iu                    status;

>>>                                ^

>>> 1 error generated.

>>>

>>> Fix this by moving uas_iu at the end of the struct

>>

>> Your patch silents the warning, but the problem is the same.

>> It would be safer/cleaner to make 'status' a pointer on the heap IMO.

> 

> I'm thinking of moving 'status' in a pointer with the following code

> changes:

> 

> UASStatus is allocated in `usb_uas_alloc_status`, which currently does

> not take a type or size for the union field. I'm thinking of adding

> requested size for the status, like this:

> 

> static UASStatus *usb_uas_alloc_status(UASDevice *uas, uint8_t id,

> uint16_t tag, size_t size);

> 

> and the common call would be

> usb_uas_alloc_status([...],sizeof(uas_iu));

> 

> Also we'd need a double free when the object is freed. Right now

> it's handled in the code when the object is not used anymore with a

> `g_free(st);`.

> I'd have to replace it with

> `g_free(st->status); g_free(st);`. Would you suggest doing it place

> or by adding a usb_uas_dealloc_status() function?

> 

> ---

> 

> However, I am confused by the use of that variable-lenght field.

> I'm looking at what seems the only place where a command is

> parsed, in `usb_uas_handle_data`.

> 

> uas_iu iu;

> [...]

>     switch (p->ep->nr) {

>     case UAS_PIPE_ID_COMMAND:

>         length = MIN(sizeof(iu), p->iov.size);

>         usb_packet_copy(p, &iu, length);

>         [...]

>         break;

> [...]

> 

> It would seem that the copy is limited to at most sizeof(uas_iu),

> so even if we had anything in add_cdb[], that wouldn't be copied

> here?

> 

> Is this intended?


Gerd, do you know?
Gerd Hoffmann Jan. 18, 2021, 4:09 p.m. UTC | #6
Hi,

> > It would seem that the copy is limited to at most sizeof(uas_iu),

> > so even if we had anything in add_cdb[], that wouldn't be copied

> > here?

> > 

> > Is this intended?

> 

> Gerd, do you know?


Don't remember, it's been a few years ago ...

Given that neither add_cdb nor add_cdb_length fields are checked
anywhere in the code it is probably save to just comment out the
add_cdb field.  Should we ever need to look at add_cdb at some
point in the future we can figure some better way deal with it,
in the simplest case just give it a fixed size based on the needs.

take care,
  Gerd
diff mbox series

Patch

diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c
index cec071d96c..5ef3f4fec9 100644
--- a/hw/usb/dev-uas.c
+++ b/hw/usb/dev-uas.c
@@ -154,9 +154,9 @@  struct UASRequest {
 
 struct UASStatus {
     uint32_t                  stream;
-    uas_iu                    status;
     uint32_t                  length;
     QTAILQ_ENTRY(UASStatus)   next;
+    uas_iu                    status;
 };
 
 /* --------------------------------------------------------------------- */