diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2019-10-29 06:42:06 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2019-10-29 06:42:06 +0000 |
commit | 712aaf03f82046e868e464ea1ea5323108a3a303 (patch) | |
tree | a12797f29f7f98006a21247b2c4d3e0da7f07222 /usr.sbin/bgpd | |
parent | e5ad04a5f84365a2087e9dc95bb9c68f97b9fe95 (diff) |
Fix two cases where the nexthop_runners tail queue can get corrupted.
First by requeuing an element that is already on the list and second
by freeing a nexthop that is still on the list resulting in a use after
free. This should fix bgpd crashes seen by various people.
Problem report including backtrace from benno@
OK benno@
Diffstat (limited to 'usr.sbin/bgpd')
-rw-r--r-- | usr.sbin/bgpd/rde_rib.c | 12 |
1 files changed, 9 insertions, 3 deletions
diff --git a/usr.sbin/bgpd/rde_rib.c b/usr.sbin/bgpd/rde_rib.c index 9dd2d233060..b3d444f4751 100644 --- a/usr.sbin/bgpd/rde_rib.c +++ b/usr.sbin/bgpd/rde_rib.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde_rib.c,v 1.207 2019/09/27 14:50:39 claudio Exp $ */ +/* $OpenBSD: rde_rib.c,v 1.208 2019/10/29 06:42:05 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> @@ -1777,13 +1777,15 @@ nexthop_update(struct kroute_nexthop *msg) if (nexthop_unref(nh)) return; /* nh lost last ref, no work left */ - if (nh->next_prefix) + if (nh->next_prefix) { /* * If nexthop_runner() is not finished with this nexthop * then ensure that all prefixes are updated by setting * the oldstate to NEXTHOP_FLAPPED. */ nh->oldstate = NEXTHOP_FLAPPED; + TAILQ_REMOVE(&nexthop_runners, nh, runner_l); + } if (msg->connected) { nh->flags |= NEXTHOP_CONNECTED; @@ -1855,8 +1857,12 @@ nexthop_unlink(struct prefix *p) if (p->nexthop == NULL || (p->flags & PREFIX_NEXTHOP_LINKED) == 0) return; - if (p == p->nexthop->next_prefix) + if (p == p->nexthop->next_prefix) { p->nexthop->next_prefix = LIST_NEXT(p, entry.list.nexthop); + /* remove nexthop from list if no prefixes left to update */ + if (p->nexthop->next_prefix == NULL) + TAILQ_REMOVE(&nexthop_runners, p->nexthop, runner_l); + } p->flags &= ~PREFIX_NEXTHOP_LINKED; LIST_REMOVE(p, entry.list.nexthop); |