summaryrefslogtreecommitdiff
path: root/usr.sbin/bgpd/rde_rib.c
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2019-10-29 06:42:06 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2019-10-29 06:42:06 +0000
commit712aaf03f82046e868e464ea1ea5323108a3a303 (patch)
treea12797f29f7f98006a21247b2c4d3e0da7f07222 /usr.sbin/bgpd/rde_rib.c
parente5ad04a5f84365a2087e9dc95bb9c68f97b9fe95 (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/rde_rib.c')
-rw-r--r--usr.sbin/bgpd/rde_rib.c12
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);