diff mbox series

virtio-net: check the existence of peer before accesing its config

Message ID 20200727074328.2279-1-jasowang@redhat.com
State New
Headers show
Series virtio-net: check the existence of peer before accesing its config | expand

Commit Message

Jason Wang July 27, 2020, 7:43 a.m. UTC
We try to get config from peer unconditionally which may lead NULL
pointer dereference. Add a check before trying to access the config.

Fixes: 108a64818e69b ("vhost-vdpa: introduce vhost-vdpa backend")
Cc: Cindy Lu <lulu@redhat.com>
Tested-by: Cornelia Huck <cohuck@redhat.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
---
 hw/net/virtio-net.c | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

Comments

Cornelia Huck July 27, 2020, 8:44 a.m. UTC | #1
On Mon, 27 Jul 2020 15:43:28 +0800
Jason Wang <jasowang@redhat.com> wrote:

typo in subject: s/accesing/accessing/

> We try to get config from peer unconditionally which may lead NULL

s/lead/lead to a/

> pointer dereference. Add a check before trying to access the config.
> 
> Fixes: 108a64818e69b ("vhost-vdpa: introduce vhost-vdpa backend")
> Cc: Cindy Lu <lulu@redhat.com>
> Tested-by: Cornelia Huck <cohuck@redhat.com>
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
>  hw/net/virtio-net.c | 22 +++++++++++-----------
>  1 file changed, 11 insertions(+), 11 deletions(-)

Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Jason Wang July 27, 2020, 8:51 a.m. UTC | #2
On 2020/7/27 下午4:44, Cornelia Huck wrote:
> On Mon, 27 Jul 2020 15:43:28 +0800
> Jason Wang <jasowang@redhat.com> wrote:
>
> typo in subject: s/accesing/accessing/
>
>> We try to get config from peer unconditionally which may lead NULL
> s/lead/lead to a/
>
>> pointer dereference. Add a check before trying to access the config.
>>
>> Fixes: 108a64818e69b ("vhost-vdpa: introduce vhost-vdpa backend")
>> Cc: Cindy Lu <lulu@redhat.com>
>> Tested-by: Cornelia Huck <cohuck@redhat.com>
>> Signed-off-by: Jason Wang <jasowang@redhat.com>
>> ---
>>   hw/net/virtio-net.c | 22 +++++++++++-----------
>>   1 file changed, 11 insertions(+), 11 deletions(-)
> Reviewed-by: Cornelia Huck <cohuck@redhat.com>


Applied with the above fixed.

Thanks
Michael S. Tsirkin July 27, 2020, 9:41 a.m. UTC | #3
On Mon, Jul 27, 2020 at 03:43:28PM +0800, Jason Wang wrote:
> We try to get config from peer unconditionally which may lead NULL
> pointer dereference. Add a check before trying to access the config.
> 
> Fixes: 108a64818e69b ("vhost-vdpa: introduce vhost-vdpa backend")
> Cc: Cindy Lu <lulu@redhat.com>
> Tested-by: Cornelia Huck <cohuck@redhat.com>
> Signed-off-by: Jason Wang <jasowang@redhat.com>

I am a bit lost here. Isn't this invoked
when guest attempts to read the config?
With no peer, what do we return to guest?
A code comment might be helpful here.

