diff options
author | Eric Dumazet <edumazet@google.com> | 2016-10-23 21:03:06 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-10-26 17:33:22 -0400 |
commit | 10df8e6152c6c400a563a673e9956320bfce1871 (patch) | |
tree | 364d982c791875093f8b1cf2f6227c6e471dcf11 | |
parent | ecc515d7238f2cffac839069d56dc271141defa0 (diff) |
udp: fix IP_CHECKSUM handling
First bug was added in commit ad6f939ab193 ("ip: Add offset parameter to
ip_cmsg_recv") : Tom missed that ipv4 udp messages could be received on
AF_INET6 socket. ip_cmsg_recv(msg, skb) should have been replaced by
ip_cmsg_recv_offset(msg, skb, sizeof(struct udphdr));
Then commit e6afc8ace6dd ("udp: remove headers from UDP packets before
queueing") forgot to adjust the offsets now UDP headers are pulled
before skb are put in receive queue.
Fixes: ad6f939ab193 ("ip: Add offset parameter to ip_cmsg_recv")
Fixes: e6afc8ace6dd ("udp: remove headers from UDP packets before queueing")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Sam Kumar <samanthakumar@google.com>
Cc: Willem de Bruijn <willemb@google.com>
Tested-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/ip.h | 4 | ||||
-rw-r--r-- | net/ipv4/ip_sockglue.c | 11 | ||||
-rw-r--r-- | net/ipv4/udp.c | 2 | ||||
-rw-r--r-- | net/ipv6/udp.c | 3 |
4 files changed, 11 insertions, 9 deletions
diff --git a/include/net/ip.h b/include/net/ip.h index c9d07988911e..5413883ac47f 100644 --- a/include/net/ip.h +++ b/include/net/ip.h | |||
@@ -578,7 +578,7 @@ int ip_options_rcv_srr(struct sk_buff *skb); | |||
578 | */ | 578 | */ |
579 | 579 | ||
580 | void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb); | 580 | void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb); |
581 | void ip_cmsg_recv_offset(struct msghdr *msg, struct sk_buff *skb, int offset); | 581 | void ip_cmsg_recv_offset(struct msghdr *msg, struct sk_buff *skb, int tlen, int offset); |
582 | int ip_cmsg_send(struct sock *sk, struct msghdr *msg, | 582 | int ip_cmsg_send(struct sock *sk, struct msghdr *msg, |
583 | struct ipcm_cookie *ipc, bool allow_ipv6); | 583 | struct ipcm_cookie *ipc, bool allow_ipv6); |
584 | int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval, | 584 | int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval, |
@@ -600,7 +600,7 @@ void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 dport, | |||
600 | 600 | ||
601 | static inline void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb) | 601 | static inline void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb) |
602 | { | 602 | { |
603 | ip_cmsg_recv_offset(msg, skb, 0); | 603 | ip_cmsg_recv_offset(msg, skb, 0, 0); |
604 | } | 604 | } |
605 | 605 | ||
606 | bool icmp_global_allow(void); | 606 | bool icmp_global_allow(void); |
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index af4919792b6a..b8a2d63d1fb8 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c | |||
@@ -98,7 +98,7 @@ static void ip_cmsg_recv_retopts(struct msghdr *msg, struct sk_buff *skb) | |||
98 | } | 98 | } |
99 | 99 | ||
100 | static void ip_cmsg_recv_checksum(struct msghdr *msg, struct sk_buff *skb, | 100 | static void ip_cmsg_recv_checksum(struct msghdr *msg, struct sk_buff *skb, |
101 | int offset) | 101 | int tlen, int offset) |
102 | { | 102 | { |
103 | __wsum csum = skb->csum; | 103 | __wsum csum = skb->csum; |
104 | 104 | ||
@@ -106,8 +106,9 @@ static void ip_cmsg_recv_checksum(struct msghdr *msg, struct sk_buff *skb, | |||
106 | return; | 106 | return; |
107 | 107 | ||
108 | if (offset != 0) | 108 | if (offset != 0) |
109 | csum = csum_sub(csum, csum_partial(skb_transport_header(skb), | 109 | csum = csum_sub(csum, |
110 | offset, 0)); | 110 | csum_partial(skb_transport_header(skb) + tlen, |
111 | offset, 0)); | ||
111 | 112 | ||
112 | put_cmsg(msg, SOL_IP, IP_CHECKSUM, sizeof(__wsum), &csum); | 113 | put_cmsg(msg, SOL_IP, IP_CHECKSUM, sizeof(__wsum), &csum); |
113 | } | 114 | } |
@@ -153,7 +154,7 @@ static void ip_cmsg_recv_dstaddr(struct msghdr *msg, struct sk_buff *skb) | |||
153 | } | 154 | } |
154 | 155 | ||
155 | void ip_cmsg_recv_offset(struct msghdr *msg, struct sk_buff *skb, | 156 | void ip_cmsg_recv_offset(struct msghdr *msg, struct sk_buff *skb, |
156 | int offset) | 157 | int tlen, int offset) |
157 | { | 158 | { |
158 | struct inet_sock *inet = inet_sk(skb->sk); | 159 | struct inet_sock *inet = inet_sk(skb->sk); |
159 | unsigned int flags = inet->cmsg_flags; | 160 | unsigned int flags = inet->cmsg_flags; |
@@ -216,7 +217,7 @@ void ip_cmsg_recv_offset(struct msghdr *msg, struct sk_buff *skb, | |||
216 | } | 217 | } |
217 | 218 | ||
218 | if (flags & IP_CMSG_CHECKSUM) | 219 | if (flags & IP_CMSG_CHECKSUM) |
219 | ip_cmsg_recv_checksum(msg, skb, offset); | 220 | ip_cmsg_recv_checksum(msg, skb, tlen, offset); |
220 | } | 221 | } |
221 | EXPORT_SYMBOL(ip_cmsg_recv_offset); | 222 | EXPORT_SYMBOL(ip_cmsg_recv_offset); |
222 | 223 | ||
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 311613e413cb..d123d68f4d1d 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -1322,7 +1322,7 @@ try_again: | |||
1322 | *addr_len = sizeof(*sin); | 1322 | *addr_len = sizeof(*sin); |
1323 | } | 1323 | } |
1324 | if (inet->cmsg_flags) | 1324 | if (inet->cmsg_flags) |
1325 | ip_cmsg_recv_offset(msg, skb, sizeof(struct udphdr) + off); | 1325 | ip_cmsg_recv_offset(msg, skb, sizeof(struct udphdr), off); |
1326 | 1326 | ||
1327 | err = copied; | 1327 | err = copied; |
1328 | if (flags & MSG_TRUNC) | 1328 | if (flags & MSG_TRUNC) |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 9aa7c1c7a9ce..b2ef061e6836 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -427,7 +427,8 @@ try_again: | |||
427 | 427 | ||
428 | if (is_udp4) { | 428 | if (is_udp4) { |
429 | if (inet->cmsg_flags) | 429 | if (inet->cmsg_flags) |
430 | ip_cmsg_recv(msg, skb); | 430 | ip_cmsg_recv_offset(msg, skb, |
431 | sizeof(struct udphdr), off); | ||
431 | } else { | 432 | } else { |
432 | if (np->rxopt.all) | 433 | if (np->rxopt.all) |
433 | ip6_datagram_recv_specific_ctl(sk, msg, skb); | 434 | ip6_datagram_recv_specific_ctl(sk, msg, skb); |