From ffa398b8d8bac4cf6368fe700466cad4ff12fee8 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sun, 19 Jul 2015 11:39:24 +0200 Subject: [PATCH] BFD: Fixes crash after socket error Thanks to Thomas King for the bugreport. --- proto/bfd/bfd.c | 28 ++++++++++++++++------------ proto/bfd/packets.c | 8 ++++++-- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/proto/bfd/bfd.c b/proto/bfd/bfd.c index 5f089846..7a085791 100644 --- a/proto/bfd/bfd.c +++ b/proto/bfd/bfd.c @@ -43,7 +43,7 @@ * the needs of BFD sessions. When a new session is created, it requests a * proper BFD interface by function bfd_get_iface(), which either finds an * existing one in &iface_list (from &bfd_proto) or allocates a new one. When a - * session is removed, an associated iface is dicharged by bfd_free_iface(). + * session is removed, an associated iface is discharged by bfd_free_iface(). * * BFD requests are the external API for the other protocols. When a protocol * wants a BFD session, it calls bfd_request_session(), which creates a @@ -62,7 +62,7 @@ * configuration (like static routes in the static protocol). BFD neighbors are * handled by BFD protocol like it is a BFD client -- when a BFD neighbor is * ready, the protocol just creates a BFD request like any other protocol. - * + * * The protocol uses a new generic event loop (structure &birdloop) from |io.c|, * which supports sockets, timers and events like the main loop. Timers * (structure &timer2) are new microsecond based timers, while sockets and @@ -129,11 +129,11 @@ static inline void bfd_notify_kick(struct bfd_proto *p); * BFD sessions */ -static void +static void bfd_session_update_state(struct bfd_session *s, uint state, uint diag) { struct bfd_proto *p = s->ifa->bfd; - uint old_state = s->loc_state; + uint old_state = s->loc_state; int notify; if (state == old_state) @@ -201,8 +201,8 @@ bfd_session_control_tx_timer(struct bfd_session *s, int reset) if (s->passive && (s->rem_id == 0)) goto stop; - if (s->rem_demand_mode && - !s->poll_active && + if (s->rem_demand_mode && + !s->poll_active && (s->loc_state == BFD_STATE_UP) && (s->rem_state == BFD_STATE_UP)) goto stop; @@ -303,7 +303,7 @@ bfd_session_process_ctl(struct bfd_session *s, u8 flags, u32 old_tx_int, u32 old bfd_send_ctl(s->ifa->bfd, s, 1); } -static void +static void bfd_session_timeout(struct bfd_session *s) { struct bfd_proto *p = s->ifa->bfd; @@ -353,7 +353,7 @@ bfd_session_set_min_rx(struct bfd_session *s, u32 val) if (val == s->req_min_rx_new) return; - s->req_min_rx_new = val; + s->req_min_rx_new = val; /* Postpone timer update if req_min_rx_int decreases and the session is up */ if ((s->loc_state != BFD_STATE_UP) || (val > s->req_min_rx_int)) @@ -575,9 +575,13 @@ bfd_free_iface(struct bfd_iface *ifa) if (!ifa || --ifa->uc) return; + if (ifa->sk) + { + sk_stop(ifa->sk); + rfree(ifa->sk); + } + rem_node(&ifa->n); - sk_stop(ifa->sk); - rfree(ifa->sk); mb_free(ifa); } @@ -873,7 +877,7 @@ bfd_notify_hook(sock *sk, int len) diag = s->loc_diag; bfd_unlock_sessions(p); - /* FIXME: convert to btime and move to bfd_session_update_state() */ + /* FIXME: convert to btime and move to bfd_session_update_state() */ s->last_state_change = now; s->notify_running = 1; @@ -1092,7 +1096,7 @@ bfd_show_sessions(struct proto *P) /* FIXME: this is thread-unsafe, but perhaps harmless */ state = s->loc_state; diag = s->loc_diag; - ifname = (s->ifa && s->ifa->sk->iface) ? s->ifa->sk->iface->name : "---"; + ifname = (s->ifa && s->ifa->iface) ? s->ifa->iface->name : "---"; tx_int = s->last_tx ? (MAX(s->des_min_tx_int, s->rem_min_rx_int) TO_MS) : 0; timeout = (MAX(s->req_min_rx_int, s->rem_min_tx_int) TO_MS) * s->rem_detect_mult; diff --git a/proto/bfd/packets.c b/proto/bfd/packets.c index b5fd6782..cb40bcda 100644 --- a/proto/bfd/packets.c +++ b/proto/bfd/packets.c @@ -63,9 +63,13 @@ void bfd_send_ctl(struct bfd_proto *p, struct bfd_session *s, int final) { sock *sk = s->ifa->sk; - struct bfd_ctl_packet *pkt = (struct bfd_ctl_packet *) sk->tbuf; + struct bfd_ctl_packet *pkt; char fb[8]; + if (!sk) + return; + + pkt = (struct bfd_ctl_packet *) sk->tbuf; pkt->vdiag = bfd_pack_vdiag(1, s->loc_diag); pkt->flags = bfd_pack_flags(s->loc_state, 0); pkt->detect_mult = s->detect_mult; @@ -139,7 +143,7 @@ bfd_rx_hook(sock *sk, int len) u8 ps = bfd_pkt_get_state(pkt); if (ps > BFD_STATE_DOWN) DROP("invalid init state", ps); - + s = bfd_find_session_by_addr(p, sk->faddr); /* FIXME: better session matching and message */