If the RDE process dies it takes the session engine along. The problem
is that the ibuf structures to the RDE become invalid but the SE still
tries to send the RDE messages which ends up in tears and SIGSEGV.
Wrap the imsg_compose() to ibuf_rde in a new helper function which does
a NULL check before. Additionally add an extra check in session_stop()
which is called in the exit handler of the SE and is triggering this
in most cases.
OK?
--
:wq Claudio
Index: session.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/session.c,v
retrieving revision 1.366
diff -u -p -r1.366 session.c
--- session.c 4 Sep 2018 12:00:29 -0000 1.366
+++ session.c 19 Sep 2018 12:28:38 -0000
@@ -94,6 +94,7 @@ int capa_neg_calc(struct peer *);
void session_dispatch_imsg(struct imsgbuf *, int, u_int *);
void session_up(struct peer *);
void session_down(struct peer *);
+int imsg_rde(int, u_int32_t, void *, u_int16_t);
void session_demote(struct peer *, int);
int session_link_state_is_up(int, int, int);
@@ -1379,8 +1380,7 @@ session_sendmsg(struct bgp_msg *msg, str
ibuf_close(&p->wbuf, msg->buf);
if (!p->throttled && p->wbuf.queued > SESS_MSG_HIGH_MARK) {
- if (imsg_compose(ibuf_rde, IMSG_XOFF, p->conf.id, 0, -1,
- NULL, 0) == -1)
+ if (imsg_rde(IMSG_XOFF, p->conf.id, NULL, 0) == -1)
log_peer_warn(&p->conf, "imsg_compose XOFF");
p->throttled = 1;
}
@@ -1671,16 +1671,16 @@ session_graceful_restart(struct peer *p)
for (i = 0; i < AID_MAX; i++) {
if (p->capa.neg.grestart.flags[i] & CAPA_GR_PRESENT) {
- if (imsg_compose(ibuf_rde, IMSG_SESSION_STALE,
- p->conf.id, 0, -1, &i, sizeof(i)) == -1)
+ if (imsg_rde(IMSG_SESSION_STALE, p->conf.id,
+ &i, sizeof(i)) == -1)
return (-1);
log_peer_warnx(&p->conf,
"graceful restart of %s, keeping routes",
aid2str(i));
p->capa.neg.grestart.flags[i] |= CAPA_GR_RESTARTING;
} else if (p->capa.neg.mp[i]) {
- if (imsg_compose(ibuf_rde, IMSG_SESSION_FLUSH,
- p->conf.id, 0, -1, &i, sizeof(i)) == -1)
+ if (imsg_rde(IMSG_SESSION_FLUSH, p->conf.id,
+ &i, sizeof(i)) == -1)
return (-1);
log_peer_warnx(&p->conf,
"graceful restart of %s, flushing routes",
@@ -1704,8 +1704,8 @@ session_graceful_stop(struct peer *p)
if (p->capa.neg.grestart.flags[i] & CAPA_GR_RESTARTING) {
log_peer_warnx(&p->conf, "graceful restart of %s, "
"time-out, flushing", aid2str(i));
- if (imsg_compose(ibuf_rde, IMSG_SESSION_FLUSH,
- p->conf.id, 0, -1, &i, sizeof(i)) == -1)
+ if (imsg_rde(IMSG_SESSION_FLUSH, p->conf.id,
+ &i, sizeof(i)) == -1)
return (-1);
}
p->capa.neg.grestart.flags[i] &= ~CAPA_GR_RESTARTING;
@@ -1771,8 +1771,7 @@ session_dispatch_msg(struct pollfd *pfd,
return (1);
}
if (p->throttled && p->wbuf.queued < SESS_MSG_LOW_MARK) {
- if (imsg_compose(ibuf_rde, IMSG_XON, p->conf.id, 0, -1,
- NULL, 0) == -1)
+ if (imsg_rde(IMSG_XON, p->conf.id, NULL, 0) == -1)
log_peer_warn(&p->conf, "imsg_compose XON");
p->throttled = 0;
}
@@ -2183,8 +2182,7 @@ parse_update(struct peer *peer)
p += MSGSIZE_HEADER; /* header is already checked */
datalen -= MSGSIZE_HEADER;
- if (imsg_compose(ibuf_rde, IMSG_UPDATE, peer->conf.id, 0, -1, p,
- datalen) == -1)
+ if (imsg_rde(IMSG_UPDATE, peer->conf.id, p, datalen) == -1)
return (-1);
return (0);
@@ -2221,8 +2219,7 @@ parse_refresh(struct peer *peer)
return (0);
}
- if (imsg_compose(ibuf_rde, IMSG_REFRESH, peer->conf.id, 0, -1, &aid,
- sizeof(aid)) == -1)
+ if (imsg_rde(IMSG_REFRESH, peer->conf.id, &aid, sizeof(aid)) == -1)
return (-1);
return (0);
@@ -2551,8 +2548,8 @@ capa_neg_calc(struct peer *p)
if (negflags & CAPA_GR_RESTARTING) {
if (!(p->capa.peer.grestart.flags[i] &
CAPA_GR_FORWARD)) {
- if (imsg_compose(ibuf_rde, IMSG_SESSION_FLUSH,
- p->conf.id, 0, -1, &i, sizeof(i)) == -1)
+ if (imsg_rde(IMSG_SESSION_FLUSH, p->conf.id,
+ &i, sizeof(i)) == -1)
return (-1);
log_peer_warnx(&p->conf, "graceful restart of "
"%s, not restarted, flushing", aid2str(i));
@@ -2657,9 +2654,8 @@ session_dispatch_imsg(struct imsgbuf *ib
/* sync the RDE in case we keep the peer */
if (reconf == RECONF_KEEP) {
- if (imsg_compose(ibuf_rde, IMSG_SESSION_ADD,
- p->conf.id, 0, -1, &p->conf,
- sizeof(struct peer_config)) == -1)
+ if (imsg_rde(IMSG_SESSION_ADD, p->conf.id,
+ &p->conf, sizeof(struct peer_config)) == -1)
fatalx("imsg_compose error");
if (p->conf.template) {
/* apply the conf to all clones */
@@ -2670,10 +2666,8 @@ session_dispatch_imsg(struct imsgbuf *ib
session_template_clone(np,
NULL, np->conf.id,
np->conf.remote_as);
- if (imsg_compose(ibuf_rde,
- IMSG_SESSION_ADD,
- np->conf.id, 0, -1,
- &np->conf,
+ if (imsg_rde(IMSG_SESSION_ADD,
+ np->conf.id, &np->conf,
sizeof(struct peer_config))
== -1)
fatalx("imsg_compose
error");
@@ -2965,9 +2959,8 @@ session_dispatch_imsg(struct imsgbuf *ib
timer_stop(p, Timer_RestartTimeout);
/* signal back to RDE to cleanup stale routes */
- if (imsg_compose(ibuf_rde,
- IMSG_SESSION_RESTARTED, imsg.hdr.peerid, 0,
- -1, &aid, sizeof(aid)) == -1)
+ if (imsg_rde(IMSG_SESSION_RESTARTED,
+ imsg.hdr.peerid, &aid, sizeof(aid)) == -1)
fatal("imsg_compose: "
"IMSG_SESSION_RESTARTED");
}
@@ -3188,8 +3181,14 @@ session_down(struct peer *peer)
{
bzero(&peer->capa.neg, sizeof(peer->capa.neg));
peer->stats.last_updown = time(NULL);
- if (imsg_compose(ibuf_rde, IMSG_SESSION_DOWN, peer->conf.id, 0, -1,
- NULL, 0) == -1)
+ /*
+ * session_down is called in the exit code path so check
+ * if the RDE is still around, if not there is no need to
+ * send the message.
+ */
+ if (ibuf_rde == NULL)
+ return;
+ if (imsg_rde(IMSG_SESSION_DOWN, peer->conf.id, NULL, 0) == -1)
fatalx("imsg_compose error");
}
@@ -3198,7 +3197,7 @@ session_up(struct peer *p)
{
struct session_up sup;
- if (imsg_compose(ibuf_rde, IMSG_SESSION_ADD, p->conf.id, 0, -1,
+ if (imsg_rde(IMSG_SESSION_ADD, p->conf.id,
&p->conf, sizeof(p->conf)) == -1)
fatalx("imsg_compose error");
@@ -3209,8 +3208,7 @@ session_up(struct peer *p)
sup.short_as = p->short_as;
memcpy(&sup.capa, &p->capa.neg, sizeof(sup.capa));
p->stats.last_updown = time(NULL);
- if (imsg_compose(ibuf_rde, IMSG_SESSION_UP, p->conf.id, 0, -1,
- &sup, sizeof(sup)) == -1)
+ if (imsg_rde(IMSG_SESSION_UP, p->conf.id, &sup, sizeof(sup)) == -1)
fatalx("imsg_compose error");
}
@@ -3224,11 +3222,27 @@ imsg_ctl_parent(int type, u_int32_t peer
int
imsg_ctl_rde(int type, pid_t pid, void *data, u_int16_t datalen)
{
+ if (ibuf_rde_ctl == NULL) {
+ log_warnx("Can't send message %u to RDE, ctl pipe closed",
+ type);
+ return (0);
+ }
/*
* Use control socket to talk to RDE to bypass the queue of the
* regular imsg socket.
*/
return (imsg_compose(ibuf_rde_ctl, type, 0, pid, -1, data, datalen));
+}
+
+int
+imsg_rde(int type, uint32_t peerid, void *data, u_int16_t datalen)
+{
+ if (ibuf_rde == NULL) {
+ log_warnx("Can't send message %u to RDE, pipe closed", type);
+ return (0);
+ }
+
+ return (imsg_compose(ibuf_rde, type, peerid, 0, -1, data, datalen));
}
void