Module: kamailio Branch: master Commit: 48f0e7fc9bd95b509e8fb619d8aafb59c125d2c8 URL: https://github.com/kamailio/kamailio/commit/48f0e7fc9bd95b509e8fb619d8aafb59...
Author: Morten Tryfoss morten@tryfoss.no Committer: Daniel-Constantin Mierla miconda@gmail.com Date: 2023-11-22T09:37:08+01:00
cdp: Avoid deadlock for callback on diameter timeout
Callback function might do an operation which creates a new transaction, which will result in a deadlock.
Fixes #3641
---
Modified: src/modules/cdp/transaction.c
---
Diff: https://github.com/kamailio/kamailio/commit/48f0e7fc9bd95b509e8fb619d8aafb59... Patch: https://github.com/kamailio/kamailio/commit/48f0e7fc9bd95b509e8fb619d8aafb59...
---
diff --git a/src/modules/cdp/transaction.c b/src/modules/cdp/transaction.c index 5680e5b59c6..bba7e27fcc8 100644 --- a/src/modules/cdp/transaction.c +++ b/src/modules/cdp/transaction.c @@ -206,6 +206,15 @@ void cdp_free_trans(cdp_trans_t *x) int cdp_trans_timer(time_t now, void *ptr) { cdp_trans_t *x, *n; + cdp_trans_list_t *cb_queue = 0; + cb_queue = pkg_malloc(sizeof(cdp_trans_list_t)); + if(!cb_queue) { + LOG_NO_MEM("pkg", sizeof(cdp_trans_list_t)); + return 0; + } + cb_queue->head = 0; + cb_queue->tail = 0; + lock_get(trans_list->lock); x = trans_list->head; while(x) { @@ -215,9 +224,6 @@ int cdp_trans_timer(time_t now, void *ptr) .timeout); //Transaction has timed out waiting for response
x->ans = 0; - if(x->cb) { - (x->cb)(1, *(x->ptr), 0, (now - x->expires)); - } n = x->next;
if(x->prev) @@ -228,7 +234,17 @@ int cdp_trans_timer(time_t now, void *ptr) x->next->prev = x->prev; else trans_list->tail = x->prev; - if(x->auto_drop) + + if(x->cb) { + /* queue cb to be done after list unlock */ + x->next = 0; + x->prev = cb_queue->tail; + if(cb_queue->tail) + cb_queue->tail->next = x; + cb_queue->tail = x; + if(!cb_queue->head) + cb_queue->head = x; + } else if(x->auto_drop) /* if no callback, auto drop here */ cdp_free_trans(x);
x = n; @@ -236,6 +252,17 @@ int cdp_trans_timer(time_t now, void *ptr) x = x->next; } lock_release(trans_list->lock); + + /* do all queued callbacks */ + x = cb_queue->head; + while(x) { + (x->cb)(1, *(x->ptr), 0, (now - x->expires)); + if(x->auto_drop) + cdp_free_trans(x); + x = x->next; + } + pkg_free(cb_queue); + return 1; }