Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 5 Mar 2017 01:31:39 +0000 (17:31 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 5 Mar 2017 01:31:39 +0000 (17:31 -0800)
Pull networking fixes from David Miller:

 1) Fix double-free in batman-adv, from Sven Eckelmann.

 2) Fix packet stats for fast-RX path, from Joannes Berg.

 3) Netfilter's ip_route_me_harder() doesn't handle request sockets
    properly, fix from Florian Westphal.

 4) Fix sendmsg deadlock in rxrpc, from David Howells.

 5) Add missing RCU locking to transport hashtable scan, from Xin Long.

 6) Fix potential packet loss in mlxsw driver, from Ido Schimmel.

 7) Fix race in NAPI handling between poll handlers and busy polling,
    from Eric Dumazet.

 8) TX path in vxlan and geneve need proper RCU locking, from Jakub
    Kicinski.

 9) SYN processing in DCCP and TCP need to disable BH, from Eric
    Dumazet.

10) Properly handle net_enable_timestamp() being invoked from IRQ
    context, also from Eric Dumazet.

11) Fix crash on device-tree systems in xgene driver, from Alban Bedel.

12) Do not call sk_free() on a locked socket, from Arnaldo Carvalho de
    Melo.

13) Fix use-after-free in netvsc driver, from Dexuan Cui.

14) Fix max MTU setting in bonding driver, from WANG Cong.

15) xen-netback hash table can be allocated from softirq context, so use
    GFP_ATOMIC. From Anoob Soman.

16) Fix MAC address change bug in bgmac driver, from Hari Vyas.

17) strparser needs to destroy strp_wq on module exit, from WANG Cong.

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net: (69 commits)
  strparser: destroy workqueue on module exit
  sfc: fix IPID endianness in TSOv2
  sfc: avoid max() in array size
  rds: remove unnecessary returned value check
  rxrpc: Fix potential NULL-pointer exception
  nfp: correct DMA direction in XDP DMA sync
  nfp: don't tell FW about the reserved buffer space
  net: ethernet: bgmac: mac address change bug
  net: ethernet: bgmac: init sequence bug
  xen-netback: don't vfree() queues under spinlock
  xen-netback: keep a local pointer for vif in backend_disconnect()
  netfilter: nf_tables: don't call nfnetlink_set_err() if nfnetlink_send() fails
  netfilter: nft_set_rbtree: incorrect assumption on lower interval lookups
  netfilter: nf_conntrack_sip: fix wrong memory initialisation
  can: flexcan: fix typo in comment
  can: usb_8dev: Fix memory leak of priv->cmd_msg_buffer
  can: gs_usb: fix coding style
  can: gs_usb: Don't use stack memory for USB transfers
  ixgbe: Limit use of 2K buffers on architectures with 256B or larger cache lines
  ixgbe: update the rss key on h/w, when ethtool ask for it
  ...

1  2 
MAINTAINERS
drivers/net/virtio_net.c
net/ipv6/addrconf.c
net/rds/rds.h
net/rxrpc/recvmsg.c
net/rxrpc/sendmsg.c

diff --combined MAINTAINERS
@@@ -5034,6 -5034,7 +5034,6 @@@ F:      lib/fault-inject.
  
  FBTFT Framebuffer drivers
  M:    Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
 -M:    Noralf Trønnes <noralf@tronnes.org>
  S:    Maintained
  F:    drivers/staging/fbtft/
  
@@@ -6011,9 -6012,8 +6011,8 @@@ F:      include/linux/hsi
  F:    include/uapi/linux/hsi/
  
  HSO 3G MODEM DRIVER
- M:    Jan Dumon <j.dumon@option.com>
- W:    http://www.pharscape.org
- S:    Maintained
+ L:    linux-usb@vger.kernel.org
+ S:    Orphan
  F:    drivers/net/usb/hso.c
  
  HSR NETWORK PROTOCOL