> ---
>  hw/net/virtio-net.c | 22 +++++++++++-----------
>  1 file changed, 11 insertions(+), 11 deletions(-)
> 
> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
> index 4895af1cbe..935b9ef5c7 100644
> --- a/hw/net/virtio-net.c
> +++ b/hw/net/virtio-net.c
> @@ -125,6 +125,7 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config)
>  {
>      VirtIONet *n = VIRTIO_NET(vdev);
>      struct virtio_net_config netcfg;
> +    NetClientState *nc = qemu_get_queue(n->nic);
>  
>      int ret = 0;
>      memset(&netcfg, 0 , sizeof(struct virtio_net_config));
> @@ -142,13 +143,12 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config)
>                   VIRTIO_NET_RSS_SUPPORTED_HASHES);
>      memcpy(config, &netcfg, n->config_size);
>  
> -    NetClientState *nc = qemu_get_queue(n->nic);
> -    if (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
> +    if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
>          ret = vhost_net_get_config(get_vhost_net(nc->peer), (uint8_t *)&netcfg,
> -                             n->config_size);
> -    if (ret != -1) {
> -        memcpy(config, &netcfg, n->config_size);
> -    }
> +                                   n->config_size);
> +        if (ret != -1) {
> +            memcpy(config, &netcfg, n->config_size);
> +        }
>      }
>  }
>  
> @@ -156,6 +156,7 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
>  {
>      VirtIONet *n = VIRTIO_NET(vdev);
>      struct virtio_net_config netcfg = {};
> +    NetClientState *nc = qemu_get_queue(n->nic);
>  
>      memcpy(&netcfg, config, n->config_size);
>  
> @@ -166,11 +167,10 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
>          qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac);
>      }
>  
> -    NetClientState *nc = qemu_get_queue(n->nic);
> -    if (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
> -        vhost_net_set_config(get_vhost_net(nc->peer), (uint8_t *)&netcfg,
> -                               0, n->config_size,
> -                        VHOST_SET_CONFIG_TYPE_MASTER);
> +    if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
> +        vhost_net_set_config(get_vhost_net(nc->peer),
> +                             (uint8_t *)&netcfg, 0, n->config_size,
> +                             VHOST_SET_CONFIG_TYPE_MASTER);
>        }
>  }
>  
> -- 
> 2.20.1
Jason Wang July 27, 2020, 9:49 a.m. UTC | #4
On 2020/7/27 下午5:41, Michael S. Tsirkin wrote:
> On Mon, Jul 27, 2020 at 03:43:28PM +0800, Jason Wang wrote:
>> We try to get config from peer unconditionally which may lead NULL
>> pointer dereference. Add a check before trying to access the config.
>>
>> Fixes: 108a64818e69b ("vhost-vdpa: introduce vhost-vdpa backend")
>> Cc: Cindy Lu <lulu@redhat.com>
>> Tested-by: Cornelia Huck <cohuck@redhat.com>
>> Signed-off-by: Jason Wang <jasowang@redhat.com>
> I am a bit lost here. Isn't this invoked
> when guest attempts to read the config?
> With no peer, what do we return to guest?


With no peer, it just work as in the past (read from the qemu's own 
emulated config space). With a vDPA as its peer, it tries to read it 
from vhost-vDPA.


> A code comment might be helpful here.


Does something like above help?

Thanks


>
>> ---
>>   hw/net/virtio-net.c | 22 +++++++++++-----------
>>   1 file changed, 11 insertions(+), 11 deletions(-)
>>
>> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
>> index 4895af1cbe..935b9ef5c7 100644
>> --- a/hw/net/virtio-net.c
>> +++ b/hw/net/virtio-net.c
>> @@ -125,6 +125,7 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config)
>>   {
>>       VirtIONet *n = VIRTIO_NET(vdev);
>>       struct virtio_net_config netcfg;
>> +    NetClientState *nc = qemu_get_queue(n->nic);
>>   
>>       int ret = 0;
>>       memset(&netcfg, 0 , sizeof(struct virtio_net_config));
>> @@ -142,13 +143,12 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config)
>>                    VIRTIO_NET_RSS_SUPPORTED_HASHES);
>>       memcpy(config, &netcfg, n->config_size);
>>   
>> -    NetClientState *nc = qemu_get_queue(n->nic);
>> -    if (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
>> +    if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
>>           ret = vhost_net_get_config(get_vhost_net(nc->peer), (uint8_t *)&netcfg,
>> -                             n->config_size);
>> -    if (ret != -1) {
>> -        memcpy(config, &netcfg, n->config_size);
>> -    }
>> +                                   n->config_size);
>> +        if (ret != -1) {
>> +            memcpy(config, &netcfg, n->config_size);
>> +        }
>>       }
>>   }
>>   
>> @@ -156,6 +156,7 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
>>   {
>>       VirtIONet *n = VIRTIO_NET(vdev);
>>       struct virtio_net_config netcfg = {};
>> +    NetClientState *nc = qemu_get_queue(n->nic);
>>   
>>       memcpy(&netcfg, config, n->config_size);
>>   
>> @@ -166,11 +167,10 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
>>           qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac);
>>       }
>>   
>> -    NetClientState *nc = qemu_get_queue(n->nic);
>> -    if (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
>> -        vhost_net_set_config(get_vhost_net(nc->peer), (uint8_t *)&netcfg,
>> -                               0, n->config_size,
>> -                        VHOST_SET_CONFIG_TYPE_MASTER);
>> +    if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
>> +        vhost_net_set_config(get_vhost_net(nc->peer),
>> +                             (uint8_t *)&netcfg, 0, n->config_size,
>> +                             VHOST_SET_CONFIG_TYPE_MASTER);
>>         }
>>   }
>>   
>> -- 
>> 2.20.1
Cornelia Huck July 27, 2020, 9:53 a.m. UTC | #5
On Mon, 27 Jul 2020 05:41:17 -0400
"Michael S. Tsirkin" <mst@redhat.com> wrote:

