Message ID | 1452882255-23203-1-git-send-email-luis.henriques@canonical.com |
---|---|
State | New |
Headers | show |
On Fri, Jan 15, 2016 at 06:24:15PM +0000, Luis Henriques wrote: > This is a note to let you know that I have just added a patch titled > > udp: properly support MSG_PEEK with truncated buffers > > to the linux-3.16.y-queue branch of the 3.16.y-ckt extended stable tree > which can be found at: > Actually, I am deferring this patch for now as it has not been included in an upstream release yet. Cheers, -- Luís > http://kernel.ubuntu.com/git/ubuntu/linux.git/log/?h=linux-3.16.y-queue > > This patch is scheduled to be released in version 3.16.7-ckt23. > > If you, or anyone else, feels it should not be added to this tree, please > reply to this email. > > For more information about the 3.16.y-ckt tree, see > https://wiki.ubuntu.com/Kernel/Dev/ExtendedStable > > Thanks. > -Luis > > ---8<------------------------------------------------------------ > > From eb98e28dee492dcf8784eeeedeb23258d9be3f4d Mon Sep 17 00:00:00 2001 > From: Eric Dumazet <edumazet@google.com> > Date: Wed, 30 Dec 2015 08:51:12 -0500 > Subject: udp: properly support MSG_PEEK with truncated buffers > > commit 197c949e7798fbf28cfadc69d9ca0c2abbf93191 upstream. > > Backport of this upstream commit into stable kernels : > 89c22d8c3b27 ("net: Fix skb csum races when peeking") > exposed a bug in udp stack vs MSG_PEEK support, when user provides > a buffer smaller than skb payload. > > In this case, > skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), > msg->msg_iov); > returns -EFAULT. > > This bug does not happen in upstream kernels since Al Viro did a great > job to replace this into : > skb_copy_and_csum_datagram_msg(skb, sizeof(struct udphdr), msg); > This variant is safe vs short buffers. > > For the time being, instead reverting Herbert Xu patch and add back > skb->ip_summed invalid changes, simply store the result of > udp_lib_checksum_complete() so that we avoid computing the checksum a > second time, and avoid the problematic > skb_copy_and_csum_datagram_iovec() call. > > This patch can be applied on recent kernels as it avoids a double > checksumming, then backported to stable kernels as a bug fix. > > Signed-off-by: Eric Dumazet <edumazet@google.com> > Acked-by: Herbert Xu <herbert@gondor.apana.org.au> > Signed-off-by: David S. Miller <davem@davemloft.net> > Cc: Michal Kubecek <mkubecek@suse.cz> > Cc: Ben Hutchings <ben@decadent.org.uk> > [ luis: backported to 3.16: adjusted context ] > Signed-off-by: Luis Henriques <luis.henriques@canonical.com> > --- > net/ipv4/udp.c | 6 ++++-- > net/ipv6/udp.c | 6 ++++-- > 2 files changed, 8 insertions(+), 4 deletions(-) > > diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c > index 4b9e4aba11b0..c57fa4c74c94 100644 > --- a/net/ipv4/udp.c > +++ b/net/ipv4/udp.c > @@ -1272,6 +1272,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, > int peeked, off = 0; > int err; > int is_udplite = IS_UDPLITE(sk); > + bool checksum_valid = false; > bool slow; > > if (flags & MSG_ERRQUEUE) > @@ -1297,11 +1298,12 @@ try_again: > */ > > if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { > - if (udp_lib_checksum_complete(skb)) > + checksum_valid = !udp_lib_checksum_complete(skb); > + if (!checksum_valid) > goto csum_copy_err; > } > > - if (skb_csum_unnecessary(skb)) > + if (checksum_valid || skb_csum_unnecessary(skb)) > err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), > msg->msg_iov, copied); > else { > diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c > index eb38829d8919..e432f8eb3c60 100644 > --- a/net/ipv6/udp.c > +++ b/net/ipv6/udp.c > @@ -389,6 +389,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, > int peeked, off = 0; > int err; > int is_udplite = IS_UDPLITE(sk); > + bool checksum_valid = false; > int is_udp4; > bool slow; > > @@ -420,11 +421,12 @@ try_again: > */ > > if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { > - if (udp_lib_checksum_complete(skb)) > + checksum_valid = !udp_lib_checksum_complete(skb); > + if (!checksum_valid) > goto csum_copy_err; > } > > - if (skb_csum_unnecessary(skb)) > + if (checksum_valid || skb_csum_unnecessary(skb)) > err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), > msg->msg_iov, copied); > else {
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 4b9e4aba11b0..c57fa4c74c94 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1272,6 +1272,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, int peeked, off = 0; int err; int is_udplite = IS_UDPLITE(sk); + bool checksum_valid = false; bool slow; if (flags & MSG_ERRQUEUE) @@ -1297,11 +1298,12 @@ try_again: */ if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { - if (udp_lib_checksum_complete(skb)) + checksum_valid = !udp_lib_checksum_complete(skb); + if (!checksum_valid) goto csum_copy_err; } - if (skb_csum_unnecessary(skb)) + if (checksum_valid || skb_csum_unnecessary(skb)) err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, copied); else { diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index eb38829d8919..e432f8eb3c60 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -389,6 +389,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, int peeked, off = 0; int err; int is_udplite = IS_UDPLITE(sk); + bool checksum_valid = false; int is_udp4; bool slow; @@ -420,11 +421,12 @@ try_again: */ if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { - if (udp_lib_checksum_complete(skb)) + checksum_valid = !udp_lib_checksum_complete(skb); + if (!checksum_valid) goto csum_copy_err; } - if (skb_csum_unnecessary(skb)) + if (checksum_valid || skb_csum_unnecessary(skb)) err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, copied); else {