@@@ -7482,24 -7482,18 +7481,24 @@@ L:   linuxppc-dev@lists.ozlabs.or
  Q:    http://patchwork.ozlabs.org/project/linuxppc-dev/list/
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git
  S:    Supported
 +F:    Documentation/ABI/stable/sysfs-firmware-opal-*
 +F:    Documentation/devicetree/bindings/powerpc/opal/
 +F:    Documentation/devicetree/bindings/rtc/rtc-opal.txt
 +F:    Documentation/devicetree/bindings/i2c/i2c-opal.txt
  F:    Documentation/powerpc/
  F:    arch/powerpc/
  F:    drivers/char/tpm/tpm_ibmvtpm*
  F:    drivers/crypto/nx/
  F:    drivers/crypto/vmx/
 +F:    drivers/i2c/busses/i2c-opal.c
  F:    drivers/net/ethernet/ibm/ibmveth.*
  F:    drivers/net/ethernet/ibm/ibmvnic.*
  F:    drivers/pci/hotplug/pnv_php.c
  F:    drivers/pci/hotplug/rpa*
 +F:    drivers/rtc/rtc-opal.c
  F:    drivers/scsi/ibmvscsi/
 +F:    drivers/tty/hvc/hvc_opal.c
  F:    tools/testing/selftests/powerpc
 -N:    opal
  N:    /pmac
  N:    powermac
  N:    powernv
@@@ -10335,12 -10329,6 +10334,12 @@@ L: linux-scsi@vger.kernel.or
  S:    Supported
  F:    drivers/scsi/qedi/
  
 +QLOGIC QL41xxx FCOE DRIVER
 +M:    QLogic-Storage-Upstream@cavium.com
 +L:    linux-scsi@vger.kernel.org
 +S:    Supported
 +F:    drivers/scsi/qedf/
 +
  QNX4 FILESYSTEM
  M:    Anders Larsen <al@alarsen.net>
  W:    http://www.alarsen.net/linux/qnx4fs/
diff --combined drivers/net/virtio_net.c
@@@ -51,7 -51,7 +51,7 @@@ module_param(gso, bool, 0444)
   * at once, the weight is chosen so that the EWMA will be insensitive to short-
   * term, transient changes in packet size.
   */
- DECLARE_EWMA(pkt_len, 1, 64)
+ DECLARE_EWMA(pkt_len, 0, 64)
  
  /* With mergeable buffers we align buffer address and use the low bits to
   * encode its true size. Buffer size is up to 1 page so we need to align to
@@@ -2080,7 -2080,7 +2080,7 @@@ static int virtnet_find_vqs(struct virt
        }
  
        ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
 -                                       names);
 +                                       names, NULL);
        if (ret)
                goto err_find;
  
diff --combined net/ipv6/addrconf.c
@@@ -43,7 -43,6 +43,7 @@@
  #include <linux/errno.h>
  #include <linux/types.h>
  #include <linux/kernel.h>
 +#include <linux/sched/signal.h>
  #include <linux/socket.h>
  #include <linux/sockios.h>
  #include <linux/net.h>
@@@ -5693,13 -5692,18 +5693,18 @@@ static int addrconf_sysctl_addr_gen_mod
        struct inet6_dev *idev = (struct inet6_dev *)ctl->extra1;
        struct net *net = (struct net *)ctl->extra2;
  
+       if (!rtnl_trylock())
+               return restart_syscall();
        ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
  
        if (write) {
                new_val = *((int *)ctl->data);
  
-               if (check_addr_gen_mode(new_val) < 0)
-                       return -EINVAL;
+               if (check_addr_gen_mode(new_val) < 0) {
+                       ret = -EINVAL;
+                       goto out;
+               }
  
                /* request for default */
                if (&net->ipv6.devconf_dflt->addr_gen_mode == ctl->data) {
                /* request for individual net device */
                } else {
                        if (!idev)
-                               return ret;
+                               goto out;
  
-                       if (check_stable_privacy(idev, net, new_val) < 0)
-                               return -EINVAL;
+                       if (check_stable_privacy(idev, net, new_val) < 0) {
+                               ret = -EINVAL;
+                               goto out;
+                       }
  
                        if (idev->cnf.addr_gen_mode != new_val) {
                                idev->cnf.addr_gen_mode = new_val;
-                               rtnl_lock();
                                addrconf_dev_config(idev->dev);
-                               rtnl_unlock();
                        }
                }
        }
  
