| From 224102de2ff105a2c05695e66a08f4b5b6b2d19c Mon Sep 17 00:00:00 2001 |
| From: lena wang <lena.wang@mediatek.com> |
| Date: Tue, 1 Mar 2022 19:17:09 +0800 |
| Subject: net: fix up skbs delta_truesize in UDP GRO frag_list |
| |
| From: lena wang <lena.wang@mediatek.com> |
| |
| commit 224102de2ff105a2c05695e66a08f4b5b6b2d19c upstream. |
| |
| The truesize for a UDP GRO packet is added by main skb and skbs in main |
| skb's frag_list: |
| skb_gro_receive_list |
| p->truesize += skb->truesize; |
| |
| The commit 53475c5dd856 ("net: fix use-after-free when UDP GRO with |
| shared fraglist") introduced a truesize increase for frag_list skbs. |
| When uncloning skb, it will call pskb_expand_head and trusesize for |
| frag_list skbs may increase. This can occur when allocators uses |
| __netdev_alloc_skb and not jump into __alloc_skb. This flow does not |
| use ksize(len) to calculate truesize while pskb_expand_head uses. |
| skb_segment_list |
| err = skb_unclone(nskb, GFP_ATOMIC); |
| pskb_expand_head |
| if (!skb->sk || skb->destructor == sock_edemux) |
| skb->truesize += size - osize; |
| |
| If we uses increased truesize adding as delta_truesize, it will be |
| larger than before and even larger than previous total truesize value |
| if skbs in frag_list are abundant. The main skb truesize will become |
| smaller and even a minus value or a huge value for an unsigned int |
| parameter. Then the following memory check will drop this abnormal skb. |
| |
| To avoid this error we should use the original truesize to segment the |
| main skb. |
| |
| Fixes: 53475c5dd856 ("net: fix use-after-free when UDP GRO with shared fraglist") |
| Signed-off-by: lena wang <lena.wang@mediatek.com> |
| Acked-by: Paolo Abeni <pabeni@redhat.com> |
| Reviewed-by: Eric Dumazet <edumazet@google.com> |
| Link: https://lore.kernel.org/r/1646133431-8948-1-git-send-email-lena.wang@mediatek.com |
| Signed-off-by: Jakub Kicinski <kuba@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/core/skbuff.c | 2 +- |
| 1 file changed, 1 insertion(+), 1 deletion(-) |
| |
| --- a/net/core/skbuff.c |
| +++ b/net/core/skbuff.c |
| @@ -3853,6 +3853,7 @@ struct sk_buff *skb_segment_list(struct |
| list_skb = list_skb->next; |
| |
| err = 0; |
| + delta_truesize += nskb->truesize; |
| if (skb_shared(nskb)) { |
| tmp = skb_clone(nskb, GFP_ATOMIC); |
| if (tmp) { |
| @@ -3877,7 +3878,6 @@ struct sk_buff *skb_segment_list(struct |
| tail = nskb; |
| |
| delta_len += nskb->len; |
| - delta_truesize += nskb->truesize; |
| |
| skb_push(nskb, -skb_network_offset(nskb) + offset); |
| |