> On Mon, Jul 27, 2020 at 03:43:28PM +0800, Jason Wang wrote:
> > We try to get config from peer unconditionally which may lead NULL
> > pointer dereference. Add a check before trying to access the config.
> > 
> > Fixes: 108a64818e69b ("vhost-vdpa: introduce vhost-vdpa backend")
> > Cc: Cindy Lu <lulu@redhat.com>
> > Tested-by: Cornelia Huck <cohuck@redhat.com>
> > Signed-off-by: Jason Wang <jasowang@redhat.com>  
> 
> I am a bit lost here. Isn't this invoked
> when guest attempts to read the config?
> With no peer, what do we return to guest?

Same as with a non-vdpa peer? It's the dereference that needs to be
guarded.

> A code comment might be helpful here.
> 
> > ---
> >  hw/net/virtio-net.c | 22 +++++++++++-----------
> >  1 file changed, 11 insertions(+), 11 deletions(-)
Michael S. Tsirkin July 27, 2020, 10:13 a.m. UTC | #6
On Mon, Jul 27, 2020 at 11:53:22AM +0200, Cornelia Huck wrote:
> On Mon, 27 Jul 2020 05:41:17 -0400
> "Michael S. Tsirkin" <mst@redhat.com> wrote:
> 
> > On Mon, Jul 27, 2020 at 03:43:28PM +0800, Jason Wang wrote:
> > > We try to get config from peer unconditionally which may lead NULL
> > > pointer dereference. Add a check before trying to access the config.
> > > 
> > > Fixes: 108a64818e69b ("vhost-vdpa: introduce vhost-vdpa backend")
> > > Cc: Cindy Lu <lulu@redhat.com>
> > > Tested-by: Cornelia Huck <cohuck@redhat.com>
> > > Signed-off-by: Jason Wang <jasowang@redhat.com>  
> > 
> > I am a bit lost here. Isn't this invoked
> > when guest attempts to read the config?
> > With no peer, what do we return to guest?
> 
> Same as with a non-vdpa peer? It's the dereference that needs to be
> guarded.

So vdpa has a GET_CONFIG ioctl which to me hints that a peer needs to be
notified on get config calls.
If we return config from qemu memory here, then I guess we
need to call GET_CONFIG on connect and validate it -
does this make sense?

Cindy, Jason?

> > A code comment might be helpful here.
> > 
> > > ---
> > >  hw/net/virtio-net.c | 22 +++++++++++-----------
> > >  1 file changed, 11 insertions(+), 11 deletions(-)
Michael S. Tsirkin July 27, 2020, 10:17 a.m. UTC | #7
On Mon, Jul 27, 2020 at 05:49:47PM +0800, Jason Wang wrote:
> 
> On 2020/7/27 下午5:41, Michael S. Tsirkin wrote:
> > On Mon, Jul 27, 2020 at 03:43:28PM +0800, Jason Wang wrote:
> > > We try to get config from peer unconditionally which may lead NULL
> > > pointer dereference. Add a check before trying to access the config.
> > > 
> > > Fixes: 108a64818e69b ("vhost-vdpa: introduce vhost-vdpa backend")
> > > Cc: Cindy Lu <lulu@redhat.com>
> > > Tested-by: Cornelia Huck <cohuck@redhat.com>
> > > Signed-off-by: Jason Wang <jasowang@redhat.com>
> > I am a bit lost here. Isn't this invoked
> > when guest attempts to read the config?
> > With no peer, what do we return to guest?
> 
> 
> With no peer, it just work as in the past (read from the qemu's own emulated
> config space). With a vDPA as its peer, it tries to read it from vhost-vDPA.

Are these scenarios where guest would sometimes get one and
sometimes another? E.g. does it happen on disconnect?
If yes that might become a problem ...

