Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

udp: with udp_segment release on error path

Failure __ip_append_data triggers udp_flush_pending_frames, but these
tests happen later. The skb must be freed directly.

Fixes: bec1f6f697362 ("udp: generate gso with UDP_SEGMENT")
Reported-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Willem de Bruijn and committed by
David S. Miller
0f149c9f 1a935268

+24 -8
+12 -4
net/ipv4/udp.c
··· 847 847 const int hlen = skb_network_header_len(skb) + 848 848 sizeof(struct udphdr); 849 849 850 - if (hlen + cork->gso_size > cork->fragsize) 850 + if (hlen + cork->gso_size > cork->fragsize) { 851 + kfree_skb(skb); 851 852 return -EINVAL; 852 - if (skb->len > cork->gso_size * UDP_MAX_SEGMENTS) 853 + } 854 + if (skb->len > cork->gso_size * UDP_MAX_SEGMENTS) { 855 + kfree_skb(skb); 853 856 return -EINVAL; 854 - if (sk->sk_no_check_tx) 857 + } 858 + if (sk->sk_no_check_tx) { 859 + kfree_skb(skb); 855 860 return -EINVAL; 861 + } 856 862 if (skb->ip_summed != CHECKSUM_PARTIAL || is_udplite || 857 - dst_xfrm(skb_dst(skb))) 863 + dst_xfrm(skb_dst(skb))) { 864 + kfree_skb(skb); 858 865 return -EIO; 866 + } 859 867 860 868 skb_shinfo(skb)->gso_size = cork->gso_size; 861 869 skb_shinfo(skb)->gso_type = SKB_GSO_UDP_L4;
+12 -4
net/ipv6/udp.c
··· 1132 1132 const int hlen = skb_network_header_len(skb) + 1133 1133 sizeof(struct udphdr); 1134 1134 1135 - if (hlen + cork->gso_size > cork->fragsize) 1135 + if (hlen + cork->gso_size > cork->fragsize) { 1136 + kfree_skb(skb); 1136 1137 return -EINVAL; 1137 - if (skb->len > cork->gso_size * UDP_MAX_SEGMENTS) 1138 + } 1139 + if (skb->len > cork->gso_size * UDP_MAX_SEGMENTS) { 1140 + kfree_skb(skb); 1138 1141 return -EINVAL; 1139 - if (udp_sk(sk)->no_check6_tx) 1142 + } 1143 + if (udp_sk(sk)->no_check6_tx) { 1144 + kfree_skb(skb); 1140 1145 return -EINVAL; 1146 + } 1141 1147 if (skb->ip_summed != CHECKSUM_PARTIAL || is_udplite || 1142 - dst_xfrm(skb_dst(skb))) 1148 + dst_xfrm(skb_dst(skb))) { 1149 + kfree_skb(skb); 1143 1150 return -EIO; 1151 + } 1144 1152 1145 1153 skb_shinfo(skb)->gso_size = cork->gso_size; 1146 1154 skb_shinfo(skb)->gso_type = SKB_GSO_UDP_L4;