Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys Protect ifnet list with psz and psref



details:   https://anonhg.NetBSD.org/src/rev/eee18ea5cfae
branches:  trunk
changeset: 345188:eee18ea5cfae
user:      ozaki-r <ozaki-r%NetBSD.org@localhost>
date:      Thu May 12 02:24:16 2016 +0000

description:
Protect ifnet list with psz and psref

The change ensures that ifnet objects in the ifnet list aren't freed during
list iterations by using pserialize(9) and psref(9).

Note that the change adds a pslist(9) for ifnet but doesn't remove the
original ifnet list (ifnet_list) to avoid breaking kvm(3) users. We
shouldn't use the original list in the kernel anymore.

diffstat:

 sys/altq/altq_subr.c                       |   23 +++-
 sys/arch/x86/x86/vmt.c                     |    7 +-
 sys/compat/common/uipc_syscalls_40.c       |   35 +++++-
 sys/compat/linux/common/linux_socket.c     |   53 ++++++++--
 sys/compat/linux32/common/linux32_socket.c |   51 ++++++++--
 sys/compat/svr4/svr4_sockio.c              |   14 ++-
 sys/compat/svr4_32/svr4_32_sockio.c        |    9 +-
 sys/dev/pci/if_bge.c                       |    9 +-
 sys/dist/pf/net/pf_if.c                    |   35 ++++++-
 sys/kern/kern_subr.c                       |    8 +-
 sys/kern/subr_tftproot.c                   |   12 +-
 sys/kern/uipc_mbuf.c                       |   24 ++++-
 sys/net/if.c                               |  137 ++++++++++++++++++++++------
 sys/net/if.h                               |   59 +++++++++++-
 sys/net/npf/npf_if.c                       |    8 +-
 sys/net/rtsock.c                           |   39 ++++++-
 sys/netinet/ip_carp.c                      |   19 +++-
 sys/netinet/raw_ip.c                       |    8 +-
 sys/netinet/sctp_asconf.c                  |   18 ++-
 sys/netinet/sctp_output.c                  |   55 ++++++++---
 sys/netinet/sctp_pcb.c                     |   13 ++-
 sys/netinet/sctp_usrreq.c                  |   15 ++-
 sys/netinet/sctputil.c                     |   12 +-
 sys/netinet6/icmp6.c                       |   10 +-
 sys/netinet6/in6.c                         |    9 +-
 sys/netinet6/in6_ifattach.c                |   14 ++-
 sys/netinet6/nd6.c                         |   11 +-
 sys/netinet6/raw_ip6.c                     |    8 +-
 sys/netipsec/xform_ipip.c                  |   10 +-
 sys/rump/librump/rumpnet/net_stub.c        |   10 +-
 30 files changed, 558 insertions(+), 177 deletions(-)

diffs (truncated from 2246 to 300 lines):

diff -r fd138124e0ba -r eee18ea5cfae sys/altq/altq_subr.c
--- a/sys/altq/altq_subr.c      Thu May 12 01:56:44 2016 +0000
+++ b/sys/altq/altq_subr.c      Thu May 12 02:24:16 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: altq_subr.c,v 1.30 2016/04/20 08:58:48 knakahara Exp $ */
+/*     $NetBSD: altq_subr.c,v 1.31 2016/05/12 02:24:16 ozaki-r Exp $   */
 /*     $KAME: altq_subr.c,v 1.24 2005/04/13 03:44:25 suz Exp $ */
 
 /*
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: altq_subr.c,v 1.30 2016/04/20 08:58:48 knakahara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: altq_subr.c,v 1.31 2016/05/12 02:24:16 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_altq.h"
@@ -355,15 +355,26 @@
        int active, s;
 
        active = 0;
-       s = splnet();
-       IFNET_FOREACH(ifp) {
+       s = pserialize_read_enter();
+       IFNET_READER_FOREACH(ifp) {
+               struct psref psref;
                if (!TBR_IS_ENABLED(&ifp->if_snd))
                        continue;
+               psref_acquire(&psref, &ifp->if_psref, ifnet_psref_class);
+               pserialize_read_exit(s);
+
                active++;
-               if (!IFQ_IS_EMPTY(&ifp->if_snd) && ifp->if_start != NULL)
+               if (!IFQ_IS_EMPTY(&ifp->if_snd) && ifp->if_start != NULL) {
+                       int _s = splnet();
                        (*ifp->if_start)(ifp);
+                       splx(_s);
+               }
+
+               s = pserialize_read_enter();
+               psref_release(&psref, &ifp->if_psref, ifnet_psref_class);
        }
-       splx(s);
+       pserialize_read_exit(s);
+
        if (active > 0)
                CALLOUT_RESET(&tbr_callout, 1, tbr_timeout, (void *)0);
        else
diff -r fd138124e0ba -r eee18ea5cfae sys/arch/x86/x86/vmt.c
--- a/sys/arch/x86/x86/vmt.c    Thu May 12 01:56:44 2016 +0000
+++ b/sys/arch/x86/x86/vmt.c    Thu May 12 02:24:16 2016 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: vmt.c,v 1.11 2015/04/23 23:23:00 pgoyette Exp $ */
+/* $NetBSD: vmt.c,v 1.12 2016/05/12 02:24:16 ozaki-r Exp $ */
 /* $OpenBSD: vmt.c,v 1.11 2011/01/27 21:29:25 dtucker Exp $ */
 
 /*
@@ -803,10 +803,12 @@
        } else if (strcmp(sc->sc_rpc_buf, "Set_Option broadcastIP 1") == 0) {
                struct ifnet *iface;
                struct sockaddr_in *guest_ip;
+               int s;
 
                /* find first available ipv4 address */
                guest_ip = NULL;
