Source-Changes-HG archive

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

[src/trunk]: src/sys/net Protect ifp returned from route_output_get_ifa surely



details:   https://anonhg.NetBSD.org/src/rev/84867b70d82e
branches:  trunk
changeset: 358144:84867b70d82e
user:      ozaki-r <ozaki-r%NetBSD.org@localhost>
date:      Thu Dec 14 05:47:45 2017 +0000

description:
Protect ifp returned from route_output_get_ifa surely

An ifp returned from route_output_get_ifa was supposed to be protected
by a returned ifa; if the ifa belongs to ifp, holding the ifa prevents
the ifp from being freed. However route_output_get_ifa can return an ifp
to which a returned ifa doesn't belong. So we need to take a reference
to a returning ifp separately.

diffstat:

 sys/net/rtsock.c |  22 ++++++++++++++++------
 1 files changed, 16 insertions(+), 6 deletions(-)

diffs (86 lines):

diff -r 9cf7e999cc48 -r 84867b70d82e sys/net/rtsock.c
--- a/sys/net/rtsock.c  Thu Dec 14 05:46:54 2017 +0000
+++ b/sys/net/rtsock.c  Thu Dec 14 05:47:45 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: rtsock.c,v 1.232 2017/12/14 05:43:14 ozaki-r Exp $     */
+/*     $NetBSD: rtsock.c,v 1.233 2017/12/14 05:47:45 ozaki-r Exp $     */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rtsock.c,v 1.232 2017/12/14 05:43:14 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rtsock.c,v 1.233 2017/12/14 05:47:45 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -608,7 +608,7 @@
 
 static struct ifaddr * __noinline
 route_output_get_ifa(const struct rt_addrinfo info, const struct rtentry *rt,
-    struct ifnet **ifp, struct psref *psref)
+    struct ifnet **ifp, struct psref *psref_ifp, struct psref *psref)
 {
        struct ifaddr *ifa = NULL;
 
@@ -618,6 +618,7 @@
                if (ifa == NULL)
                        goto next;
                *ifp = ifa->ifa_ifp;
+               if_acquire(*ifp, psref_ifp);
                if (info.rti_info[RTAX_IFA] == NULL &&
                    info.rti_info[RTAX_GATEWAY] == NULL)
                        goto next;
@@ -648,8 +649,14 @@
                    info.rti_info[RTAX_GATEWAY], psref);
        }
 out:
-       if (ifa != NULL && *ifp == NULL)
+       if (ifa != NULL && *ifp == NULL) {
                *ifp = ifa->ifa_ifp;
+               if_acquire(*ifp, psref_ifp);
+       }
+       if (ifa == NULL && *ifp != NULL) {
+               if_put(*ifp, psref_ifp);
+               *ifp = NULL;
+       }
        return ifa;
 }
 
@@ -660,7 +667,7 @@
        int error = 0;
        struct ifnet *ifp = NULL, *new_ifp;
        struct ifaddr *ifa = NULL, *new_ifa;
-       struct psref psref_ifa, psref_new_ifa, psref_ifp;
+       struct psref psref_ifa, psref_new_ifa, psref_ifp, psref_new_ifp;
        bool newgw, ifp_changed = false;
 
        /*
@@ -674,6 +681,7 @@
        if (newgw || info->rti_info[RTAX_IFP] != NULL ||
            info->rti_info[RTAX_IFA] != NULL) {
                ifp = rt_getifp(info, &psref_ifp);
+               /* info refers ifp so we need to keep a reference */
                ifa = rt_getifa(info, &psref_ifa);
                if (ifa == NULL) {
                        error = ENETUNREACH;
@@ -698,7 +706,8 @@
         * flags may also be different; ifp may be specified
         * by ll sockaddr when protocol address is ambiguous
         */
-       new_ifa = route_output_get_ifa(*info, rt, &new_ifp, &psref_new_ifa);
+       new_ifa = route_output_get_ifa(*info, rt, &new_ifp, &psref_new_ifp,
+           &psref_new_ifa);
        if (new_ifa != NULL) {
                ifa_release(ifa, &psref_ifa);
                ifa = new_ifa;
@@ -736,6 +745,7 @@
        (void)ifp_changed; /* XXX gcc */
 #endif
 out:
+       if_put(new_ifp, &psref_new_ifp);
        if_put(ifp, &psref_ifp);
 
        return error;



Home | Main Index | Thread Index | Old Index