> 
> > A code comment might be helpful here.
> 
> 
> Does something like above help?
> 
> Thanks
> 
> 
> > 
> > > ---
> > >   hw/net/virtio-net.c | 22 +++++++++++-----------
> > >   1 file changed, 11 insertions(+), 11 deletions(-)
> > > 
> > > diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
> > > index 4895af1cbe..935b9ef5c7 100644
> > > --- a/hw/net/virtio-net.c
> > > +++ b/hw/net/virtio-net.c
> > > @@ -125,6 +125,7 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config)
> > >   {
> > >       VirtIONet *n = VIRTIO_NET(vdev);
> > >       struct virtio_net_config netcfg;
> > > +    NetClientState *nc = qemu_get_queue(n->nic);
> > >       int ret = 0;
> > >       memset(&netcfg, 0 , sizeof(struct virtio_net_config));
> > > @@ -142,13 +143,12 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config)
> > >                    VIRTIO_NET_RSS_SUPPORTED_HASHES);
> > >       memcpy(config, &netcfg, n->config_size);
> > > -    NetClientState *nc = qemu_get_queue(n->nic);
> > > -    if (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
> > > +    if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
> > >           ret = vhost_net_get_config(get_vhost_net(nc->peer), (uint8_t *)&netcfg,
> > > -                             n->config_size);
> > > -    if (ret != -1) {
> > > -        memcpy(config, &netcfg, n->config_size);
> > > -    }
> > > +                                   n->config_size);
> > > +        if (ret != -1) {
> > > +            memcpy(config, &netcfg, n->config_size);
> > > +        }
> > >       }
> > >   }
> > > @@ -156,6 +156,7 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
> > >   {
> > >       VirtIONet *n = VIRTIO_NET(vdev);
> > >       struct virtio_net_config netcfg = {};
> > > +    NetClientState *nc = qemu_get_queue(n->nic);
> > >       memcpy(&netcfg, config, n->config_size);
> > > @@ -166,11 +167,10 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
> > >           qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac);
> > >       }
> > > -    NetClientState *nc = qemu_get_queue(n->nic);
> > > -    if (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
> > > -        vhost_net_set_config(get_vhost_net(nc->peer), (uint8_t *)&netcfg,
> > > -                               0, n->config_size,
> > > -                        VHOST_SET_CONFIG_TYPE_MASTER);
> > > +    if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
> > > +        vhost_net_set_config(get_vhost_net(nc->peer),
> > > +                             (uint8_t *)&netcfg, 0, n->config_size,
> > > +                             VHOST_SET_CONFIG_TYPE_MASTER);
> > >         }
> > >   }
> > > -- 
> > > 2.20.1
Michael S. Tsirkin July 27, 2020, 10:21 a.m. UTC | #8
On Mon, Jul 27, 2020 at 05:49:47PM +0800, Jason Wang wrote:
> 
> On 2020/7/27 下午5:41, Michael S. Tsirkin wrote:
> > On Mon, Jul 27, 2020 at 03:43:28PM +0800, Jason Wang wrote:
> > > We try to get config from peer unconditionally which may lead NULL
> > > pointer dereference. Add a check before trying to access the config.
> > > 
> > > Fixes: 108a64818e69b ("vhost-vdpa: introduce vhost-vdpa backend")
> > > Cc: Cindy Lu <lulu@redhat.com>
> > > Tested-by: Cornelia Huck <cohuck@redhat.com>
> > > Signed-off-by: Jason Wang <jasowang@redhat.com>
> > I am a bit lost here. Isn't this invoked
> > when guest attempts to read the config?
> > With no peer, what do we return to guest?
> 
> 
> With no peer, it just work as in the past (read from the qemu's own emulated
> config space). With a vDPA as its peer, it tries to read it from vhost-vDPA.
> 
> 
> > A code comment might be helpful here.
> 
> 
> Does something like above help?
> 
> Thanks

I think this part of commit log caused confusion:

	 Add a check before trying to access the config.

looking more at the code, imho in fact here is a better description of
what is going on:

	We try to check whether a peer is VDPA in order to get config from
	there - with no peer, this leads to a NULL
	pointer dereference. Add a check before trying to access the peer
	type. No peer means not VDPA.


