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;