From 56b27074c0158d0f5b8a505bf39ec1f6ef75f5eb Mon Sep 17 00:00:00 2001 From: Martin Cooper Date: Mon, 10 Nov 2025 10:21:45 -0800 Subject: [PATCH] Fix crash when AGWPE connection attempt times out When a connection attempt via AGWPE had exhausted all retries, Direwolf would crash (segfault) on Linux. This happened because the timer expiry check (dl_timer_expiry) iterates over the state machine list in a way that assumes the list is not modified during iteration. However, recent changes to clean up AGWPE connections violated this assumption, such that a state machine might be removed from the list during iteration. Updating the iterations was missed in those earlier changes. This change replaces the loop structure with one that allows for the modification of the list during iteration. Currently t1_expiry() is the only case in which the list may be modified; however, t3_expiry() and tm201_expiry() loops have also been changed to insure against possible future modifications. Fixes #621 --- src/ax25_link.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/ax25_link.c b/src/ax25_link.c index 2f818640..a94491d1 100644 --- a/src/ax25_link.c +++ b/src/ax25_link.c @@ -5347,7 +5347,7 @@ static void test_frame (ax25_dlsm_t *S, cmdres_t cr, int pf, unsigned char *info void dl_timer_expiry (void) { - ax25_dlsm_t *p; + ax25_dlsm_t *p, *p_next; double now = dtime_now(); // Examine all of the data link state machines. @@ -5356,28 +5356,41 @@ void dl_timer_expiry (void) // - is not paused. // - expiration time has arrived or passed. - for (p = list_head; p != NULL; p = p->next) { +// It is possible that one of the expiry functions might modify the list as +// iteration proceeds, so the following loops need to iterate in a way that +// allows for this. + + p = list_head; + while (p) { + p_next = p->next; if (p->t1_exp != 0 && p->t1_paused_at == 0 && p->t1_exp <= now) { p->t1_exp = 0; p->t1_paused_at = 0; p->t1_had_expired = 1; t1_expiry (p); } + p = p_next; } - for (p = list_head; p != NULL; p = p->next) { + p = list_head; + while (p) { + p_next = p->next; if (p->t3_exp != 0 && p->t3_exp <= now) { p->t3_exp = 0; t3_expiry (p); } + p = p_next; } - for (p = list_head; p != NULL; p = p->next) { + p = list_head; + while (p) { + p_next = p->next; if (p->tm201_exp != 0 && p->tm201_paused_at == 0 && p->tm201_exp <= now) { p->tm201_exp = 0; p->tm201_paused_at = 0; tm201_expiry (p); } + p = p_next; } } /* end dl_timer_expiry */