diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2012-07-12 15:59:18 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2012-07-12 15:59:18 +0000 |
commit | e761b5abc1208d6fb62ccf130f29f63baa57535d (patch) | |
tree | e787770b72d6c10564b36b25abe441244b3e2caf /sys/netinet | |
parent | e7b75dcba9f06bc96767d3dd77d10ce73103d1a8 (diff) |
Be way more careful when accessing a possibly cached route in_selectsrc()
since it may already been gone. Fixes panic seen by stsp@ when unplugging
a used USB interface. Tested and OK stsp@
Diffstat (limited to 'sys/netinet')
-rw-r--r-- | sys/netinet/in_pcb.c | 17 |
1 files changed, 8 insertions, 9 deletions
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index c5eda674760..6ae4d9fad94 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in_pcb.c,v 1.126 2012/03/06 12:44:17 claudio Exp $ */ +/* $OpenBSD: in_pcb.c,v 1.127 2012/07/12 15:59:17 claudio Exp $ */ /* $NetBSD: in_pcb.c,v 1.25 1996/02/13 23:41:53 christos Exp $ */ /* @@ -824,16 +824,14 @@ in_selectsrc(struct sockaddr_in *sin, struct route *ro, int soopts, * If route is known or can be allocated now, * our src addr is taken from the i/f, else punt. */ - if (ro->ro_rt && - (satosin(&ro->ro_dst)->sin_addr.s_addr != - sin->sin_addr.s_addr || - soopts & SO_DONTROUTE)) { + if (ro->ro_rt && (!(ro->ro_rt->rt_flags & RTF_UP) || + (satosin(&ro->ro_dst)->sin_addr.s_addr != sin->sin_addr.s_addr || + soopts & SO_DONTROUTE))) { RTFREE(ro->ro_rt); - ro->ro_rt = (struct rtentry *)0; + ro->ro_rt = NULL; } if ((soopts & SO_DONTROUTE) == 0 && /*XXX*/ - (ro->ro_rt == (struct rtentry *)0 || - ro->ro_rt->rt_ifp == (struct ifnet *)0)) { + (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL)) { /* No route yet, so try to acquire one */ ro->ro_dst.sa_family = AF_INET; ro->ro_dst.sa_len = sizeof(struct sockaddr_in); @@ -854,7 +852,8 @@ in_selectsrc(struct sockaddr_in *sin, struct route *ro, int soopts, * unless it is the loopback (in case a route * to our address on another net goes to loopback). */ - if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK)) + if (ro->ro_rt && ro->ro_rt->rt_ifp && + !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK)) ia = ifatoia(ro->ro_rt->rt_ifa); if (ia == 0) { u_int16_t fport = sin->sin_port; |