Skip to content

Commit 68cd2a2

Browse files
committed
zebra: Fix use after free in rib_process_result
Running zebra after commit 888756b in valgrind produces this item: ==17102== Invalid read of size 8 ==17102== at 0x44D84C: rib_dest_from_rnode (rib.h:375) ==17102== by 0x4546ED: rib_process_result (zebra_rib.c:1904) ==17102== by 0x45436D: rib_process_dplane_results (zebra_rib.c:3295) ==17102== by 0x4D0902B: thread_call (thread.c:1607) ==17102== by 0x4CC3983: frr_run (libfrr.c:1011) ==17102== by 0x4266F6: main (main.c:473) ==17102== Address 0x83bd468 is 88 bytes inside a block of size 96 free'd ==17102== at 0x4A35F54: free (vg_replace_malloc.c:530) ==17102== by 0x4CCAC00: qfree (memory.c:129) ==17102== by 0x4D03DC6: route_node_destroy (table.c:501) ==17102== by 0x4D039EE: route_node_free (table.c:90) ==17102== by 0x4D03971: route_node_delete (table.c:382) ==17102== by 0x44D82A: route_unlock_node (table.h:256) ==17102== by 0x454617: rib_process_result (zebra_rib.c:1882) ==17102== by 0x45436D: rib_process_dplane_results (zebra_rib.c:3295) ==17102== by 0x4D0902B: thread_call (thread.c:1607) ==17102== by 0x4CC3983: frr_run (libfrr.c:1011) ==17102== by 0x4266F6: main (main.c:473) ==17102== Block was alloc'd at ==17102== at 0x4A36FF6: calloc (vg_replace_malloc.c:752) ==17102== by 0x4CCAA2D: qcalloc (memory.c:110) ==17102== by 0x4D03D88: route_node_create (table.c:489) ==17102== by 0x4D0360F: route_node_new (table.c:65) ==17102== by 0x4D034F8: route_node_set (table.c:74) ==17102== by 0x4D03486: route_node_get (table.c:327) ==17102== by 0x4CFB700: srcdest_rnode_get (srcdest_table.c:243) ==17102== by 0x4545C1: rib_process_result (zebra_rib.c:1872) ==17102== by 0x45436D: rib_process_dplane_results (zebra_rib.c:3295) ==17102== by 0x4D0902B: thread_call (thread.c:1607) ==17102== by 0x4CC3983: frr_run (libfrr.c:1011) ==17102== by 0x4266F6: main (main.c:473) ==17102== This is happening because of this order of events: 1) Route is deleted in the main thread and scheduled for rib processing. 2) Rib garbage collection is run and we remove the route node since it is no longer needed. 3) Data plane returns from the deletion in the kernel and we call the srcdest_rnode_get function to get the prefix that was deleted. This recreates a new route node. This creates a route_node with a lock count of 1, which we freed via the route_unlock_node call. Then we continued to use the rn pointer. Which leaves us with use after frees. The solution is, of course, to just move the unlock the node at the end of the function if we have a route_node. Fixes: #3854 Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
1 parent 6c74ad5 commit 68cd2a2

File tree

1 file changed

+3
-2
lines changed

1 file changed

+3
-2
lines changed

zebra/zebra_rib.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1860,8 +1860,6 @@ static void rib_process_after(struct zebra_dplane_ctx *ctx)
18601860
goto done;
18611861
}
18621862

1863-
route_unlock_node(rn);
1864-
18651863
srcdest_rnode_prefixes(rn, &dest_pfx, &src_pfx);
18661864

18671865
op = dplane_ctx_get_op(ctx);
@@ -2011,6 +2009,9 @@ static void rib_process_after(struct zebra_dplane_ctx *ctx)
20112009

20122010
done:
20132011

2012+
if (rn)
2013+
route_unlock_node(rn);
2014+
20142015
/* Return context to dataplane module */
20152016
dplane_ctx_fini(&ctx);
20162017
}

0 commit comments

Comments
 (0)