On 26/04/15(Sun) 09:36, Remi Locherer wrote:
> >Synopsis: crash on urtwn removal
> >Environment:
> System : OpenBSD 5.7
> Details : OpenBSD 5.7-current (GENERIC.MP) #955: Sat Apr 25
> 20:12:31 MDT 2015
>
> [email protected]:/usr/src/sys/arch/amd64/compile/GENERIC.MP
>
> Architecture: OpenBSD.amd64
> Machine : amd64
>
> >Description:
> Since a couple of month every now and then I'm getting a
> "urtwn0: device timeout". Usually I deal with it by unlugging the
> urtwn device and plug it in again, then run "sh /etc/netstart urtwn0".
>
> Sometimes the systems crashes when I unplug the urtwn device.
>
> Photos from ddb after such a crash:
>
> https://relo.ch/crash_on_urtwn_removal-trace_part1.jpg
> https://relo.ch/crash_on_urtwn_removal-trace_part2.jpg
> https://relo.ch/crash_on_urtwn_removal-ps_part1.jpg
> https://relo.ch/crash_on_urtwn_removal-ps_part2.jpg
> https://relo.ch/crash_on_urtwn_removal-ps_part3.jpg
Hello Remi and thanks for the bug report.
The panic you're seeing might be related to a use after free, I'd be
interested to know if the diff below helps.
Index: netinet6/in6_ifattach.c
===================================================================
RCS file: /cvs/src/sys/netinet6/in6_ifattach.c,v
retrieving revision 1.86
diff -u -p -r1.86 in6_ifattach.c
--- netinet6/in6_ifattach.c 14 Mar 2015 03:38:52 -0000 1.86
+++ netinet6/in6_ifattach.c 27 Apr 2015 08:21:53 -0000
@@ -600,9 +600,6 @@ in6_ifdetach(struct ifnet *ifp)
ip6_mrouter_detach(ifp);
#endif
- /* remove neighbor management table */
- nd6_purge(ifp);
-
/* nuke any of IPv6 addresses we have */
TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrlist, ifa_list, next) {
if (ifa->ifa_addr->sa_family != AF_INET6)
@@ -612,12 +609,8 @@ in6_ifdetach(struct ifnet *ifp)
}
/*
- * remove neighbor management table. we call it twice just to make
- * sure we nuke everything. maybe we need just one call.
- * XXX: since the first call did not release addresses, some prefixes
- * might remain. We should call nd6_purge() again to release the
- * prefixes after removing all addresses above.
- * (Or can we just delay calling nd6_purge until at this point?)
+ * Remove neighbor management table. Must be called after
+ * purging addresses.
*/
nd6_purge(ifp);
Index: netinet6/nd6.c
===================================================================
RCS file: /cvs/src/sys/netinet6/nd6.c,v
retrieving revision 1.134
diff -u -p -r1.134 nd6.c
--- netinet6/nd6.c 17 Apr 2015 11:04:02 -0000 1.134
+++ netinet6/nd6.c 27 Apr 2015 08:24:49 -0000
@@ -590,24 +590,8 @@ nd6_purge(struct ifnet *ifp)
/* Nuke prefix list entries toward ifp */
LIST_FOREACH_SAFE(pr, &nd_prefix, ndpr_entry, npr) {
- if (pr->ndpr_ifp == ifp) {
- /*
- * Because if_detach() does *not* release prefixes
- * while purging addresses the reference count will
- * still be above zero. We therefore reset it to
- * make sure that the prefix really gets purged.
- */
- pr->ndpr_refcnt = 0;
- /*
- * Previously, pr->ndpr_addr is removed as well,
- * but I strongly believe we don't have to do it.
- * nd6_purge() is only called from in6_ifdetach(),
- * which removes all the associated interface addresses
- * by itself.
- * ([email protected] 20010129)
- */
+ if (pr->ndpr_ifp == ifp)
prelist_remove(pr);
- }
}
if (ifp->if_xflags & IFXF_AUTOCONF6) {
Index: netinet6/nd6_rtr.c
===================================================================
RCS file: /cvs/src/sys/netinet6/nd6_rtr.c,v
retrieving revision 1.101
diff -u -p -r1.101 nd6_rtr.c
--- netinet6/nd6_rtr.c 25 Mar 2015 17:39:33 -0000 1.101
+++ netinet6/nd6_rtr.c 27 Apr 2015 08:26:59 -0000
@@ -1452,7 +1452,8 @@ nd6_addr_add(void *prptr)
pfxlist_onlink_check();
/* Decrement prefix refcount now that the task is done. */
- pr->ndpr_refcnt--;
+ if (--pr->ndpr_refcnt == 0)
+ prelist_remove(pr);
splx(s);
}