aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/net/core/skbuff.c
diff options
context:
space:
mode:
authorWillem de Bruijn <willemb@google.com>2017-10-19 12:40:39 -0400
committerDavid S. Miller <davem@davemloft.net>2017-10-22 01:45:52 +0100
commit54d431176429e9cf064461589e5174349a9f73da (patch)
treee67d98437ea56d6872670cfccc7ae660d2fdcf24 /net/core/skbuff.c
parentMerge branch 'bpf-range-marking-fixes' (diff)
downloadwireguard-linux-54d431176429e9cf064461589e5174349a9f73da.tar.xz
wireguard-linux-54d431176429e9cf064461589e5174349a9f73da.zip
sock: correct sk_wmem_queued accounting on efault in tcp zerocopy
Syzkaller hits WARN_ON(sk->sk_wmem_queued) in sk_stream_kill_queues after triggering an EFAULT in __zerocopy_sg_from_iter. On this error, skb_zerocopy_stream_iter resets the skb to its state before the operation with __pskb_trim. It cannot kfree_skb like datagram callers, as the skb may have data from a previous send call. __pskb_trim calls skb_condense for unowned skbs, which adjusts their truesize. These tcp skbuffs are owned and their truesize must add up to sk_wmem_queued. But they match because their skb->sk is NULL until tcp_transmit_skb. Temporarily set skb->sk when calling __pskb_trim to signal that the skbuffs are owned and avoid the skb_condense path. Fixes: 52267790ef52 ("sock: add MSG_ZEROCOPY") Signed-off-by: Willem de Bruijn <willemb@google.com> Reviewed-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to '')
-rw-r--r--net/core/skbuff.c4
1 files changed, 4 insertions, 0 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index e62476beee95..24656076906d 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -1124,9 +1124,13 @@ int skb_zerocopy_iter_stream(struct sock *sk, struct sk_buff *skb,
err = __zerocopy_sg_from_iter(sk, skb, &msg->msg_iter, len);
if (err == -EFAULT || (err == -EMSGSIZE && skb->len == orig_len)) {
+ struct sock *save_sk = skb->sk;
+
/* Streams do not free skb on error. Reset to prev state. */
msg->msg_iter = orig_iter;
+ skb->sk = sk;
___pskb_trim(skb, orig_len);
+ skb->sk = save_sk;
return err;
}