> 
> > 
> > > ---
> > >   hw/net/virtio-net.c | 22 +++++++++++-----------
> > >   1 file changed, 11 insertions(+), 11 deletions(-)
> > > 
> > > diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
> > > index 4895af1cbe..935b9ef5c7 100644
> > > --- a/hw/net/virtio-net.c
> > > +++ b/hw/net/virtio-net.c
> > > @@ -125,6 +125,7 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config)
> > >   {
> > >       VirtIONet *n = VIRTIO_NET(vdev);
> > >       struct virtio_net_config netcfg;
> > > +    NetClientState *nc = qemu_get_queue(n->nic);
> > >       int ret = 0;
> > >       memset(&netcfg, 0 , sizeof(struct virtio_net_config));
> > > @@ -142,13 +143,12 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config)
> > >                    VIRTIO_NET_RSS_SUPPORTED_HASHES);
> > >       memcpy(config, &netcfg, n->config_size);
> > > -    NetClientState *nc = qemu_get_queue(n->nic);
> > > -    if (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
> > > +    if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
> > >           ret = vhost_net_get_config(get_vhost_net(nc->peer), (uint8_t *)&netcfg,
> > > -                             n->config_size);
> > > -    if (ret != -1) {
> > > -        memcpy(config, &netcfg, n->config_size);
> > > -    }
> > > +                                   n->config_size);
> > > +        if (ret != -1) {
> > > +            memcpy(config, &netcfg, n->config_size);
> > > +        }
> > >       }
> > >   }
> > > @@ -156,6 +156,7 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
> > >   {
> > >       VirtIONet *n = VIRTIO_NET(vdev);
> > >       struct virtio_net_config netcfg = {};
> > > +    NetClientState *nc = qemu_get_queue(n->nic);
> > >       memcpy(&netcfg, config, n->config_size);
> > > @@ -166,11 +167,10 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
> > >           qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac);
> > >       }
> > > -    NetClientState *nc = qemu_get_queue(n->nic);
> > > -    if (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
> > > -        vhost_net_set_config(get_vhost_net(nc->peer), (uint8_t *)&netcfg,
> > > -                               0, n->config_size,
> > > -                        VHOST_SET_CONFIG_TYPE_MASTER);
> > > +    if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
> > > +        vhost_net_set_config(get_vhost_net(nc->peer),
> > > +                             (uint8_t *)&netcfg, 0, n->config_size,
> > > +                             VHOST_SET_CONFIG_TYPE_MASTER);
> > >         }
> > >   }
> > > -- 
> > > 2.20.1
Jason Wang July 27, 2020, 10:22 a.m. UTC | #9
On 2020/7/27 下午6:17, Michael S. Tsirkin wrote:
> On Mon, Jul 27, 2020 at 05:49:47PM +0800, Jason Wang wrote:
>> On 2020/7/27 下午5:41, Michael S. Tsirkin wrote:
>>> On Mon, Jul 27, 2020 at 03:43:28PM +0800, Jason Wang wrote:
>>>> We try to get config from peer unconditionally which may lead NULL
>>>> pointer dereference. Add a check before trying to access the config.
>>>>
>>>> Fixes: 108a64818e69b ("vhost-vdpa: introduce vhost-vdpa backend")
>>>> Cc: Cindy Lu <lulu@redhat.com>
>>>> Tested-by: Cornelia Huck <cohuck@redhat.com>
>>>> Signed-off-by: Jason Wang <jasowang@redhat.com>
>>> I am a bit lost here. Isn't this invoked
>>> when guest attempts to read the config?
>>> With no peer, what do we return to guest?
>>
>> With no peer, it just work as in the past (read from the qemu's own emulated
>> config space). With a vDPA as its peer, it tries to read it from vhost-vDPA.
> Are these scenarios where guest would sometimes get one and
> sometimes another? E.g. does it happen on disconnect?
> If yes that might become a problem ...


For disconnecting yes, but I wonder if we need to care about that case 
anyway.

Thanks