+ out:
+       rtnl_unlock();
        return ret;
  }
  
diff --combined net/rds/rds.h
@@@ -798,6 -798,13 +798,6 @@@ static inline int rds_message_verify_ch
  /* page.c */
  int rds_page_remainder_alloc(struct scatterlist *scat, unsigned long bytes,
                             gfp_t gfp);
 -int rds_page_copy_user(struct page *page, unsigned long offset,
 -                     void __user *ptr, unsigned long bytes,
 -                     int to_user);
 -#define rds_page_copy_to_user(page, offset, ptr, bytes) \
 -      rds_page_copy_user(page, offset, ptr, bytes, 1)
 -#define rds_page_copy_from_user(page, offset, ptr, bytes) \
 -      rds_page_copy_user(page, offset, ptr, bytes, 0)
  void rds_page_exit(void);
  
  /* recv.c */
@@@ -903,7 -910,7 +903,7 @@@ void rds_connect_path_complete(struct r
  void rds_connect_complete(struct rds_connection *conn);
  
  /* transport.c */
int rds_trans_register(struct rds_transport *trans);
void rds_trans_register(struct rds_transport *trans);
  void rds_trans_unregister(struct rds_transport *trans);
  struct rds_transport *rds_trans_get_preferred(struct net *net, __be32 addr);
  void rds_trans_put(struct rds_transport *trans);
diff --combined net/rxrpc/recvmsg.c
@@@ -14,8 -14,6 +14,8 @@@
  #include <linux/net.h>
  #include <linux/skbuff.h>
  #include <linux/export.h>
 +#include <linux/sched/signal.h>
 +
  #include <net/sock.h>
  #include <net/af_rxrpc.h>
  #include "ar-internal.h"
@@@ -489,6 -487,20 +489,20 @@@ try_again
  
        trace_rxrpc_recvmsg(call, rxrpc_recvmsg_dequeue, 0, 0, 0, 0);
  
+       /* We're going to drop the socket lock, so we need to lock the call
+        * against interference by sendmsg.
+        */
+       if (!mutex_trylock(&call->user_mutex)) {
+               ret = -EWOULDBLOCK;
+               if (flags & MSG_DONTWAIT)
+                       goto error_requeue_call;
+               ret = -ERESTARTSYS;
+               if (mutex_lock_interruptible(&call->user_mutex) < 0)
+                       goto error_requeue_call;
+       }
+       release_sock(&rx->sk);
        if (test_bit(RXRPC_CALL_RELEASED, &call->flags))
                BUG();
  
                                       &call->user_call_ID);
                }
                if (ret < 0)
-                       goto error;
+                       goto error_unlock_call;
        }
  
        if (msg->msg_name) {
        }
  
        if (ret < 0)
