diff options
author | Martin Pieuchot <mpi@cvs.openbsd.org> | 2015-12-09 09:02:03 +0000 |
---|---|---|
committer | Martin Pieuchot <mpi@cvs.openbsd.org> | 2015-12-09 09:02:03 +0000 |
commit | 816cc1ea4a069a761e7320a34750e7b7cce27542 (patch) | |
tree | defd19ac9b44d744ffa4214c3b85154b63a1e64a /sys | |
parent | 28cba98c93dc1557517753580fce354d9f7a24bd (diff) |
Do not trigger a KASSERT() when destroying/detaching an interface with
RTF_CLONED routes attached.
In thise case if_get(9) can return NULL inside rtflushclone1() because
ifdetach() starts by clearing the interface pointer in the index map.
So it is perfectly correct to bail and we're not going to leak any route
entry because we're garbage collecting all of them.
Reported by daniel@ and Aaron Miller <aaron DOT miller04 AT gmail DOT com>
Diffstat (limited to 'sys')
-rw-r--r-- | sys/net/route.c | 23 |
1 files changed, 19 insertions, 4 deletions
diff --git a/sys/net/route.c b/sys/net/route.c index 8a922d2873b..814d2644e28 100644 --- a/sys/net/route.c +++ b/sys/net/route.c @@ -1,4 +1,4 @@ -/* $OpenBSD: route.c,v 1.289 2015/12/05 10:07:55 tedu Exp $ */ +/* $OpenBSD: route.c,v 1.290 2015/12/09 09:02:02 mpi Exp $ */ /* $NetBSD: route.c,v 1.14 1996/02/13 22:00:46 christos Exp $ */ /* @@ -645,6 +645,9 @@ rtdeletemsg(struct rtentry *rt, struct ifnet *ifp, u_int tableid) static inline int rtequal(struct rtentry *a, struct rtentry *b) { + if (a == b) + return 1; + if (memcmp(rt_key(a), rt_key(b), rt_key(a)->sa_len) == 0 && rt_plen(a) == rt_plen(b)) return 1; @@ -656,10 +659,22 @@ int rtflushclone1(struct rtentry *rt, void *arg, u_int id) { struct rtentry *parent = arg; + struct ifnet *ifp; - if ((rt->rt_flags & RTF_CLONED) != 0 && (rt->rt_parent == parent || - rtequal(rt->rt_parent, parent))) - rtdeletemsg(rt, NULL, id); + ifp = if_get(rt->rt_ifidx); + + /* + * This happens when an interface with a RTF_CLONING route is + * being detached. In this case it's safe to bail because all + * the routes are being purged by rt_if_remove(). + */ + if (ifp == NULL) + return 0; + + if (ISSET(rt->rt_flags, RTF_CLONED) && rtequal(rt->rt_parent, parent)) + rtdeletemsg(rt, ifp, id); + + if_put(ifp); return 0; } |