From: Al Viro <viro@ZenIV.linux.org.uk>
To: netdev@vger.kernel.org
Cc: Eric Dumazet <eric.dumazet@gmail.com>,
Alan Curry <rlwinm@sdf.org>,
alexmcwhirter@triadic.us, David Miller <davem@davemloft.net>,
Christian Lamparter <chunkeey@googlemail.com>
Subject: Re: PROBLEM: network data corruption (bisected to e5a4b0bb803b)
Date: Fri, 10 Feb 2017 21:45:13 +0000 [thread overview]
Message-ID: <20170210214513.GA8937@ZenIV.linux.org.uk> (raw)
In-Reply-To: <20170210081126.GA14157@ZenIV.linux.org.uk>
[repost with netdev added - hadn't realized it wasn't in Cc]
On Tue, Aug 09, 2016 at 03:58:36PM +0100, Al Viro wrote:
> Actually returning to the original behaviour would be "restore ->msg_iter
> if we tried skb_copy_and_csum_datagram() and failed for any reason". Which
> would be bloody inconsistent wrt EFAULT, since the other branch (chunk
> large enough to cover the entire recvmsg()) will copy as much as it can
> and (in old kernel) drain iovec or (on the current one) leave iov_iter
> advance unreverted.
To resurrect the old thread: the problem is still there. Namely, csum
mismatch on packet should leave the iterator as it had been. That much
is clear; the question is what should be done on EFAULT halfway through.
Semantics of both csum and non-csum skb_copy_datagram_msg() variants in
EFAULT case is an interesting question. None of that family report
partial copy; it's full or -EFAULT. So for the sake of basic sanity
it would be better to leave iterator in the original state when that
kind of thing happens. On the other hand, quite a few callers don't
care about the state of iterator after that and I wonder if the overhead
would be sensitive. OTTH, the overhead in question is "save 5 words into
local variable and don't use it in the normal case" - in the code that
copies an skb worth of data.
AFAICS, the following gives consistent (and minimally surprising) semantics,
as well as fixing the outright bug with iov_iter left advanced in case of csum
errors. Comments?
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index c27011bbe30c..14ae17e77603 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -848,7 +848,7 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q,
vlan_offset = offsetof(struct vlan_ethhdr, h_vlan_proto);
total += VLAN_HLEN;
- ret = skb_copy_datagram_iter(skb, 0, iter, vlan_offset);
+ ret = __skb_copy_datagram_iter(skb, 0, iter, vlan_offset);
if (ret || !iov_iter_count(iter))
goto done;
@@ -857,7 +857,7 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q,
goto done;
}
- ret = skb_copy_datagram_iter(skb, vlan_offset, iter,
+ ret = __skb_copy_datagram_iter(skb, vlan_offset, iter,
skb->len - vlan_offset);
done:
@@ -899,11 +899,14 @@ static ssize_t macvtap_do_read(struct macvtap_queue *q,
finish_wait(sk_sleep(&q->sk), &wait);
if (skb) {
+ struct iov_iter saved = *to;
ret = macvtap_put_user(q, skb, to);
- if (unlikely(ret < 0))
+ if (unlikely(ret < 0)) {
+ *to = saved;
kfree_skb(skb);
- else
+ } else {
consume_skb(skb);
+ }
}
return ret;
}
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index a411b43a69eb..0d8badc3c4e9 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -480,7 +480,7 @@ static ssize_t ppp_read(struct file *file, char __user *buf,
iov.iov_base = buf;
iov.iov_len = count;
iov_iter_init(&to, READ, &iov, 1, count);
- if (skb_copy_datagram_iter(skb, 0, &to, skb->len))
+ if (__skb_copy_datagram_iter(skb, 0, &to, skb->len))
goto outf;
ret = skb->len;
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 30863e378925..2003b8c9970e 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -1430,7 +1430,7 @@ static ssize_t tun_put_user(struct tun_struct *tun,
vlan_offset = offsetof(struct vlan_ethhdr, h_vlan_proto);
- ret = skb_copy_datagram_iter(skb, 0, iter, vlan_offset);
+ ret = __skb_copy_datagram_iter(skb, 0, iter, vlan_offset);
if (ret || !iov_iter_count(iter))
goto done;
@@ -1439,7 +1439,8 @@ static ssize_t tun_put_user(struct tun_struct *tun,
goto done;
}
- skb_copy_datagram_iter(skb, vlan_offset, iter, skb->len - vlan_offset);
+ /* XXX: no error check? */
+ __skb_copy_datagram_iter(skb, vlan_offset, iter, skb->len - vlan_offset);
done:
/* caller is in process context, */
@@ -1501,6 +1502,7 @@ static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile,
{
struct sk_buff *skb;
ssize_t ret;
+ struct iov_iter saved;
int err;
tun_debug(KERN_INFO, tun, "tun_do_read\n");
@@ -1513,11 +1515,14 @@ static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile,
if (!skb)
return err;
+ saved = *to;
ret = tun_put_user(tun, tfile, skb, to);
- if (unlikely(ret < 0))
+ if (unlikely(ret < 0)) {
+ *to = saved;
kfree_skb(skb);
- else
+ } else {
consume_skb(skb);
+ }
return ret;
}
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index f1adddc1c5ac..ee8d962373af 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -3060,8 +3060,17 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock,
int *err);
unsigned int datagram_poll(struct file *file, struct socket *sock,
struct poll_table_struct *wait);
-int skb_copy_datagram_iter(const struct sk_buff *from, int offset,
+int __skb_copy_datagram_iter(const struct sk_buff *from, int offset,
struct iov_iter *to, int size);
+static inline int skb_copy_datagram_iter(const struct sk_buff *from, int offset,
+ struct iov_iter *to, int size)
+{
+ struct iov_iter saved = *to;
+ int res = __skb_copy_datagram_iter(from, offset, to, size);
+ if (unlikely(res))
+ *to = saved;
+ return res;
+}
static inline int skb_copy_datagram_msg(const struct sk_buff *from, int offset,
struct msghdr *msg, int size)
{
diff --git a/net/core/datagram.c b/net/core/datagram.c
index ea633342ab0d..33ff2046dda1 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -394,7 +394,7 @@ EXPORT_SYMBOL(skb_kill_datagram);
* @to: iovec iterator to copy to
* @len: amount of data to copy from buffer to iovec
*/
-int skb_copy_datagram_iter(const struct sk_buff *skb, int offset,
+int __skb_copy_datagram_iter(const struct sk_buff *skb, int offset,
struct iov_iter *to, int len)
{
int start = skb_headlen(skb);
@@ -445,7 +445,7 @@ int skb_copy_datagram_iter(const struct sk_buff *skb, int offset,
if ((copy = end - offset) > 0) {
if (copy > len)
copy = len;
- if (skb_copy_datagram_iter(frag_iter, offset - start,
+ if (__skb_copy_datagram_iter(frag_iter, offset - start,
to, copy))
goto fault;
if ((len -= copy) == 0)
@@ -471,7 +471,7 @@ int skb_copy_datagram_iter(const struct sk_buff *skb, int offset,
return 0;
}
-EXPORT_SYMBOL(skb_copy_datagram_iter);
+EXPORT_SYMBOL(__skb_copy_datagram_iter);
/**
* skb_copy_datagram_from_iter - Copy a datagram from an iov_iter.
@@ -750,14 +750,16 @@ int skb_copy_and_csum_datagram_msg(struct sk_buff *skb,
{
__wsum csum;
int chunk = skb->len - hlen;
+ struct iov_iter saved;
if (!chunk)
return 0;
+ saved = msg->msg_iter;
if (msg_data_left(msg) < chunk) {
if (__skb_checksum_complete(skb))
goto csum_error;
- if (skb_copy_datagram_msg(skb, hlen, msg, chunk))
+ if (__skb_copy_datagram_iter(skb, hlen, &msg->msg_iter, chunk))
goto fault;
} else {
csum = csum_partial(skb->data, hlen, skb->csum);
@@ -771,8 +773,10 @@ int skb_copy_and_csum_datagram_msg(struct sk_buff *skb,
}
return 0;
csum_error:
+ msg->msg_iter = saved;
return -EINVAL;
fault:
+ msg->msg_iter = saved;
return -EFAULT;
}
EXPORT_SYMBOL(skb_copy_and_csum_datagram_msg);
next prev parent reply other threads:[~2017-02-10 21:45 UTC|newest]
Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-07-24 3:35 PROBLEM: network data corruption (bisected to e5a4b0bb803b) Alan Curry
2016-07-24 17:45 ` Christian Lamparter
2016-07-24 17:45 ` Christian Lamparter
2016-07-24 19:02 ` Al Viro
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-07-28 1:22 ` Al Viro
2016-08-03 3:49 ` Alan Curry
2016-08-03 12:43 ` Christian Lamparter
2016-08-03 23:25 ` Alan Curry
[not found] ` <20160803054118.GG2356@ZenIV.linux.org.uk>
[not found] ` <2363167.YiBS7sFNO2@debian64>
[not found] ` <20160809145836.GQ2356@ZenIV.linux.org.uk>
[not found] ` <20170210081126.GA14157@ZenIV.linux.org.uk>
2017-02-10 21:45 ` Al Viro [this message]
2017-02-11 19:37 ` Christian Lamparter
2017-02-12 5:42 ` Al Viro
2017-02-13 21:56 ` Christian Lamparter
2017-02-14 1:33 ` [PATCH][CFT] Saner error handling in skb_copy_datagram_iter() et.al. (was Re: PROBLEM: network data corruption (bisected to e5a4b0bb803b)) Al Viro
2017-02-17 15:54 ` [PATCH][CFT] Saner error handling in skb_copy_datagram_iter() et.al David Miller
2017-02-17 17:03 ` Al Viro
2017-02-18 0:02 ` Al Viro
2017-02-18 2:24 ` Al Viro
2017-02-19 19:19 ` Christian Lamparter
2017-02-20 15:14 ` David Miller
2017-02-21 13:25 ` David Laight
2016-07-26 4:32 ` PROBLEM: network data corruption (bisected to e5a4b0bb803b) 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=20170210214513.GA8937@ZenIV.linux.org.uk \
--to=viro@zeniv.linux.org.uk \
--cc=alexmcwhirter@triadic.us \
--cc=chunkeey@googlemail.com \
--cc=davem@davemloft.net \
--cc=eric.dumazet@gmail.com \
--cc=netdev@vger.kernel.org \
--cc=rlwinm@sdf.org \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.