net: correct udp zerocopy refcnt also when zerocopy only on append
authorWillem de Bruijn <willemb@google.com>
Fri, 7 Jun 2019 21:57:48 +0000 (17:57 -0400)
committerDavid S. Miller <davem@davemloft.net>
Tue, 11 Jun 2019 18:40:54 +0000 (11:40 -0700)
The below patch fixes an incorrect zerocopy refcnt increment when
appending with MSG_MORE to an existing zerocopy udp skb.

  send(.., MSG_ZEROCOPY | MSG_MORE); // refcnt 1
  send(.., MSG_ZEROCOPY | MSG_MORE); // refcnt still 1 (bar frags)

But it missed that zerocopy need not be passed at the first send. The
right test whether the uarg is newly allocated and thus has extra
refcnt 1 is not !skb, but !skb_zcopy.

  send(.., MSG_MORE); // <no uarg>
  send(.., MSG_ZEROCOPY); // refcnt 1

Fixes: 100f6d8e09905 ("net: correct zerocopy refcnt with udp MSG_MORE")
Reported-by: syzbot <syzkaller@googlegroups.com>
Signed-off-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv4/ip_output.c
net/ipv6/ip6_output.c

index 8c9189a41b136c6f170e146f8a425a7041efc5f8..16f9159234a2014491fdd7f7371d6cb06b978adc 100644 (file)
@@ -918,7 +918,7 @@ static int __ip_append_data(struct sock *sk,
                uarg = sock_zerocopy_realloc(sk, length, skb_zcopy(skb));
                if (!uarg)
                        return -ENOBUFS;
-               extra_uref = !skb;      /* only extra ref if !MSG_MORE */
+               extra_uref = !skb_zcopy(skb);   /* only ref on new uarg */
                if (rt->dst.dev->features & NETIF_F_SG &&
                    csummode == CHECKSUM_PARTIAL) {
                        paged = true;
index 934c88f128abbd22bb994d56a018da1748ff3a16..834475717110ecc53aa5bd2e3f275f2e8980fb05 100644 (file)
@@ -1340,7 +1340,7 @@ emsgsize:
                uarg = sock_zerocopy_realloc(sk, length, skb_zcopy(skb));
                if (!uarg)
                        return -ENOBUFS;
-               extra_uref = !skb;      /* only extra ref if !MSG_MORE */
+               extra_uref = !skb_zcopy(skb);   /* only ref on new uarg */
                if (rt->dst.dev->features & NETIF_F_SG &&
                    csummode == CHECKSUM_PARTIAL) {
                        paged = true;