Merge branch 'udp-add-missing-check-on-edumx-rx-path'
Paolo Abeni says: ==================== udp: add missing check on edumx rx path The early demux RX path for the UDP protocol is currently missing some checks. Both ipv4 and ipv6 implementations lack checksum conversion and the ipv6 implementation additionally lack the zero checksum validation. The first patch takes care of UDPv4 and the second one of UDPv6 ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
978298888e
|
@ -2124,6 +2124,28 @@ static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh,
|
|||
inet_compute_pseudo);
|
||||
}
|
||||
|
||||
/* wrapper for udp_queue_rcv_skb tacking care of csum conversion and
|
||||
* return code conversion for ip layer consumption
|
||||
*/
|
||||
static int udp_unicast_rcv_skb(struct sock *sk, struct sk_buff *skb,
|
||||
struct udphdr *uh)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (inet_get_convert_csum(sk) && uh->check && !IS_UDPLITE(sk))
|
||||
skb_checksum_try_convert(skb, IPPROTO_UDP, uh->check,
|
||||
inet_compute_pseudo);
|
||||
|
||||
ret = udp_queue_rcv_skb(sk, skb);
|
||||
|
||||
/* a return value > 0 means to resubmit the input, but
|
||||
* it wants the return to be -protocol, or 0
|
||||
*/
|
||||
if (ret > 0)
|
||||
return -ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* All we need to do is get the socket, and then do a checksum.
|
||||
*/
|
||||
|
@ -2170,14 +2192,9 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
|
|||
if (unlikely(sk->sk_rx_dst != dst))
|
||||
udp_sk_rx_dst_set(sk, dst);
|
||||
|
||||
ret = udp_queue_rcv_skb(sk, skb);
|
||||
ret = udp_unicast_rcv_skb(sk, skb, uh);
|
||||
sock_put(sk);
|
||||
/* a return value > 0 means to resubmit the input, but
|
||||
* it wants the return to be -protocol, or 0
|
||||
*/
|
||||
if (ret > 0)
|
||||
return -ret;
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST))
|
||||
|
@ -2185,22 +2202,8 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
|
|||
saddr, daddr, udptable, proto);
|
||||
|
||||
sk = __udp4_lib_lookup_skb(skb, uh->source, uh->dest, udptable);
|
||||
if (sk) {
|
||||
int ret;
|
||||
|
||||
if (inet_get_convert_csum(sk) && uh->check && !IS_UDPLITE(sk))
|
||||
skb_checksum_try_convert(skb, IPPROTO_UDP, uh->check,
|
||||
inet_compute_pseudo);
|
||||
|
||||
ret = udp_queue_rcv_skb(sk, skb);
|
||||
|
||||
/* a return value > 0 means to resubmit the input, but
|
||||
* it wants the return to be -protocol, or 0
|
||||
*/
|
||||
if (ret > 0)
|
||||
return -ret;
|
||||
return 0;
|
||||
}
|
||||
if (sk)
|
||||
return udp_unicast_rcv_skb(sk, skb, uh);
|
||||
|
||||
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
|
||||
goto drop;
|
||||
|
|
|
@ -752,6 +752,28 @@ static void udp6_sk_rx_dst_set(struct sock *sk, struct dst_entry *dst)
|
|||
}
|
||||
}
|
||||
|
||||
/* wrapper for udp_queue_rcv_skb tacking care of csum conversion and
|
||||
* return code conversion for ip layer consumption
|
||||
*/
|
||||
static int udp6_unicast_rcv_skb(struct sock *sk, struct sk_buff *skb,
|
||||
struct udphdr *uh)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (inet_get_convert_csum(sk) && uh->check && !IS_UDPLITE(sk))
|
||||
skb_checksum_try_convert(skb, IPPROTO_UDP, uh->check,
|
||||
ip6_compute_pseudo);
|
||||
|
||||
ret = udpv6_queue_rcv_skb(sk, skb);
|
||||
|
||||
/* a return value > 0 means to resubmit the input, but
|
||||
* it wants the return to be -protocol, or 0
|
||||
*/
|
||||
if (ret > 0)
|
||||
return -ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
|
||||
int proto)
|
||||
{
|
||||
|
@ -803,13 +825,14 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
|
|||
if (unlikely(sk->sk_rx_dst != dst))
|
||||
udp6_sk_rx_dst_set(sk, dst);
|
||||
|
||||
ret = udpv6_queue_rcv_skb(sk, skb);
|
||||
sock_put(sk);
|
||||
if (!uh->check && !udp_sk(sk)->no_check6_rx) {
|
||||
sock_put(sk);
|
||||
goto report_csum_error;
|
||||
}
|
||||
|
||||
/* a return value > 0 means to resubmit the input */
|
||||
if (ret > 0)
|
||||
return ret;
|
||||
return 0;
|
||||
ret = udp6_unicast_rcv_skb(sk, skb, uh);
|
||||
sock_put(sk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -822,30 +845,13 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
|
|||
/* Unicast */
|
||||
sk = __udp6_lib_lookup_skb(skb, uh->source, uh->dest, udptable);
|
||||
if (sk) {
|
||||
int ret;
|
||||
|
||||
if (!uh->check && !udp_sk(sk)->no_check6_rx) {
|
||||
udp6_csum_zero_error(skb);
|
||||
goto csum_error;
|
||||
}
|
||||
|
||||
if (inet_get_convert_csum(sk) && uh->check && !IS_UDPLITE(sk))
|
||||
skb_checksum_try_convert(skb, IPPROTO_UDP, uh->check,
|
||||
ip6_compute_pseudo);
|
||||
|
||||
ret = udpv6_queue_rcv_skb(sk, skb);
|
||||
|
||||
/* a return value > 0 means to resubmit the input */
|
||||
if (ret > 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
if (!uh->check && !udp_sk(sk)->no_check6_rx)
|
||||
goto report_csum_error;
|
||||
return udp6_unicast_rcv_skb(sk, skb, uh);
|
||||
}
|
||||
|
||||
if (!uh->check) {
|
||||
udp6_csum_zero_error(skb);
|
||||
goto csum_error;
|
||||
}
|
||||
if (!uh->check)
|
||||
goto report_csum_error;
|
||||
|
||||
if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
|
||||
goto discard;
|
||||
|
@ -866,6 +872,9 @@ short_packet:
|
|||
ulen, skb->len,
|
||||
daddr, ntohs(uh->dest));
|
||||
goto discard;
|
||||
|
||||
report_csum_error:
|
||||
udp6_csum_zero_error(skb);
|
||||
csum_error:
|
||||
__UDP6_INC_STATS(net, UDP_MIB_CSUMERRORS, proto == IPPROTO_UDPLITE);
|
||||
discard:
|
||||
|
|
Loading…
Reference in New Issue