>
>>> A code comment might be helpful here.
>>
>> Does something like above help?
>>
>> Thanks
>>
>>
>>>> ---
>>>>    hw/net/virtio-net.c | 22 +++++++++++-----------
>>>>    1 file changed, 11 insertions(+), 11 deletions(-)
>>>>
>>>> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
>>>> index 4895af1cbe..935b9ef5c7 100644
>>>> --- a/hw/net/virtio-net.c
>>>> +++ b/hw/net/virtio-net.c
>>>> @@ -125,6 +125,7 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config)
>>>>    {
>>>>        VirtIONet *n = VIRTIO_NET(vdev);
>>>>        struct virtio_net_config netcfg;
>>>> +    NetClientState *nc = qemu_get_queue(n->nic);
>>>>        int ret = 0;
>>>>        memset(&netcfg, 0 , sizeof(struct virtio_net_config));
>>>> @@ -142,13 +143,12 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config)
>>>>                     VIRTIO_NET_RSS_SUPPORTED_HASHES);
>>>>        memcpy(config, &netcfg, n->config_size);
>>>> -    NetClientState *nc = qemu_get_queue(n->nic);
>>>> -    if (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
>>>> +    if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
>>>>            ret = vhost_net_get_config(get_vhost_net(nc->peer), (uint8_t *)&netcfg,
>>>> -                             n->config_size);
>>>> -    if (ret != -1) {
>>>> -        memcpy(config, &netcfg, n->config_size);
>>>> -    }
>>>> +                                   n->config_size);
>>>> +        if (ret != -1) {
>>>> +            memcpy(config, &netcfg, n->config_size);
>>>> +        }
>>>>        }
>>>>    }
>>>> @@ -156,6 +156,7 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
>>>>    {
>>>>        VirtIONet *n = VIRTIO_NET(vdev);
>>>>        struct virtio_net_config netcfg = {};
>>>> +    NetClientState *nc = qemu_get_queue(n->nic);
>>>>        memcpy(&netcfg, config, n->config_size);
>>>> @@ -166,11 +167,10 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
>>>>            qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac);
>>>>        }
>>>> -    NetClientState *nc = qemu_get_queue(n->nic);
>>>> -    if (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
>>>> -        vhost_net_set_config(get_vhost_net(nc->peer), (uint8_t *)&netcfg,
>>>> -                               0, n->config_size,
>>>> -                        VHOST_SET_CONFIG_TYPE_MASTER);
>>>> +    if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
>>>> +        vhost_net_set_config(get_vhost_net(nc->peer),
>>>> +                             (uint8_t *)&netcfg, 0, n->config_size,
>>>> +                             VHOST_SET_CONFIG_TYPE_MASTER);
>>>>          }
>>>>    }
>>>> -- 
>>>> 2.20.1
Jason Wang July 27, 2020, 10:23 a.m. UTC | #10
On 2020/7/27 下午6:21, Michael S. Tsirkin wrote:
> On Mon, Jul 27, 2020 at 05:49:47PM +0800, Jason Wang wrote:
>> On 2020/7/27 下午5:41, Michael S. Tsirkin wrote:
>>> On Mon, Jul 27, 2020 at 03:43:28PM +0800, Jason Wang wrote:
>>>> We try to get config from peer unconditionally which may lead NULL
>>>> pointer dereference. Add a check before trying to access the config.
>>>>
>>>> Fixes: 108a64818e69b ("vhost-vdpa: introduce vhost-vdpa backend")
>>>> Cc: Cindy Lu <lulu@redhat.com>
>>>> Tested-by: Cornelia Huck <cohuck@redhat.com>
>>>> Signed-off-by: Jason Wang <jasowang@redhat.com>
>>> I am a bit lost here. Isn't this invoked
>>> when guest attempts to read the config?
>>> With no peer, what do we return to guest?
>>
>> With no peer, it just work as in the past (read from the qemu's own emulated
>> config space). With a vDPA as its peer, it tries to read it from vhost-vDPA.
>>
>>
>>> A code comment might be helpful here.
>>
>> Does something like above help?
>>
>> Thanks
> I think this part of commit log caused confusion:
>
> 	 Add a check before trying to access the config.
>
> looking more at the code, imho in fact here is a better description of
> what is going on:
>
> 	We try to check whether a peer is VDPA in order to get config from
> 	there - with no peer, this leads to a NULL
> 	pointer dereference. Add a check before trying to access the peer
> 	type. No peer means not VDPA.


Yes, this looks much better.

Thanks


