summaryrefslogtreecommitdiff
path: root/sys/net
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2019-06-21 17:11:44 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2019-06-21 17:11:44 +0000
commitfb482f64f911b7fca87d82ac917a331783e5915c (patch)
tree5de16192a2d5c2016a8f06548095348d71e6ebdf /sys/net
parentd54cd84095c832ef5111a5e80e44ec90ec860873 (diff)
Prevent recursions by not deleting entries inside rtable_walk(9).
rtable_walk(9) now passes a routing entry back to the caller when a non zero value is returned and if it asked for it. This allows us to call rtdeletemsg()/rtrequest_delete() from the caller without creating a recursion because of rtflushclone(). Multicast code hasn't been adapted and is still possibly creating recursions. However multicast route entries aren't cloned so if a recursion exists it isn't because of rtflushclone(). Fix stack exhaustion triggered by the use of "-msave-args". Issue reported by Dániel Lévai on bugs@ confirmed by and ok bluhm@.
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/if_spppsubr.c4
-rw-r--r--sys/net/route.c114
-rw-r--r--sys/net/route.h6
-rw-r--r--sys/net/rtable.c16
-rw-r--r--sys/net/rtable.h4
-rw-r--r--sys/net/rtsock.c7
6 files changed, 99 insertions, 52 deletions
diff --git a/sys/net/if_spppsubr.c b/sys/net/if_spppsubr.c
index c7c283e2480..4627e18ba9b 100644
--- a/sys/net/if_spppsubr.c
+++ b/sys/net/if_spppsubr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_spppsubr.c,v 1.174 2018/02/19 08:59:52 mpi Exp $ */
+/* $OpenBSD: if_spppsubr.c,v 1.175 2019/06/21 17:11:42 mpi Exp $ */
/*
* Synchronous PPP link level subroutines.
*
@@ -4167,7 +4167,7 @@ sppp_update_gw(struct ifnet *ifp)
/* update routing table */
for (tid = 0; tid <= RT_TABLEID_MAX; tid++) {
- rtable_walk(tid, AF_INET, sppp_update_gw_walker, ifp);
+ rtable_walk(tid, AF_INET, NULL, sppp_update_gw_walker, ifp);
}
}
diff --git a/sys/net/route.c b/sys/net/route.c
index 2cde81661a7..b87a31ab789 100644
--- a/sys/net/route.c
+++ b/sys/net/route.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: route.c,v 1.385 2019/06/13 08:12:10 claudio Exp $ */
+/* $OpenBSD: route.c,v 1.386 2019/06/21 17:11:42 mpi Exp $ */
/* $NetBSD: route.c,v 1.14 1996/02/13 22:00:46 christos Exp $ */
/*
@@ -156,7 +156,7 @@ void rt_timer_init(void);
int rt_setgwroute(struct rtentry *, u_int);
void rt_putgwroute(struct rtentry *);
int rtflushclone1(struct rtentry *, void *, u_int);
-void rtflushclone(unsigned int, struct rtentry *);
+int rtflushclone(struct ifnet *ifp, struct rtentry *, unsigned int);
int rt_ifa_purge_walker(struct rtentry *, void *, unsigned int);
struct rtentry *rt_match(struct sockaddr *, uint32_t *, int, unsigned int);
int rt_clone(struct rtentry **, struct sockaddr *, unsigned int);
@@ -702,7 +702,6 @@ rtflushclone1(struct rtentry *rt, void *arg, u_int id)
{
struct rtentry *cloningrt = arg;
struct ifnet *ifp;
- int error;
if (!ISSET(rt->rt_flags, RTF_CLONED))
return 0;
@@ -722,23 +721,35 @@ rtflushclone1(struct rtentry *rt, void *arg, u_int id)
if (ifp == NULL)
return 0;
- error = rtdeletemsg(rt, ifp, id);
- if (error == 0)
- error = EAGAIN;
-
if_put(ifp);
- return error;
+ return EEXIST;
}
-void
-rtflushclone(unsigned int rtableid, struct rtentry *parent)
+int
+rtflushclone(struct ifnet *ifp, struct rtentry *parent, unsigned int rtableid)
{
+ struct rtentry *rt = NULL;
+ int error;
#ifdef DIAGNOSTIC
if (!parent || (parent->rt_flags & RTF_CLONING) == 0)
panic("rtflushclone: called with a non-cloning route");
#endif
- rtable_walk(rtableid, rt_key(parent)->sa_family, rtflushclone1, parent);
+
+ do {
+ error = rtable_walk(rtableid, rt_key(parent)->sa_family, &rt,
+ rtflushclone1, parent);
+ if (rt != NULL && error == EEXIST) {
+ error = rtdeletemsg(rt, ifp, rtableid);
+ if (error == 0)
+ error = EAGAIN;
+ }
+ rtfree(rt);
+ rt = NULL;
+ } while (error == EAGAIN);
+
+ return error;
+
}
int
@@ -780,7 +791,7 @@ rtrequest_delete(struct rt_addrinfo *info, u_int8_t prio, struct ifnet *ifp,
/* Clean up any cloned children. */
if (ISSET(rt->rt_flags, RTF_CLONING))
- rtflushclone(tableid, rt);
+ rtflushclone(ifp, rt, tableid);
rtfree(rt->rt_parent);
rt->rt_parent = NULL;
@@ -1284,12 +1295,13 @@ rt_ifa_dellocal(struct ifaddr *ifa)
/*
* Remove all addresses attached to ``ifa''.
*/
-void
+int
rt_ifa_purge(struct ifaddr *ifa)
{
struct ifnet *ifp = ifa->ifa_ifp;
+ struct rtentry *rt = NULL;
unsigned int rtableid;
- int i;
+ int error, af = ifa->ifa_addr->sa_family;
KASSERT(ifp != NULL);
@@ -1297,27 +1309,38 @@ rt_ifa_purge(struct ifaddr *ifa)
/* skip rtables that are not in the rdomain of the ifp */
if (rtable_l2(rtableid) != ifp->if_rdomain)
continue;
- for (i = 1; i <= AF_MAX; i++) {
- rtable_walk(rtableid, i, rt_ifa_purge_walker, ifa);
- }
+
+ do {
+ error = rtable_walk(rtableid, af, &rt,
+ rt_ifa_purge_walker, ifa);
+ if (rt != NULL && error == EEXIST) {
+ error = rtdeletemsg(rt, ifp, rtableid);
+ if (error == 0)
+ error = EAGAIN;
+ }
+ rtfree(rt);
+ rt = NULL;
+ } while (error == EAGAIN);
+
+ if (error == EAFNOSUPPORT)
+ error = 0;
+
+ if (error)
+ break;
}
+
+ return error;
}
int
rt_ifa_purge_walker(struct rtentry *rt, void *vifa, unsigned int rtableid)
{
struct ifaddr *ifa = vifa;
- struct ifnet *ifp = ifa->ifa_ifp;
- int error;
-
- if (rt->rt_ifa != ifa)
- return (0);
- if ((error = rtdeletemsg(rt, ifp, rtableid))) {
- return (error);
- }
+ if (rt->rt_ifa == ifa)
+ return EEXIST;
- return (EAGAIN);
+ return 0;
}
/*
@@ -1639,23 +1662,42 @@ rtlabel_unref(u_int16_t id)
}
}
-void
+int
rt_if_track(struct ifnet *ifp)
{
- int i;
- u_int tid;
+ unsigned int rtableid;
+ struct rtentry *rt = NULL;
+ int i, error;
- for (tid = 0; tid < rtmap_limit; tid++) {
+ for (rtableid = 0; rtableid < rtmap_limit; rtableid++) {
/* skip rtables that are not in the rdomain of the ifp */
- if (rtable_l2(tid) != ifp->if_rdomain)
+ if (rtable_l2(rtableid) != ifp->if_rdomain)
continue;
for (i = 1; i <= AF_MAX; i++) {
- if (!rtable_mpath_capable(tid, i))
+ if (!rtable_mpath_capable(rtableid, i))
continue;
- rtable_walk(tid, i, rt_if_linkstate_change, ifp);
+ do {
+ error = rtable_walk(rtableid, i, &rt,
+ rt_if_linkstate_change, ifp);
+ if (rt != NULL && error == EEXIST) {
+ error = rtdeletemsg(rt, ifp, rtableid);
+ if (error == 0)
+ error = EAGAIN;
+ }
+ rtfree(rt);
+ rt = NULL;
+ } while (error == EAGAIN);
+
+ if (error == EAFNOSUPPORT)
+ error = 0;
+
+ if (error)
+ break;
}
}
+
+ return (error);
}
int
@@ -1690,9 +1732,7 @@ rt_if_linkstate_change(struct rtentry *rt, void *arg, u_int id)
*/
if (ISSET(rt->rt_flags, RTF_CLONED|RTF_DYNAMIC) &&
!ISSET(rt->rt_flags, RTF_CACHED|RTF_BFD)) {
- if ((error = rtdeletemsg(rt, ifp, id)))
- return (error);
- return (EAGAIN);
+ return (EEXIST);
}
if (!ISSET(rt->rt_flags, RTF_UP))
@@ -1823,7 +1863,7 @@ int
db_show_arptab(void)
{
db_printf("Route tree for AF_INET\n");
- rtable_walk(0, AF_INET, db_show_rtentry, NULL);
+ rtable_walk(0, AF_INET, NULL, db_show_rtentry, NULL);
return (0);
}
#endif /* DDB */
diff --git a/sys/net/route.h b/sys/net/route.h
index 93ed426607c..f116002d058 100644
--- a/sys/net/route.h
+++ b/sys/net/route.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: route.h,v 1.175 2019/04/28 17:59:51 mpi Exp $ */
+/* $OpenBSD: route.h,v 1.176 2019/06/21 17:11:42 mpi Exp $ */
/* $NetBSD: route.h,v 1.9 1996/02/13 22:00:49 christos Exp $ */
/*
@@ -451,7 +451,7 @@ void rtfree(struct rtentry *);
int rt_ifa_add(struct ifaddr *, int, struct sockaddr *, unsigned int);
int rt_ifa_del(struct ifaddr *, int, struct sockaddr *, unsigned int);
-void rt_ifa_purge(struct ifaddr *);
+int rt_ifa_purge(struct ifaddr *);
int rt_ifa_addlocal(struct ifaddr *);
int rt_ifa_dellocal(struct ifaddr *);
void rtredirect(struct sockaddr *, struct sockaddr *, struct sockaddr *, struct rtentry **, unsigned int);
@@ -459,7 +459,7 @@ int rtrequest(int, struct rt_addrinfo *, u_int8_t, struct rtentry **,
u_int);
int rtrequest_delete(struct rt_addrinfo *, u_int8_t, struct ifnet *,
struct rtentry **, u_int);
-void rt_if_track(struct ifnet *);
+int rt_if_track(struct ifnet *);
int rt_if_linkstate_change(struct rtentry *, void *, u_int);
int rtdeletemsg(struct rtentry *, struct ifnet *, u_int);
#endif /* _KERNEL */
diff --git a/sys/net/rtable.c b/sys/net/rtable.c
index 092d53b265f..ec57747f447 100644
--- a/sys/net/rtable.c
+++ b/sys/net/rtable.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtable.c,v 1.68 2019/03/05 19:07:56 anton Exp $ */
+/* $OpenBSD: rtable.c,v 1.69 2019/06/21 17:11:42 mpi Exp $ */
/*
* Copyright (c) 2014-2016 Martin Pieuchot
@@ -664,6 +664,7 @@ leave:
struct rtable_walk_cookie {
int (*rwc_func)(struct rtentry *, void *, unsigned int);
void *rwc_arg;
+ struct rtentry **rwc_prt;
unsigned int rwc_rid;
};
@@ -679,16 +680,21 @@ rtable_walk_helper(struct art_node *an, void *xrwc)
int error = 0;
SRPL_FOREACH(rt, &sr, &an->an_rtlist, rt_next) {
- if ((error = (*rwc->rwc_func)(rt, rwc->rwc_arg, rwc->rwc_rid)))
+ error = (*rwc->rwc_func)(rt, rwc->rwc_arg, rwc->rwc_rid);
+ if (error != 0)
break;
}
+ if (rwc->rwc_prt != NULL && rt != NULL) {
+ rtref(rt);
+ *rwc->rwc_prt = rt;
+ }
SRPL_LEAVE(&sr);
return (error);
}
int
-rtable_walk(unsigned int rtableid, sa_family_t af,
+rtable_walk(unsigned int rtableid, sa_family_t af, struct rtentry **prt,
int (*func)(struct rtentry *, void *, unsigned int), void *arg)
{
struct art_root *ar;
@@ -701,10 +707,10 @@ rtable_walk(unsigned int rtableid, sa_family_t af,
rwc.rwc_func = func;
rwc.rwc_arg = arg;
+ rwc.rwc_prt = prt;
rwc.rwc_rid = rtableid;
- while ((error = art_walk(ar, rtable_walk_helper, &rwc)) == EAGAIN)
- continue;
+ error = art_walk(ar, rtable_walk_helper, &rwc);
return (error);
}
diff --git a/sys/net/rtable.h b/sys/net/rtable.h
index 69909cf9a55..c492d684739 100644
--- a/sys/net/rtable.h
+++ b/sys/net/rtable.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtable.h,v 1.23 2019/04/28 17:59:51 mpi Exp $ */
+/* $OpenBSD: rtable.h,v 1.24 2019/06/21 17:11:42 mpi Exp $ */
/*
* Copyright (c) 2014-2016 Martin Pieuchot
@@ -48,7 +48,7 @@ int rtable_insert(unsigned int, struct sockaddr *,
struct rtentry *);
int rtable_delete(unsigned int, struct sockaddr *,
struct sockaddr *, struct rtentry *);
-int rtable_walk(unsigned int, sa_family_t,
+int rtable_walk(unsigned int, sa_family_t, struct rtentry **,
int (*)(struct rtentry *, void *, unsigned int), void *);
int rtable_mpath_capable(unsigned int, sa_family_t);
diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c
index 457211c2a7e..bd43a731387 100644
--- a/sys/net/rtsock.c
+++ b/sys/net/rtsock.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtsock.c,v 1.287 2019/06/05 12:53:43 claudio Exp $ */
+/* $OpenBSD: rtsock.c,v 1.288 2019/06/21 17:11:42 mpi Exp $ */
/* $NetBSD: rtsock.c,v 1.18 1996/03/29 00:32:10 cgd Exp $ */
/*
@@ -931,7 +931,7 @@ rtm_output(struct rt_msghdr *rtm, struct rtentry **prt,
NET_LOCK();
ifp->if_rtrequest(ifp, RTM_INVALIDATE, rt);
/* Reset the MTU of the gateway route. */
- rtable_walk(tableid, rt_key(rt)->sa_family,
+ rtable_walk(tableid, rt_key(rt)->sa_family, NULL,
route_cleargateway, rt);
NET_UNLOCK();
if_put(ifp);
@@ -1911,7 +1911,8 @@ sysctl_rtable(int *name, u_int namelen, void *where, size_t *given, void *new,
if (af != 0 && af != i)
continue;
- error = rtable_walk(tableid, i, sysctl_dumpentry, &w);
+ error = rtable_walk(tableid, i, NULL, sysctl_dumpentry,
+ &w);
if (error == EAFNOSUPPORT)
error = 0;
if (error)