From a4520229a77eae2c33df7a003a07b95f162482e0 Mon Sep 17 00:00:00 2001 From: Olivier Houchard Date: Mon, 8 Jun 2026 15:48:42 +0200 Subject: [PATCH] BUG/MEDIUM: checks: Dequeue checks on purge When tune.max-checks-per-thread is used, checks that should run are queued, to avoid having too many checks running at the same time. But if the check is about to be purged, because the server is being deleted, we have to explicitly remove it from the queue as that memory is about to be freed, otherwise it will cause a use-after-free. Also, queued checks have not yet incremented th_ctx->running_checks, so don't decrement it if we're queued. This should be backported up to 3.0. --- src/check.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/check.c b/src/check.c index 3864e7c77..8d0effa4c 100644 --- a/src/check.c +++ b/src/check.c @@ -1407,7 +1407,20 @@ struct task *process_chk_conn(struct task *t, void *context, unsigned int state) check_release_buf(check, &check->bi); check_release_buf(check, &check->bo); - _HA_ATOMIC_DEC(&th_ctx->running_checks); + + if (unlikely(LIST_INLIST(&check->check_queue))) { + /* + * If that check is still queued, and we're about to + * purge it, then remove it from the queue, as it is + * about to be freed. + * This can happen if a server is deleted while the check + * is queued. + */ + if (check->state & CHK_ST_PURGE) + LIST_DEL_INIT(&check->check_queue); + } + else + _HA_ATOMIC_DEC(&th_ctx->running_checks); _HA_ATOMIC_DEC(&th_ctx->active_checks); check->state &= ~(CHK_ST_INPROGRESS|CHK_ST_IN_ALLOC|CHK_ST_OUT_ALLOC); check->state &= ~CHK_ST_READY; @@ -1566,6 +1579,7 @@ void free_check(struct check *check) ha_free(&check->tcpcheck); } + LIST_DEL_INIT(&check->check_queue); pool_free(pool_head_uniqueid, istptr(check->unique_id)); check->unique_id = IST_NULL; ha_free(&check->pool_conn_name);