>
>
>>>> ---
>>>>    hw/net/virtio-net.c | 22 +++++++++++-----------
>>>>    1 file changed, 11 insertions(+), 11 deletions(-)
>>>>
>>>> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
>>>> index 4895af1cbe..935b9ef5c7 100644
>>>> --- a/hw/net/virtio-net.c
>>>> +++ b/hw/net/virtio-net.c
>>>> @@ -125,6 +125,7 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config)
>>>>    {
>>>>        VirtIONet *n = VIRTIO_NET(vdev);
>>>>        struct virtio_net_config netcfg;
>>>> +    NetClientState *nc = qemu_get_queue(n->nic);
>>>>        int ret = 0;
>>>>        memset(&netcfg, 0 , sizeof(struct virtio_net_config));
>>>> @@ -142,13 +143,12 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config)
>>>>                     VIRTIO_NET_RSS_SUPPORTED_HASHES);
>>>>        memcpy(config, &netcfg, n->config_size);
>>>> -    NetClientState *nc = qemu_get_queue(n->nic);
>>>> -    if (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
>>>> +    if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
>>>>            ret = vhost_net_get_config(get_vhost_net(nc->peer), (uint8_t *)&netcfg,
>>>> -                             n->config_size);
>>>> -    if (ret != -1) {
>>>> -        memcpy(config, &netcfg, n->config_size);
>>>> -    }
>>>> +                                   n->config_size);
>>>> +        if (ret != -1) {
>>>> +            memcpy(config, &netcfg, n->config_size);
>>>> +        }
>>>>        }
>>>>    }
>>>> @@ -156,6 +156,7 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
>>>>    {
>>>>        VirtIONet *n = VIRTIO_NET(vdev);
>>>>        struct virtio_net_config netcfg = {};
>>>> +    NetClientState *nc = qemu_get_queue(n->nic);
>>>>        memcpy(&netcfg, config, n->config_size);
>>>> @@ -166,11 +167,10 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
>>>>            qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac);
>>>>        }
>>>> -    NetClientState *nc = qemu_get_queue(n->nic);
>>>> -    if (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
>>>> -        vhost_net_set_config(get_vhost_net(nc->peer), (uint8_t *)&netcfg,
>>>> -                               0, n->config_size,
>>>> -                        VHOST_SET_CONFIG_TYPE_MASTER);
>>>> +    if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
>>>> +        vhost_net_set_config(get_vhost_net(nc->peer),
>>>> +                             (uint8_t *)&netcfg, 0, n->config_size,
>>>> +                             VHOST_SET_CONFIG_TYPE_MASTER);
>>>>          }
>>>>    }
>>>> -- 
>>>> 2.20.1
Jason Wang July 27, 2020, 10:26 a.m. UTC | #11
On 2020/7/27 下午6:13, Michael S. Tsirkin wrote:
> On Mon, Jul 27, 2020 at 11:53:22AM +0200, Cornelia Huck wrote:
>> On Mon, 27 Jul 2020 05:41:17 -0400
>> "Michael S. Tsirkin" <mst@redhat.com> wrote:
>>
>>> On Mon, Jul 27, 2020 at 03:43:28PM +0800, Jason Wang wrote:
>>>> We try to get config from peer unconditionally which may lead NULL
>>>> pointer dereference. Add a check before trying to access the config.
>>>>
>>>> Fixes: 108a64818e69b ("vhost-vdpa: introduce vhost-vdpa backend")
>>>> Cc: Cindy Lu <lulu@redhat.com>
>>>> Tested-by: Cornelia Huck <cohuck@redhat.com>
>>>> Signed-off-by: Jason Wang <jasowang@redhat.com>
>>> I am a bit lost here. Isn't this invoked
>>> when guest attempts to read the config?
>>> With no peer, what do we return to guest?
>> Same as with a non-vdpa peer? It's the dereference that needs to be
>> guarded.
> So vdpa has a GET_CONFIG ioctl which to me hints that a peer needs to be
> notified on get config calls.
> If we return config from qemu memory here, then I guess we
> need to call GET_CONFIG on connect and validate it -
> does this make sense?
>
> Cindy, Jason?


For "connect" you meant connecting virtio-net to its peer (vDPA)? AFAIK, 
if we start with no peer, there's no way to set a peer afterwards.

Thanks


>
>>> A code comment might be helpful here.
>>>
>>>> ---
>>>>   hw/net/virtio-net.c | 22 +++++++++++-----------
>>>>   1 file changed, 11 insertions(+), 11 deletions(-)
Michael S. Tsirkin July 27, 2020, 11:41 a.m. UTC | #12
On Mon, Jul 27, 2020 at 06:26:37PM +0800, Jason Wang wrote:
> 
> On 2020/7/27 下午6:13, Michael S. Tsirkin wrote:
> > On Mon, Jul 27, 2020 at 11:53:22AM +0200, Cornelia Huck wrote:
> > > On Mon, 27 Jul 2020 05:41:17 -0400
> > > "Michael S. Tsirkin" <mst@redhat.com> wrote:
> > > 
> > > > On Mon, Jul 27, 2020 at 03:43:28PM +0800, Jason Wang wrote:
> > > > > We try to get config from peer unconditionally which may lead NULL
> > > > > pointer dereference. Add a check before trying to access the config.
> > > > > 
> > > > > Fixes: 108a64818e69b ("vhost-vdpa: introduce vhost-vdpa backend")
> > > > > Cc: Cindy Lu <lulu@redhat.com>
> > > > > Tested-by: Cornelia Huck <cohuck@redhat.com>
> > > > > Signed-off-by: Jason Wang <jasowang@redhat.com>
> > > > I am a bit lost here. Isn't this invoked
> > > > when guest attempts to read the config?
> > > > With no peer, what do we return to guest?
> > > Same as with a non-vdpa peer? It's the dereference that needs to be
> > > guarded.
> > So vdpa has a GET_CONFIG ioctl which to me hints that a peer needs to be
> > notified on get config calls.
> > If we return config from qemu memory here, then I guess we
> > need to call GET_CONFIG on connect and validate it -
> > does this make sense?
> > 
> > Cindy, Jason?
> 
> 
> For "connect" you meant connecting virtio-net to its peer (vDPA)? AFAIK, if
> we start with no peer, there's no way to set a peer afterwards.
> 
> Thanks


That would be a good sentence to add in a code comment:

/*
 * Is this VDPA? No peer means not VDPA: there's no way to
 * disconnect/reconnect a VDPA peer.
 */

