From: Alan Curry <rlwinm@sdf.org>
To: Al Viro <viro@ZenIV.linux.org.uk>
Cc: alexmcwhirter@triadic.us, David Miller <davem@davemloft.net>,
rlwinm@sdf.org, chunkeey@googlemail.com,
linux-wireless@vger.kernel.org, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: Re: PROBLEM: network data corruption (bisected to e5a4b0bb803b)
Date: Wed, 3 Aug 2016 03:49:26 +0000 (UTC) [thread overview]
Message-ID: <201608030349.u733nRPn000595@sdf.org> (raw)
In-Reply-To: <20160728012253.GT2356@ZenIV.linux.org.uk>
Al Viro wrote:
>
> Which just might mean that we have *three* issues here -
> (1) buggered __copy_to_user_inatomic() (and friends) on some sparcs
> (2) your ssl-only corruption
> (3) Alan's x86_64 corruption on plain TCP read - no ssl *or* sparc
> anywhere, and no multi-segment recvmsg(). Which would strongly argue in
> favour of some kind of copy_page_to_iter() breakage triggered when handling
> a fragmented skb, as in (1). Except that I don't see anything similar in
> x86_64 uaccess primitives...
>
I think I've solved (3) at least...
Using the twin weapons of printk and stubbornness, I have built a working
theory of the bug. I haven't traced it all the way through, so my explanation
may be partly wrong. I do have a patch that eliminates the symptom in all my
tests though. Here's what happens:
A corrupted packet somehow arrives in skb_copy_and_csum_datagram_msg().
During downloads at reasonably high speed, about 0.1% of my incoming
packets are bad. Probably because the access point is that suspicious
Comcast thing.
skb_copy_and_csum_datagram_msg() does this:
if (skb_copy_and_csum_datagram(skb, hlen, &msg->msg_iter,
chunk, &csum))
goto fault;
if (csum_fold(csum))
goto csum_error;
skb_copy_and_csum_datagram() copies the bad data, computes the checksum,
and *advances the iterator*. The checksum is bad, so it goes to
csum_error, which returns without indicating success to userspace, but the
bad data is in the userspace buffer, and since the iterator has advanced,
the proper data doesn't get written to the proper place when it arrives in a
retransmission. The same iterator is still used because we're still in the
same syscall (I guess - this is one of the parts I didn't check out).
My ugly patch fixes this in the most obvious way: make a local copy of
msg->msg_iter before the call to skb_copy_and_csum_datagram(), and copy it
back if the checksum is bad, just before "goto csum_error;". (I wonder if the
other failure exits from this function might need to do the same thing.)
You can probably reproduce this problem if you deliberately inject some
bad TCP checksums into a stream. Just make sure the receiving machine is
in a blocking read() on the socket when the bad packet arrives. You may
need to resend the offending packet afterward with the checksum corrected.
diff --git a/net/core/datagram.c b/net/core/datagram.c
index b7de71f..574d4bf 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -730,6 +730,7 @@ int skb_copy_and_csum_datagram_msg(struct sk_buff *skb,
{
__wsum csum;
int chunk = skb->len - hlen;
+ struct iov_iter save_iter;
if (!chunk)
return 0;
@@ -741,11 +742,14 @@ int skb_copy_and_csum_datagram_msg(struct sk_buff *skb,
goto fault;
} else {
csum = csum_partial(skb->data, hlen, skb->csum);
+ memcpy(&save_iter, &msg->msg_iter, sizeof save_iter);
if (skb_copy_and_csum_datagram(skb, hlen, &msg->msg_iter,
chunk, &csum))
goto fault;
- if (csum_fold(csum))
+ if (csum_fold(csum)) {
+ memcpy(&msg->msg_iter, &save_iter, sizeof save_iter);
goto csum_error;
+ }
if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE))
netdev_rx_csum_fault(skb->dev);
}
--
Alan Curry
next prev parent reply other threads:[~2016-08-03 3:50 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-07-24 3:35 Alan Curry
2016-07-24 17:45 ` Christian Lamparter
2016-07-24 19:02 ` Al Viro
2016-07-26 4:57 ` Alan Curry
2016-07-26 13:59 ` Christian Lamparter
2016-07-26 18:15 ` alexmcwhirter
2016-07-27 6:39 ` Kalle Valo
2016-07-27 1:14 ` Alan Curry
2016-07-27 10:32 ` Alan Curry
2016-07-27 18:04 ` alexmcwhirter
2016-07-27 23:02 ` alexmcwhirter
2016-07-27 23:45 ` David Miller
2016-07-28 0:31 ` Al Viro
2016-07-28 0:26 ` alexmcwhirter
2016-07-28 1:22 ` Al Viro
2016-08-03 3:49 ` Alan Curry [this message]
2016-08-03 12:43 ` Christian Lamparter
2016-08-03 23:25 ` Alan Curry
2016-07-26 4:32 ` Alan Curry
2016-07-26 4:38 ` alexmcwhirter
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=201608030349.u733nRPn000595@sdf.org \
--to=rlwinm@sdf.org \
--cc=alexmcwhirter@triadic.us \
--cc=chunkeey@googlemail.com \
--cc=davem@davemloft.net \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-wireless@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=viro@ZenIV.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®