Applied On Thu, 2020-01-16 at 23:16 -0800, Brian Gix wrote: > Any packet that may be handled internally by the daemon must be sent in > it's own idle_oneshot context, to prevent multiple nodes from handling > and responding in the same context, eventually corrupting memory. > > This addresses the following crash: > Program terminated with signal SIGSEGV, Segmentation fault. > 0 tcache_get (tc_idx=0) at malloc.c:2951 > 2951 tcache->entries[tc_idx] = e->next; > (gdb) bt > 0 tcache_get (tc_idx=0) at malloc.c:2951 > 1 __GI___libc_malloc (bytes=bytes@entry=16) at malloc.c:3058 > 2 0x0000564cff9bc1de in l_malloc (size=size@entry=16) at ell/util.c:62 > 3 0x0000564cff9bd46b in l_queue_push_tail (queue=0x564d000c9710, data=data@entry=0x564d000d0d60) at > ell/queue.c:136 > 4 0x0000564cff9beabd in idle_add (callback=callback@entry=0x564cff9be4e0 <oneshot_callback>, > user_data=user_data@entry=0x564d000d4700, > flags=flags@entry=268435456, destroy=destroy@entry=0x564cff9be4c0 <idle_destroy>) at ell/main.c:292 > 5 0x0000564cff9be5f7 in l_idle_oneshot (callback=callback@entry=0x564cff998bc0 <tx_worker>, > user_data=user_data@entry=0x564d000d83f0, > destroy=destroy@entry=0x0) at ell/idle.c:144 > 6 0x0000564cff998326 in send_tx (io=<optimized out>, info=0x7ffd035503f4, data=<optimized out>, > len=<optimized out>) > at mesh/mesh-io-generic.c:637 > 7 0x0000564cff99675a in send_network_beacon (key=0x564d000cfee0) at mesh/net-keys.c:355 > 8 snb_timeout (timeout=0x564d000dd730, user_data=0x564d000cfee0) at mesh/net-keys.c:364 > 9 0x0000564cff9bdca2 in timeout_callback (fd=<optimized out>, events=<optimized out>, > user_data=0x564d000dd730) at ell/timeout.c:81 > 10 timeout_callback (fd=<optimized out>, events=<optimized out>, user_data=0x564d000dd730) at > ell/timeout.c:70 > 11 0x0000564cff9bedcd in l_main_iterate (timeout=<optimized out>) at ell/main.c:473 > 12 0x0000564cff9bee7c in l_main_run () at ell/main.c:520 > 13 l_main_run () at ell/main.c:502 > 14 0x0000564cff9bf08c in l_main_run_with_signal (callback=<optimized out>, user_data=0x0) at ell/main.c:642 > 15 0x0000564cff994b64 in main (argc=<optimized out>, argv=0x7ffd03550668) at mesh/main.c:268 > --- > mesh/net.c | 50 +++++++++++++++++++++++++++++++++++++------------- > 1 file changed, 37 insertions(+), 13 deletions(-) > > diff --git a/mesh/net.c b/mesh/net.c > index 35388beec..219217793 100644 > --- a/mesh/net.c > +++ b/mesh/net.c > @@ -241,6 +241,12 @@ struct net_queue_data { > bool seen; > }; > > +struct oneshot_tx { > + struct mesh_net *net; > + uint8_t size; > + uint8_t packet[30]; > +}; > + > struct net_beacon_data { > uint32_t key_id; > uint32_t ivi; > @@ -2247,24 +2253,35 @@ static void send_relay_pkt(struct mesh_net *net, uint8_t *data, uint8_t size) > mesh_io_send(io, &info, packet, size + 1); > } > > -static void send_msg_pkt(struct mesh_net *net, uint8_t *packet, uint8_t size) > +static bool simple_match(const void *a, const void *b) > { > - struct mesh_io *io = net->io; > + return a == b; > +} > + > +static void send_msg_pkt_oneshot(void *user_data) > +{ > + struct oneshot_tx *tx = user_data; > + struct mesh_net *net; > struct mesh_io_send_info info; > struct net_queue_data net_data = { > .info = NULL, > - .data = packet + 1, > - .len = size - 1, > + .data = tx->packet + 1, > + .len = tx->size - 1, > .relay_advice = RELAY_NONE, > }; > > /* Send to local nodes first */ > l_queue_foreach(nets, net_rx, &net_data); > > - if (net_data.relay_advice == RELAY_DISALLOWED) > + /* Make sure specific network still valid */ > + net = l_queue_find(nets, simple_match, tx->net); > + > + if (!net || net_data.relay_advice == RELAY_DISALLOWED) { > + l_free(tx); > return; > + } > > - packet[0] = MESH_AD_TYPE_NETWORK; > + tx->packet[0] = MESH_AD_TYPE_NETWORK; > info.type = MESH_IO_TIMING_TYPE_GENERAL; > info.u.gen.interval = net->tx_interval; > info.u.gen.cnt = net->tx_cnt; > @@ -2272,7 +2289,19 @@ static void send_msg_pkt(struct mesh_net *net, uint8_t *packet, uint8_t size) > /* No extra randomization when sending regular mesh messages */ > info.u.gen.max_delay = DEFAULT_MIN_DELAY; > > - mesh_io_send(io, &info, packet, size); > + mesh_io_send(net->io, &info, tx->packet, tx->size); > + l_free(tx); > +} > + > +static void send_msg_pkt(struct mesh_net *net, uint8_t *packet, uint8_t size) > +{ > + struct oneshot_tx *tx = l_new(struct oneshot_tx, 1); > + > + tx->net = net; > + tx->size = size; > + memcpy(tx->packet, packet, size); > + > + l_idle_oneshot(send_msg_pkt_oneshot, tx, NULL); > } > > static enum _relay_advice packet_received(void *user_data, > @@ -2847,11 +2876,6 @@ bool mesh_net_set_key(struct mesh_net *net, uint16_t idx, const uint8_t *key, > return true; > } > > -static bool is_this_net(const void *a, const void *b) > -{ > - return a == b; > -} > - > bool mesh_net_attach(struct mesh_net *net, struct mesh_io *io) > { > bool first; > @@ -2874,7 +2898,7 @@ bool mesh_net_attach(struct mesh_net *net, struct mesh_io *io) > net_msg_recv, NULL); > } > > - if (l_queue_find(nets, is_this_net, net)) > + if (l_queue_find(nets, simple_match, net)) > return false; > > l_queue_push_head(nets, net);