summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2015-12-09 09:02:03 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2015-12-09 09:02:03 +0000
commit816cc1ea4a069a761e7320a34750e7b7cce27542 (patch)
treedefd19ac9b44d744ffa4214c3b85154b63a1e64a /sys
parent28cba98c93dc1557517753580fce354d9f7a24bd (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.c23
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;
}