-               IFNET_FOREACH(iface) {
+               s = pserialize_read_enter();
+               IFNET_READER_FOREACH(iface) {
                        struct ifaddr *iface_addr;
 
                        /* skip loopback */
@@ -824,6 +826,7 @@
                                break;
                        }
                }
+               pserialize_read_exit(s);
 
                if (guest_ip != NULL) {
                        if (vm_rpc_send_rpci_tx(sc, "info-set guestinfo.ip %s",
diff -r fd138124e0ba -r eee18ea5cfae sys/compat/common/uipc_syscalls_40.c
--- a/sys/compat/common/uipc_syscalls_40.c      Thu May 12 01:56:44 2016 +0000
+++ b/sys/compat/common/uipc_syscalls_40.c      Thu May 12 02:24:16 2016 +0000
@@ -1,9 +1,9 @@
-/*     $NetBSD: uipc_syscalls_40.c,v 1.8 2014/11/26 09:53:53 ozaki-r Exp $     */
+/*     $NetBSD: uipc_syscalls_40.c,v 1.9 2016/05/12 02:24:16 ozaki-r Exp $     */
 
 /* written by Pavel Cahyna, 2006. Public domain. */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uipc_syscalls_40.c,v 1.8 2014/11/26 09:53:53 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uipc_syscalls_40.c,v 1.9 2016/05/12 02:24:16 ozaki-r Exp $");
 
 /*
  * System call interface to the socket abstraction.
@@ -39,23 +39,33 @@
        int space = 0, error = 0;
        const int sz = (int)sizeof(ifr);
        const bool docopy = ifc->ifc_req != NULL;
+       int s;
+       int bound = curlwp->l_pflag & LP_BOUND;
+       struct psref psref;
 
        if (docopy) {
                space = ifc->ifc_len;
                ifrp = ifc->ifc_req;
        }
 
-       IFNET_FOREACH(ifp) {
+       curlwp->l_pflag |= LP_BOUND;
+       s = pserialize_read_enter();
+       IFNET_READER_FOREACH(ifp) {
+               psref_acquire(&psref, &ifp->if_psref, ifnet_psref_class);
+               pserialize_read_exit(s);
+
                (void)strncpy(ifr.ifr_name, ifp->if_xname,
                    sizeof(ifr.ifr_name));
-               if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0')
-                       return ENAMETOOLONG;
+               if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0') {
+                       error = ENAMETOOLONG;
+                       goto release_exit;
+               }
                if (IFADDR_EMPTY(ifp)) {
                        memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
                        if (space >= sz) {
                                error = copyout(&ifr, ifrp, sz);
                                if (error != 0)
-                                       return (error);
+                                       goto release_exit;
                                ifrp++;
                        }
                        space -= sizeof(ifr);
@@ -103,14 +113,25 @@
                                }
                        }
                        if (error != 0)
-                               return (error);
+                               goto release_exit;
                        space -= sz;
                }
+
+               s = pserialize_read_enter();
+               psref_release(&psref, &ifp->if_psref, ifnet_psref_class);
        }
+       pserialize_read_exit(s);
+       curlwp->l_pflag ^= bound ^ LP_BOUND;
+
        if (docopy)
                ifc->ifc_len -= space;
        else
                ifc->ifc_len = -space;
        return (0);
+
+release_exit:
+       psref_release(&psref, &ifp->if_psref, ifnet_psref_class);
+       curlwp->l_pflag ^= bound ^ LP_BOUND;
+       return error;
 }
 #endif
diff -r fd138124e0ba -r eee18ea5cfae sys/compat/linux/common/linux_socket.c
--- a/sys/compat/linux/common/linux_socket.c    Thu May 12 01:56:44 2016 +0000
+++ b/sys/compat/linux/common/linux_socket.c    Thu May 12 02:24:16 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: linux_socket.c,v 1.126 2015/07/24 13:02:52 maxv Exp $  */
+/*     $NetBSD: linux_socket.c,v 1.127 2016/05/12 02:24:16 ozaki-r Exp $       */
 
 /*-
  * Copyright (c) 1995, 1998, 2008 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: linux_socket.c,v 1.126 2015/07/24 13:02:52 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: linux_socket.c,v 1.127 2016/05/12 02:24:16 ozaki-r Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_inet.h"
@@ -1118,6 +1118,9 @@
        int space = 0, error;
        const int sz = (int)sizeof(ifr);
        bool docopy;
+       int s;
+       int bound = curlwp->l_pflag & LP_BOUND;
+       struct psref psref;
 
        error = copyin(data, &ifc, sizeof(ifc));
        if (error)
@@ -1129,11 +1132,18 @@
                ifrp = ifc.ifc_req;
        }
 
-       IFNET_FOREACH(ifp) {
+       curlwp->l_pflag |= LP_BOUND;
+       s = pserialize_read_enter();
+       IFNET_READER_FOREACH(ifp) {
+               psref_acquire(&psref, &ifp->if_psref, ifnet_psref_class);
+               pserialize_read_exit(s);
+
                (void)strncpy(ifr.ifr_name, ifp->if_xname,
                    sizeof(ifr.ifr_name));
-               if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0')
-                       return ENAMETOOLONG;
+               if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0') {
+                       error = ENAMETOOLONG;
+                       goto release_exit;
+               }
                if (IFADDR_EMPTY(ifp))
                        continue;
                IFADDR_FOREACH(ifa, ifp) {
@@ -1147,12 +1157,17 @@
                        if (space >= sz) {
                                error = copyout(&ifr, ifrp, sz);
                                if (error != 0)
-                                       return error;
+                                       goto release_exit;
                                ifrp++;
                        }
                        space -= sz;
                }
+
+               s = pserialize_read_enter();
+               psref_release(&psref, &ifp->if_psref, ifnet_psref_class);
        }
+       pserialize_read_exit(s);
+       curlwp->l_pflag ^= bound ^ LP_BOUND;
 
        if (docopy)
                ifc.ifc_len -= space;
@@ -1160,6 +1175,11 @@
                ifc.ifc_len = -space;
 
        return copyout(&ifc, data, sizeof(ifc));
+
+release_exit:
+       psref_release(&psref, &ifp->if_psref, ifnet_psref_class);
+       curlwp->l_pflag ^= bound ^ LP_BOUND;
+       return error;
 }
 
 int
@@ -1174,6 +1194,7 @@
        struct sockaddr_dl *sadl;
        int error, found;
        int index, ifnum;
+       int s;
 
        /*
         * We can't emulate this ioctl by calling sys_ioctl() to run
@@ -1205,14 +1226,17 @@
         * Try real interface name first, then fake "ethX"
         */
        found = 0;
-       IFNET_FOREACH(ifp) {
+       s = pserialize_read_enter();
+       IFNET_READER_FOREACH(ifp) {
                if (found)
                        break;
                if (strcmp(lreq.ifr_name, ifp->if_xname))
                        /* not this interface */
                        continue;
+
                found=1;
                if (IFADDR_EMPTY(ifp)) {
+                       pserialize_read_exit(s);
                        error = ENODEV;
                        goto out;
                }
@@ -1228,10 +1252,13 @@
                                   sizeof(lreq.ifr_hwaddr.sa_data)));
                        lreq.ifr_hwaddr.sa_family =
                                sadl->sdl_family;
+                       pserialize_read_exit(s);
+
                        error = copyout(&lreq, data, sizeof(lreq));
                        goto out;
                }
        }
+       pserialize_read_exit(s);
 
        if (strncmp(lreq.ifr_name, "eth", 3) != 0) {
                /* unknown interface, not even an "eth*" name */
@@ -1247,10 +1274,8 @@
        }
 
        error = EINVAL;                 /* in case we don't find one */
-       found = 0;
-       IFNET_FOREACH(ifp) {
-               if (found)
-                       break;
+       s = pserialize_read_enter();
+       IFNET_READER_FOREACH(ifp) {
                memcpy(lreq.ifr_name, ifp->if_xname,
                       MIN(LINUX_IFNAMSIZ, IFNAMSIZ));
                IFADDR_FOREACH(ifa, ifp) {
@@ -1269,11 +1294,13 @@
                                   sizeof(lreq.ifr_hwaddr.sa_data)));
                        lreq.ifr_hwaddr.sa_family =
                                sadl->sdl_family;
+                       pserialize_read_exit(s);



Home | Main Index | Thread Index | Old Index