configvar: don't crash on stale configvars in finalize_overrides
What changed, and why it matters
This commit fixes a crash in Core Lightning that could occur when starting a plugin with startup parameters after a previously-configured plugin option had disabled itself. The crash happened because the code tried to use a plugin option that no longer existed (a 'stale configvar'). The fix skips these stale entries instead of crashing. It is a denial-of-service-style bug triggered by plugin configuration changes, not a remote exploit for stealing funds.
Treat as a routine bug fix with low security severity. No immediate emergency response is warranted, but operators should upgrade to avoid crashes when reconfiguring plugins with startup parameters. Reviewers may want to confirm no other configvar consumers dereference opt_find_long() results unchecked.
Security signals we found
NULL pointer dereference crash fixed
Denial-of-service via plugin configuration lifecycle
Plugin option registration/unregistration edge case
Changelog labels this as a fixed crash
Evidence from the diff
In common/configvar.c, finalize_overrides() iterates over configvars and calls opt_find_long() to resolve each option. If a plugin registered an option but later disabled itself, the option table entry is removed, so opt_find_long() returns NULL. The code then dereferenced opts[i] without checking for NULL, causing a crash. The patch adds a NULL check and continues, leaving the stale configvar in place so it can be reused if the plugin is restarted. A test plugin (selfdisable.py) is also adjusted to actually register its dummy option, enabling the crash scenario to be reproduced in tests.
Changed components
common/configvar.clightningd plugin configuration systemplugin option override finalizationInspect captured patch +6 / −1
### common/configvar.c
@@ -107,6 +107,11 @@ void configvar_finalize_overrides(struct configvar **cvs)
opts = tal_arr(tmpctx, const struct opt_table *, tal_count(cvs));
for (size_t i = 0; i < tal_count(cvs); i++) {
opts[i] = opt_find_long(cvs[i]->optvar, NULL);
+ /* The plugin which registered this option may have
+ * disabled itself since: leave the stale configvar alone,
+ * it can still be reused if that plugin is started again. */
+ if (!opts[i])
+ continue;
/* If you're allowed multiple, they don't override...
* unless transient values exist, which override non-transient. */
if (opts[i]->type & OPT_MULTI) {
### tests/plugins/selfdisable.py
@@ -9,5 +9,5 @@ def init(configuration, options, plugin):
return {'disable': 'init saying disable'}
-# plugin.add_option('dummy-option', False, 'does nothing', opt_type='bool')
+plugin.add_option('dummy-option', False, 'does nothing', opt_type='bool')
plugin.run()Why this scored 42/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.