diff mbox series

virtio-net: Add validation for used length

Message ID 20210525045838.1137-1-xieyongji@bytedance.com
State New
Headers show
Series virtio-net: Add validation for used length | expand

Commit Message

Yongji Xie May 25, 2021, 4:58 a.m. UTC
This adds validation for used length (might come
from an untrusted device) to avoid data corruption
or loss.

Signed-off-by: Xie Yongji <xieyongji@bytedance.com>
---
 drivers/net/virtio_net.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

Comments

Jason Wang May 25, 2021, 6:30 a.m. UTC | #1
在 2021/5/25 下午12:58, Xie Yongji 写道:
> This adds validation for used length (might come
> from an untrusted device) to avoid data corruption
> or loss.
>
> Signed-off-by: Xie Yongji <xieyongji@bytedance.com>
> ---
>   drivers/net/virtio_net.c | 22 ++++++++++++++++++++++
>   1 file changed, 22 insertions(+)
>
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index c4711e23af88..2dcdc1a3c7e8 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -668,6 +668,13 @@ static struct sk_buff *receive_small(struct net_device *dev,
>   		void *orig_data;
>   		u32 act;
>   
> +		if (unlikely(len > GOOD_PACKET_LEN)) {
> +			pr_debug("%s: rx error: len %u exceeds max size %lu\n",
> +				 dev->name, len, GOOD_PACKET_LEN);
> +			dev->stats.rx_length_errors++;
> +			goto err_xdp;
> +		}


Need to count vi->hdr_len here?


> +
>   		if (unlikely(hdr->hdr.gso_type))
>   			goto err_xdp;
>   
> @@ -739,6 +746,14 @@ static struct sk_buff *receive_small(struct net_device *dev,
>   	}
>   	rcu_read_unlock();
>   
> +	if (unlikely(len > GOOD_PACKET_LEN)) {
> +		pr_debug("%s: rx error: len %u exceeds max size %lu\n",
> +			 dev->name, len, GOOD_PACKET_LEN);
> +		dev->stats.rx_length_errors++;
> +		put_page(page);
> +		return NULL;
> +	}
> +
>   	skb = build_skb(buf, buflen);
>   	if (!skb) {
>   		put_page(page);
> @@ -822,6 +837,13 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
>   		void *data;
>   		u32 act;
>   
> +		if (unlikely(len > truesize)) {
> +			pr_debug("%s: rx error: len %u exceeds truesize %lu\n",
> +				 dev->name, len, (unsigned long)ctx);
> +			dev->stats.rx_length_errors++;
> +			goto err_xdp;
> +		}


There's a similar check after the XDP, let's simply move it here?

And do we need similar check in receive_big()?

Thanks


> +
>   		/* Transient failure which in theory could occur if
>   		 * in-flight packets from before XDP was enabled reach
>   		 * the receive path after XDP is loaded.
Jason Wang May 26, 2021, 7:52 a.m. UTC | #2
在 2021/5/25 下午4:45, Yongji Xie 写道:
> On Tue, May 25, 2021 at 2:30 PM Jason Wang <jasowang@redhat.com> wrote:

>>

>> 在 2021/5/25 下午12:58, Xie Yongji 写道:

>>> This adds validation for used length (might come

>>> from an untrusted device) to avoid data corruption

>>> or loss.

>>>

>>> Signed-off-by: Xie Yongji <xieyongji@bytedance.com>

>>> ---

>>>    drivers/net/virtio_net.c | 22 ++++++++++++++++++++++

>>>    1 file changed, 22 insertions(+)

>>>

>>> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c

>>> index c4711e23af88..2dcdc1a3c7e8 100644

>>> --- a/drivers/net/virtio_net.c

>>> +++ b/drivers/net/virtio_net.c

>>> @@ -668,6 +668,13 @@ static struct sk_buff *receive_small(struct net_device *dev,

>>>                void *orig_data;

>>>                u32 act;

>>>

>>> +             if (unlikely(len > GOOD_PACKET_LEN)) {

>>> +                     pr_debug("%s: rx error: len %u exceeds max size %lu\n",

>>> +                              dev->name, len, GOOD_PACKET_LEN);

>>> +                     dev->stats.rx_length_errors++;

>>> +                     goto err_xdp;

>>> +             }

>>

>> Need to count vi->hdr_len here?

>>

> We did len -= vi->hdr_len before.



Right.


>

>>> +

>>>                if (unlikely(hdr->hdr.gso_type))

>>>                        goto err_xdp;

>>>

>>> @@ -739,6 +746,14 @@ static struct sk_buff *receive_small(struct net_device *dev,

>>>        }

>>>        rcu_read_unlock();

>>>

>>> +     if (unlikely(len > GOOD_PACKET_LEN)) {

>>> +             pr_debug("%s: rx error: len %u exceeds max size %lu\n",

>>> +                      dev->name, len, GOOD_PACKET_LEN);

>>> +             dev->stats.rx_length_errors++;

>>> +             put_page(page);

>>> +             return NULL;

>>> +     }

>>> +

>>>        skb = build_skb(buf, buflen);

>>>        if (!skb) {

>>>                put_page(page);

>>> @@ -822,6 +837,13 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,

>>>                void *data;

>>>                u32 act;

>>>

>>> +             if (unlikely(len > truesize)) {

>>> +                     pr_debug("%s: rx error: len %u exceeds truesize %lu\n",

>>> +                              dev->name, len, (unsigned long)ctx);

>>> +                     dev->stats.rx_length_errors++;

>>> +                     goto err_xdp;

>>> +             }

>>

>> There's a similar check after the XDP, let's simply move it here?

> Do we still need that in non-XDP cases?



I meant we check once for both XDP and non-XDP if we do it before if 
(xdp_prog)


>

>> And do we need similar check in receive_big()?

>>

> It seems that the check in page_to_skb() can do similar things.



Right.

Thanks


>

> Thanks,

> Yongji

>
Yongji Xie May 26, 2021, 12:39 p.m. UTC | #3
On Wed, May 26, 2021 at 3:52 PM Jason Wang <jasowang@redhat.com> wrote:
>

>

> 在 2021/5/25 下午4:45, Yongji Xie 写道:

> > On Tue, May 25, 2021 at 2:30 PM Jason Wang <jasowang@redhat.com> wrote:

> >>

> >> 在 2021/5/25 下午12:58, Xie Yongji 写道:

> >>> This adds validation for used length (might come

> >>> from an untrusted device) to avoid data corruption

> >>> or loss.

> >>>

> >>> Signed-off-by: Xie Yongji <xieyongji@bytedance.com>

> >>> ---

> >>>    drivers/net/virtio_net.c | 22 ++++++++++++++++++++++

> >>>    1 file changed, 22 insertions(+)

> >>>

> >>> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c

> >>> index c4711e23af88..2dcdc1a3c7e8 100644

> >>> --- a/drivers/net/virtio_net.c

> >>> +++ b/drivers/net/virtio_net.c

> >>> @@ -668,6 +668,13 @@ static struct sk_buff *receive_small(struct net_device *dev,

> >>>                void *orig_data;

> >>>                u32 act;

> >>>

> >>> +             if (unlikely(len > GOOD_PACKET_LEN)) {

> >>> +                     pr_debug("%s: rx error: len %u exceeds max size %lu\n",

> >>> +                              dev->name, len, GOOD_PACKET_LEN);

> >>> +                     dev->stats.rx_length_errors++;

> >>> +                     goto err_xdp;

> >>> +             }

> >>

> >> Need to count vi->hdr_len here?

> >>

> > We did len -= vi->hdr_len before.

>

>

> Right.

>

>

> >

> >>> +

> >>>                if (unlikely(hdr->hdr.gso_type))

> >>>                        goto err_xdp;

> >>>

> >>> @@ -739,6 +746,14 @@ static struct sk_buff *receive_small(struct net_device *dev,

> >>>        }

> >>>        rcu_read_unlock();

> >>>

> >>> +     if (unlikely(len > GOOD_PACKET_LEN)) {

> >>> +             pr_debug("%s: rx error: len %u exceeds max size %lu\n",

> >>> +                      dev->name, len, GOOD_PACKET_LEN);

> >>> +             dev->stats.rx_length_errors++;

> >>> +             put_page(page);

> >>> +             return NULL;

> >>> +     }

> >>> +

> >>>        skb = build_skb(buf, buflen);

> >>>        if (!skb) {

> >>>                put_page(page);

> >>> @@ -822,6 +837,13 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,

> >>>                void *data;

> >>>                u32 act;

> >>>

> >>> +             if (unlikely(len > truesize)) {

> >>> +                     pr_debug("%s: rx error: len %u exceeds truesize %lu\n",

> >>> +                              dev->name, len, (unsigned long)ctx);

> >>> +                     dev->stats.rx_length_errors++;

> >>> +                     goto err_xdp;

> >>> +             }

> >>

> >> There's a similar check after the XDP, let's simply move it here?

> > Do we still need that in non-XDP cases?

>

>

> I meant we check once for both XDP and non-XDP if we do it before if

> (xdp_prog)

>


Will do it in v2.

Thanks,
Yongji
diff mbox series

Patch

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index c4711e23af88..2dcdc1a3c7e8 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -668,6 +668,13 @@  static struct sk_buff *receive_small(struct net_device *dev,
 		void *orig_data;
 		u32 act;
 
+		if (unlikely(len > GOOD_PACKET_LEN)) {
+			pr_debug("%s: rx error: len %u exceeds max size %lu\n",
+				 dev->name, len, GOOD_PACKET_LEN);
+			dev->stats.rx_length_errors++;
+			goto err_xdp;
+		}
+
 		if (unlikely(hdr->hdr.gso_type))
 			goto err_xdp;
 
@@ -739,6 +746,14 @@  static struct sk_buff *receive_small(struct net_device *dev,
 	}
 	rcu_read_unlock();
 
+	if (unlikely(len > GOOD_PACKET_LEN)) {
+		pr_debug("%s: rx error: len %u exceeds max size %lu\n",
+			 dev->name, len, GOOD_PACKET_LEN);
+		dev->stats.rx_length_errors++;
+		put_page(page);
+		return NULL;
+	}
+
 	skb = build_skb(buf, buflen);
 	if (!skb) {
 		put_page(page);
@@ -822,6 +837,13 @@  static struct sk_buff *receive_mergeable(struct net_device *dev,
 		void *data;
 		u32 act;
 
+		if (unlikely(len > truesize)) {
+			pr_debug("%s: rx error: len %u exceeds truesize %lu\n",
+				 dev->name, len, (unsigned long)ctx);
+			dev->stats.rx_length_errors++;
+			goto err_xdp;
+		}
+
 		/* Transient failure which in theory could occur if
 		 * in-flight packets from before XDP was enabled reach
 		 * the receive path after XDP is loaded.