-               goto error;
+               goto error_unlock_call;
  
        if (call->state == RXRPC_CALL_COMPLETE) {
                ret = rxrpc_recvmsg_term(call, msg);
                if (ret < 0)
-                       goto error;
+                       goto error_unlock_call;
                if (!(flags & MSG_PEEK))
                        rxrpc_release_call(rx, call);
                msg->msg_flags |= MSG_EOR;
                msg->msg_flags &= ~MSG_MORE;
        ret = copied;
  
- error:
+ error_unlock_call:
+       mutex_unlock(&call->user_mutex);
        rxrpc_put_call(call, rxrpc_call_put);
+       trace_rxrpc_recvmsg(call, rxrpc_recvmsg_return, 0, 0, 0, ret);
+       return ret;
+ error_requeue_call:
+       if (!(flags & MSG_PEEK)) {
+               write_lock_bh(&rx->recvmsg_lock);
+               list_add(&call->recvmsg_link, &rx->recvmsg_q);
+               write_unlock_bh(&rx->recvmsg_lock);
+               trace_rxrpc_recvmsg(call, rxrpc_recvmsg_requeue, 0, 0, 0, 0);
+       } else {
+               rxrpc_put_call(call, rxrpc_call_put);
+       }
  error_no_call:
        release_sock(&rx->sk);
        trace_rxrpc_recvmsg(call, rxrpc_recvmsg_return, 0, 0, 0, ret);
@@@ -611,7 -636,7 +638,7 @@@ int rxrpc_kernel_recv_data(struct socke
        iov.iov_len = size - *_offset;
        iov_iter_kvec(&iter, ITER_KVEC | READ, &iov, 1, size - *_offset);
  
-       lock_sock(sock->sk);
+       mutex_lock(&call->user_mutex);
  
        switch (call->state) {
        case RXRPC_CALL_CLIENT_RECV_REPLY:
  read_phase_complete:
        ret = 1;
  out:
-       release_sock(sock->sk);
+       mutex_unlock(&call->user_mutex);
        _leave(" = %d [%zu,%d]", ret, *_offset, *_abort);
        return ret;
  
diff --combined net/rxrpc/sendmsg.c
@@@ -15,8 -15,6 +15,8 @@@
  #include <linux/gfp.h>
  #include <linux/skbuff.h>
  #include <linux/export.h>
 +#include <linux/sched/signal.h>
 +
  #include <net/sock.h>
  #include <net/af_rxrpc.h>
  #include "ar-internal.h"
@@@ -61,9 -59,12 +61,12 @@@ static int rxrpc_wait_for_tx_window(str
                }
  
                trace_rxrpc_transmit(call, rxrpc_transmit_wait);
-               release_sock(&rx->sk);
+               mutex_unlock(&call->user_mutex);
                *timeo = schedule_timeout(*timeo);
-               lock_sock(&rx->sk);
+               if (mutex_lock_interruptible(&call->user_mutex) < 0) {
+                       ret = sock_intr_errno(*timeo);
+                       break;
+               }
        }
  
        remove_wait_queue(&call->waitq, &myself);
@@@ -173,7 -174,7 +176,7 @@@ static void rxrpc_queue_packet(struct r
  /*
   * send data through a socket
   * - must be called in process context
-  * - caller holds the socket locked
+  * - The caller holds the call user access mutex, but not the socket lock.
   */
  static int rxrpc_send_data(struct rxrpc_sock *rx,
                           struct rxrpc_call *call,
@@@ -439,10 -440,13 +442,13 @@@ static int rxrpc_sendmsg_cmsg(struct ms
  
  /*
   * Create a new client call for sendmsg().
+  * - Called with the socket lock held, which it must release.
+  * - If it returns a call, the call's lock will need releasing by the caller.
   */
  static struct rxrpc_call *
  rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg,
                                  unsigned long user_call_ID, bool exclusive)
+       __releases(&rx->sk.sk_lock.slock)
  {
        struct rxrpc_conn_parameters cp;
        struct rxrpc_call *call;
  
        _enter("");
  
-       if (!msg->msg_name)
+       if (!msg->msg_name) {
+               release_sock(&rx->sk);
                return ERR_PTR(-EDESTADDRREQ);
+       }
  
        key = rx->key;
        if (key && !rx->key->payload.data[0])
        cp.exclusive            = rx->exclusive | exclusive;
        cp.service_id           = srx->srx_service;
        call = rxrpc_new_client_call(rx, &cp, srx, user_call_ID, GFP_KERNEL);
+       /* The socket is now unlocked */
  
        _leave(" = %p\n", call);
        return call;
   * - the socket may be either a client socket or a server socket
   */
  int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
+       __releases(&rx->sk.sk_lock.slock)
  {
        enum rxrpc_command cmd;
        struct rxrpc_call *call;
        ret = rxrpc_sendmsg_cmsg(msg, &user_call_ID, &cmd, &abort_code,
                                 &exclusive);
        if (ret < 0)
-               return ret;
+               goto error_release_sock;
  
        if (cmd == RXRPC_CMD_ACCEPT) {
+               ret = -EINVAL;
                if (rx->sk.sk_state != RXRPC_SERVER_LISTENING)
-                       return -EINVAL;
+                       goto error_release_sock;
                call = rxrpc_accept_call(rx, user_call_ID, NULL);
+               /* The socket is now unlocked. */
                if (IS_ERR(call))
                        return PTR_ERR(call);
                rxrpc_put_call(call, rxrpc_call_put);
  
        call = rxrpc_find_call_by_user_ID(rx, user_call_ID);
        if (!call) {
+               ret = -EBADSLT;
                if (cmd != RXRPC_CMD_SEND_DATA)
-                       return -EBADSLT;
+                       goto error_release_sock;
                call = rxrpc_new_client_call_for_sendmsg(rx, msg, user_call_ID,
                                                         exclusive);
+               /* The socket is now unlocked... */
                if (IS_ERR(call))
                        return PTR_ERR(call);
+               /* ... and we have the call lock. */
+       } else {
+               ret = -EBUSY;
+               if (call->state == RXRPC_CALL_UNINITIALISED ||
+                   call->state == RXRPC_CALL_CLIENT_AWAIT_CONN ||
+                   call->state == RXRPC_CALL_SERVER_PREALLOC ||
+                   call->state == RXRPC_CALL_SERVER_SECURING ||
+                   call->state == RXRPC_CALL_SERVER_ACCEPTING)
+                       goto error_release_sock;
+               ret = mutex_lock_interruptible(&call->user_mutex);
+               release_sock(&rx->sk);
+               if (ret < 0) {
+                       ret = -ERESTARTSYS;
+                       goto error_put;
+               }
        }
  
        _debug("CALL %d USR %lx ST %d on CONN %p",
                ret = rxrpc_send_data(rx, call, msg, len);
        }
  
+       mutex_unlock(&call->user_mutex);
+ error_put:
        rxrpc_put_call(call, rxrpc_call_put);
        _leave(" = %d", ret);
        return ret;
+ error_release_sock:
+       release_sock(&rx->sk);
+       return ret;
  }
  
  /**
@@@ -564,7 -598,7 +600,7 @@@ int rxrpc_kernel_send_data(struct socke
        ASSERTCMP(msg->msg_name, ==, NULL);
        ASSERTCMP(msg->msg_control, ==, NULL);
  
-       lock_sock(sock->sk);
+       mutex_lock(&call->user_mutex);
  
        _debug("CALL %d USR %lx ST %d on CONN %p",
               call->debug_id, call->user_call_ID, call->state, call->conn);
                ret = rxrpc_send_data(rxrpc_sk(sock->sk), call, msg, len);
        }
  
-       release_sock(sock->sk);
+       mutex_unlock(&call->user_mutex);
        _leave(" = %d", ret);
        return ret;
  }
@@@ -600,12 -634,12 +636,12 @@@ void rxrpc_kernel_abort_call(struct soc
  {
        _enter("{%d},%d,%d,%s", call->debug_id, abort_code, error, why);
  
-       lock_sock(sock->sk);
+       mutex_lock(&call->user_mutex);
  
        if (rxrpc_abort_call(why, call, 0, abort_code, error))
                rxrpc_send_abort_packet(call);
  
-       release_sock(sock->sk);
+       mutex_unlock(&call->user_mutex);
        _leave("");
  }