When it comes to reference counting in the receiving path, route entries
act as proxy for interface addresses.  In other words you CANNOT
dereference ``rt->rt_ifa'' after calling rtfree(9).

Diff below fixes that in icmp_reflect(), ok?

Index: netmpls/mpls_input.c
===================================================================
RCS file: /cvs/src/sys/netmpls/mpls_input.c,v
retrieving revision 1.56
diff -u -p -r1.56 mpls_input.c
--- netmpls/mpls_input.c        11 Jul 2016 09:23:06 -0000      1.56
+++ netmpls/mpls_input.c        22 Aug 2016 11:20:48 -0000
@@ -385,8 +385,9 @@ mpls_do_error(struct mbuf *m, int type, 
                        m_freem(m);
                        return (NULL);
                }
-               rtfree(rt);
+               /* It is safe to dereference ``ia'' iff ``rt'' is valid. */
                error = icmp_reflect(m, NULL, ia);
+               rtfree(rt);
                if (error)
                        return (NULL);
 
Index: netinet/ip_icmp.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_icmp.c,v
retrieving revision 1.151
diff -u -p -r1.151 ip_icmp.c
--- netinet/ip_icmp.c   9 Dec 2015 09:27:40 -0000       1.151
+++ netinet/ip_icmp.c   22 Aug 2016 11:21:02 -0000
@@ -702,7 +702,7 @@ icmp_reflect(struct mbuf *m, struct mbuf
        struct ip *ip = mtod(m, struct ip *);
        struct mbuf *opts = NULL;
        struct sockaddr_in sin;
-       struct rtentry *rt;
+       struct rtentry *rt = NULL;
        int optlen = (ip->ip_hl << 2) - sizeof(struct ip);
        u_int rtableid;
 
@@ -733,7 +733,6 @@ icmp_reflect(struct mbuf *m, struct mbuf
                if (rtisvalid(rt) &&
                    ISSET(rt->rt_flags, RTF_LOCAL|RTF_BROADCAST))
                        ia = ifatoia(rt->rt_ifa);
-               rtfree(rt);
        }
 
        /*
@@ -742,6 +741,8 @@ icmp_reflect(struct mbuf *m, struct mbuf
         * drop the packet as there is no path to the host.
         */
        if (ia == NULL) {
+               rtfree(rt);
+
                memset(&sin, 0, sizeof(sin));
                sin.sin_len = sizeof(sin);
                sin.sin_family = AF_INET;
@@ -756,12 +757,14 @@ icmp_reflect(struct mbuf *m, struct mbuf
                }
 
                ia = ifatoia(rt->rt_ifa);
-               rtfree(rt);
        }
 
        ip->ip_dst = ip->ip_src;
-       ip->ip_src = ia->ia_addr.sin_addr;
        ip->ip_ttl = MAXTTL;
+
+       /* It is safe to dereference ``ia'' iff ``rt'' is valid. */
+       ip->ip_src = ia->ia_addr.sin_addr;
+       rtfree(rt);
 
        if (optlen > 0) {
                u_char *cp;

Reply via email to