ospf6d: Prevent use after free

I am seeing a crash of ospf6d with this stack trace:

OSPF6: Received signal 11 at 1636042827 (si_addr 0x0, PC 0x55efc2d09ec2); aborting...
OSPF6: zlog_signal+0x18c                  7fe20c8ca19a     7ffd08035590 /lib/libfrr.so.0 (mapped at 0x7fe20c819000)
OSPF6: core_handler+0xe3                  7fe20c90805e     7ffd080356b0 /lib/libfrr.so.0 (mapped at 0x7fe20c819000)
OSPF6: funlockfile+0x50                   7fe20c7f8140     7ffd08035800 /lib/x86_64-linux-gnu/libpthread.so.0 (mapped at 0x7fe20c7e4000)
OSPF6:     ---- signal ----
OSPF6: ospf6_neighbor_state_change+0xdc     55efc2d09ec2     7ffd08035d90 /usr/lib/frr/ospf6d (mapped at 0x55efc2c8e000)
OSPF6: exchange_done+0x15c                55efc2d0ab4a     7ffd08035dc0 /usr/lib/frr/ospf6d (mapped at 0x55efc2c8e000)
OSPF6: thread_call+0xc2                   7fe20c91ee32     7ffd08035df0 /lib/libfrr.so.0 (mapped at 0x7fe20c819000)
OSPF6: frr_run+0x217                      7fe20c8bf7f3     7ffd08035eb0 /lib/libfrr.so.0 (mapped at 0x7fe20c819000)
OSPF6: main+0xf3                          55efc2cd7573     7ffd08035fc0 /usr/lib/frr/ospf6d (mapped at 0x55efc2c8e000)
OSPF6: __libc_start_main+0xea             7fe20c645d0a     7ffd08036000 /lib/x86_64-linux-gnu/libc.so.6 (mapped at 0x7fe20c61f000)
OSPF6: _start+0x2a                        55efc2cd706a     7ffd080360d0 /usr/lib/frr/ospf6d (mapped at 0x55efc2c8e000)
OSPF6: in thread exchange_done scheduled from ospf6d/ospf6_message.c:2264 ospf6_dbdesc_send_newone()

The stack trace when decoded is:

(gdb) l *(ospf6_neighbor_state_change+0xdc)
0x7bec2 is in ospf6_neighbor_state_change (ospf6d/ospf6_neighbor.c:200).
warning: Source file is more recent than executable.
195				   on->name, ospf6_neighbor_state_str[prev_state],
196				   ospf6_neighbor_state_str[next_state],
197				   ospf6_neighbor_event_string(event));
198		}
199
200		/* Optionally notify about adjacency changes */
201		if (CHECK_FLAG(on->ospf6_if->area->ospf6->config_flags,
202			       OSPF6_LOG_ADJACENCY_CHANGES)
203		    && (CHECK_FLAG(on->ospf6_if->area->ospf6->config_flags,
204				   OSPF6_LOG_ADJACENCY_DETAIL)

OSPFv3 is creating the event without a managing thread and as such
if the event is not run before a deletion event comes in memory
will be freed up and we'll start trying to access memory we should
not.  Modify ospfv3 to track the thread and appropriately stop
it when the memory is deleted or it is no longer need to run
that bit of code.

Signed-off-by: Donald Sharp <sharpd@nvidia.com>
This commit is contained in:
Donald Sharp 2021-11-04 13:00:51 -04:00
parent 77c657fb1f
commit 9318fc6a38
3 changed files with 7 additions and 2 deletions

View File

@ -772,7 +772,8 @@ static void ospf6_dbdesc_recv_master(struct ospf6_header *oh,
/* More bit check */ /* More bit check */
if (!CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_MBIT) if (!CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_MBIT)
&& !CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT)) && !CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT))
thread_add_event(master, exchange_done, on, 0, NULL); thread_add_event(master, exchange_done, on, 0,
&on->thread_exchange_done);
else { else {
thread_add_event(master, ospf6_dbdesc_send_newone, on, 0, thread_add_event(master, ospf6_dbdesc_send_newone, on, 0,
&on->thread_send_dbdesc); &on->thread_send_dbdesc);
@ -2261,7 +2262,8 @@ int ospf6_dbdesc_send_newone(struct thread *thread)
if (!CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT) && /* Slave */ if (!CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT) && /* Slave */
!CHECK_FLAG(on->dbdesc_last.bits, OSPF6_DBDESC_MBIT) !CHECK_FLAG(on->dbdesc_last.bits, OSPF6_DBDESC_MBIT)
&& !CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT)) && !CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT))
thread_add_event(master, exchange_done, on, 0, NULL); thread_add_event(master, exchange_done, on, 0,
&on->thread_exchange_done);
thread_execute(master, ospf6_dbdesc_send, on, 0); thread_execute(master, ospf6_dbdesc_send, on, 0);
return 0; return 0;

View File

@ -168,6 +168,7 @@ void ospf6_neighbor_delete(struct ospf6_neighbor *on)
THREAD_OFF(on->thread_send_lsreq); THREAD_OFF(on->thread_send_lsreq);
THREAD_OFF(on->thread_send_lsupdate); THREAD_OFF(on->thread_send_lsupdate);
THREAD_OFF(on->thread_send_lsack); THREAD_OFF(on->thread_send_lsack);
THREAD_OFF(on->thread_exchange_done);
THREAD_OFF(on->gr_helper_info.t_grace_timer); THREAD_OFF(on->gr_helper_info.t_grace_timer);
bfd_sess_free(&on->bfd_session); bfd_sess_free(&on->bfd_session);
@ -603,6 +604,7 @@ int oneway_received(struct thread *thread)
THREAD_OFF(on->thread_send_lsreq); THREAD_OFF(on->thread_send_lsreq);
THREAD_OFF(on->thread_send_lsupdate); THREAD_OFF(on->thread_send_lsupdate);
THREAD_OFF(on->thread_send_lsack); THREAD_OFF(on->thread_send_lsack);
THREAD_OFF(on->thread_exchange_done);
return 0; return 0;
} }

View File

@ -136,6 +136,7 @@ struct ospf6_neighbor {
struct thread *thread_send_lsreq; struct thread *thread_send_lsreq;
struct thread *thread_send_lsupdate; struct thread *thread_send_lsupdate;
struct thread *thread_send_lsack; struct thread *thread_send_lsack;
struct thread *thread_exchange_done;
/* BFD information */ /* BFD information */
struct bfd_session_params *bfd_session; struct bfd_session_params *bfd_session;