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.
This commit is contained in:
Olivier Houchard 2026-06-08 15:48:42 +02:00 committed by Olivier Houchard
parent 3fa818c78f
commit a4520229a7

View file

@ -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);