> 
> > 
> > > > A code comment might be helpful here.
> > > > 
> > > > > ---
> > > > >   hw/net/virtio-net.c | 22 +++++++++++-----------
> > > > >   1 file changed, 11 insertions(+), 11 deletions(-)
Jason Wang July 27, 2020, 12:44 p.m. UTC | #13
On 2020/7/27 下午7:41, Michael S. Tsirkin wrote:
> On Mon, Jul 27, 2020 at 06:26:37PM +0800, Jason Wang wrote:
>> On 2020/7/27 下午6:13, Michael S. Tsirkin wrote:
>>> On Mon, Jul 27, 2020 at 11:53:22AM +0200, Cornelia Huck wrote:
>>>> On Mon, 27 Jul 2020 05:41:17 -0400
>>>> "Michael S. Tsirkin" <mst@redhat.com> wrote:
>>>>
>>>>> On Mon, Jul 27, 2020 at 03:43:28PM +0800, Jason Wang wrote:
>>>>>> We try to get config from peer unconditionally which may lead NULL
>>>>>> pointer dereference. Add a check before trying to access the config.
>>>>>>
>>>>>> Fixes: 108a64818e69b ("vhost-vdpa: introduce vhost-vdpa backend")
>>>>>> Cc: Cindy Lu <lulu@redhat.com>
>>>>>> Tested-by: Cornelia Huck <cohuck@redhat.com>
>>>>>> Signed-off-by: Jason Wang <jasowang@redhat.com>
>>>>> I am a bit lost here. Isn't this invoked
>>>>> when guest attempts to read the config?
>>>>> With no peer, what do we return to guest?
>>>> Same as with a non-vdpa peer? It's the dereference that needs to be
>>>> guarded.
>>> So vdpa has a GET_CONFIG ioctl which to me hints that a peer needs to be
>>> notified on get config calls.
>>> If we return config from qemu memory here, then I guess we
>>> need to call GET_CONFIG on connect and validate it -
>>> does this make sense?
>>>
>>> Cindy, Jason?
>>
>> For "connect" you meant connecting virtio-net to its peer (vDPA)? AFAIK, if
>> we start with no peer, there's no way to set a peer afterwards.
>>
>> Thanks
>
> That would be a good sentence to add in a code comment:
>
> /*
>   * Is this VDPA? No peer means not VDPA: there's no way to
>   * disconnect/reconnect a VDPA peer.
>   */


Sure.

Thanks


>
>>>>> A code comment might be helpful here.
>>>>>
>>>>>> ---
>>>>>>    hw/net/virtio-net.c | 22 +++++++++++-----------
>>>>>>    1 file changed, 11 insertions(+), 11 deletions(-)
diff mbox series

Patch

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 4895af1cbe..935b9ef5c7 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -125,6 +125,7 @@  static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config)
 {
     VirtIONet *n = VIRTIO_NET(vdev);
     struct virtio_net_config netcfg;
+    NetClientState *nc = qemu_get_queue(n->nic);
 
     int ret = 0;
     memset(&netcfg, 0 , sizeof(struct virtio_net_config));
@@ -142,13 +143,12 @@  static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config)
                  VIRTIO_NET_RSS_SUPPORTED_HASHES);
     memcpy(config, &netcfg, n->config_size);
 
-    NetClientState *nc = qemu_get_queue(n->nic);
-    if (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
+    if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
         ret = vhost_net_get_config(get_vhost_net(nc->peer), (uint8_t *)&netcfg,
-                             n->config_size);
-    if (ret != -1) {
-        memcpy(config, &netcfg, n->config_size);
-    }
+                                   n->config_size);
+        if (ret != -1) {
+            memcpy(config, &netcfg, n->config_size);
+        }
     }
 }
 
@@ -156,6 +156,7 @@  static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
 {
     VirtIONet *n = VIRTIO_NET(vdev);
     struct virtio_net_config netcfg = {};
+    NetClientState *nc = qemu_get_queue(n->nic);
 
     memcpy(&netcfg, config, n->config_size);
 
@@ -166,11 +167,10 @@  static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
         qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac);
     }
 
-    NetClientState *nc = qemu_get_queue(n->nic);
-    if (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
-        vhost_net_set_config(get_vhost_net(nc->peer), (uint8_t *)&netcfg,
-                               0, n->config_size,
-                        VHOST_SET_CONFIG_TYPE_MASTER);
+    if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
+        vhost_net_set_config(get_vhost_net(nc->peer),
+                             (uint8_t *)&netcfg, 0, n->config_size,
+                             VHOST_SET_CONFIG_TYPE_MASTER);
       }
 }