askrene: fix error path if we fail sanity checks.
What changed, and why it matters
This commit fixes a programming mistake in Core Lightning's 'askrene' plugin where an error-handling path tried to free memory that had already been freed. Re-freeing the same memory can crash the process or corrupt memory. The fix replaces the shared 'goto fail' path with direct returns so the double-free cannot happen.
Apply the patch. It is a straightforward correctness fix that prevents memory corruption on routing sanity-check failures. No immediate incident response is indicated unless crashes in askrene have already been observed.
Security signals we found
Double-free / use-after-free bug in error path
Memory corruption / crash potential in routing plugin
Fix removes shared cleanup label causing duplicate tal_free
No explicit security framing by vendor
Evidence from the diff
In plugins/askrene/mcf.c, the linear_routes() function used a goto label ‘fail’ that freed working_ctx. Several sanity-check failures already freed *flows and then jumped to ‘fail’, which freed working_ctx a second time. The patch removes the goto and returns the error message directly from each check, eliminating the double-free/use-after-free risk on these error paths.
Changed components
plugins/askrene/mcf.clinear_routes() functionCore Lightning askrene minimum-cost-flow routing pluginInspect captured patch +9 / −12
diff --git a/plugins/askrene/mcf.c b/plugins/askrene/mcf.c
index 3acf0a33..44cdfc72 100644
--- a/plugins/askrene/mcf.c
+++ b/plugins/askrene/mcf.c
@@ -1618,24 +1618,21 @@ linear_routes(const tal_t *ctx, struct route_query *rq,
rq_log(rq, rq, LOG_BROKEN,
"%s: check_htlc_min_limits failed", __func__);
*flows = tal_free(*flows);
- goto fail;
+ return error_message;
}
if (!check_htlc_max_limits(rq, *flows)) {
- error_message =
- rq_log(rq, rq, LOG_BROKEN,
- "%s: check_htlc_max_limits failed", __func__);
*flows = tal_free(*flows);
- goto fail;
+ return rq_log(rq, rq, LOG_BROKEN,
+ "%s: check_htlc_max_limits failed", __func__);
}
if (tal_count(*flows) > rq->maxparts) {
- error_message = rq_log(
- rq, rq, LOG_BROKEN,
- "%s: the number of flows (%zu) exceeds the limit set "
- "on payment parts (%" PRIu32
- "), please submit a bug report",
- __func__, tal_count(*flows), rq->maxparts);
+ size_t num_flows = tal_count(*flows);
*flows = tal_free(*flows);
- goto fail;
+ return rq_log(rq, rq, LOG_BROKEN,
+ "%s: the number of flows (%zu) exceeds the limit set "
+ "on payment parts (%" PRIu32
+ "), please submit a bug report",
+ __func__, num_flows, rq->maxparts);
}
return NULL;
Why this scored 31/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.