libplugin: make jsonrpc_set_datastore_binary() take an explicit length.
What changed, and why it matters
This is a small internal code cleanup in Core Lightning's plugin helper library. It changes a helper function so callers pass the data length explicitly, rather than the helper measuring it itself. The commit message frames this as a convenience change, not a security fix. There is no direct evidence in the commit of an exploitable vulnerability, but the change removes a class of potential bugs where a non-tal pointer could be mis-measured.
Treat as a defensive hardening/cleanup commit. Review other call sites of json_add_hex_talarr() across the codebase for similar assumptions, and ensure plugin authors know the new binary helper requires an explicit length. No urgent security response is indicated by this commit alone.
Security signals we found
API change removes implicit tal-length dependency for binary datastore values
Call sites updated to use tal_bytelen() explicitly
No direct security claim in commit message or diff
Potential latent bug class (incorrect length for non-tal binary pointer) is addressed
Evidence from the diff
The patch modifies jsonrpc_set_datastore_binary() and its backing jsonrpc_set_datastore_() in plugins/libplugin.c/h. Previously the helper took a boolean value_is_string and, for binary data, called json_add_hex_talarr() which derives the length from the tal allocation header. Now callers pass an explicit int len_or_str, with -1 reserved for string mode. The macro jsonrpc_set_datastore_binary gains a len parameter, and the two call sites in plugins/chanbackup.c are updated to pass tal_bytelen(). This eliminates the requirement that binary values be tal-allocated arrays, reducing the risk of passing a non-tal pointer (e.g., a struct field or stack buffer) that would cause json_add_hex_talarr() to read incorrect lengths or crash. No overflow, injection, or cryptographic weakness is visible in the diff.
Changed components
plugins/libplugin.cplugins/libplugin.hplugins/chanbackup.cjsonrpc_set_datastore_binary() helperjsonrpc_set_datastore_() internal functionInspect captured patch +9 / −8
diff --git a/plugins/chanbackup.c b/plugins/chanbackup.c
index 1fb660a3..11091edd 100644
--- a/plugins/chanbackup.c
+++ b/plugins/chanbackup.c
@@ -665,7 +665,7 @@ static struct command_result *commit_peer_backup(struct command *cmd,
"chanbackup/peers/%s",
fmt_node_id(tmpctx,
&pb->peer)),
- pb->data,
+ pb->data, tal_bytelen(pb->data),
"create-or-replace",
NULL, NULL, NULL);
}
@@ -899,6 +899,7 @@ static struct command_result *handle_your_peer_storage(struct command *cmd,
return jsonrpc_set_datastore_binary(cmd,
"chanbackup/latestscb",
decoded_bkp,
+ tal_bytelen(decoded_bkp),
"create-or-replace",
datastore_success,
datastore_failed,
diff --git a/plugins/libplugin.c b/plugins/libplugin.c
index 896564f7..614b5d3d 100644
--- a/plugins/libplugin.c
+++ b/plugins/libplugin.c
@@ -912,7 +912,7 @@ void rpc_enable_batching(struct plugin *plugin)
struct command_result *jsonrpc_set_datastore_(struct command *cmd,
const char *path,
const void *value,
- bool value_is_string,
+ int len_or_str,
const char *mode,
struct command_result *(*cb)(struct command *command,
const char *method,
@@ -936,10 +936,10 @@ struct command_result *jsonrpc_set_datastore_(struct command *cmd,
req = jsonrpc_request_start(cmd, "datastore", cb, errcb, arg);
json_add_keypath(req->js->jout, "key", path);
- if (value_is_string)
+ if (len_or_str == -1)
json_add_string(req->js, "string", value);
else
- json_add_hex_talarr(req->js, "hex", value);
+ json_add_hex(req->js, "hex", value, len_or_str);
json_add_string(req->js, "mode", mode);
return send_outreq(req);
}
diff --git a/plugins/libplugin.h b/plugins/libplugin.h
index 54b4f883..2cc781da 100644
--- a/plugins/libplugin.h
+++ b/plugins/libplugin.h
@@ -272,7 +272,7 @@ struct json_stream *jsonrpc_stream_fail_data(struct command *cmd,
struct command_result *jsonrpc_set_datastore_(struct command *cmd,
const char *path,
const void *value,
- bool value_is_string,
+ int len_or_str,
const char *mode,
struct command_result *(*cb)(struct command *command,
const char *method,
@@ -288,7 +288,7 @@ struct command_result *jsonrpc_set_datastore_(struct command *cmd,
NON_NULL_ARGS(1, 2, 3, 5);
#define jsonrpc_set_datastore_string(cmd, path, str, mode, cb, errcb, arg) \
- jsonrpc_set_datastore_((cmd), (path), (str), true, (mode), \
+ jsonrpc_set_datastore_((cmd), (path), (str), -1, (mode), \
typesafe_cb_preargs(struct command_result *, void *, \
(cb), (arg), \
struct command *command, \
@@ -303,8 +303,8 @@ struct command_result *jsonrpc_set_datastore_(struct command *cmd,
const jsmntok_t *result), \
(arg))
-#define jsonrpc_set_datastore_binary(cmd, path, tal_ptr, mode, cb, errcb, arg) \
- jsonrpc_set_datastore_((cmd), (path), (tal_ptr), false, (mode), \
+#define jsonrpc_set_datastore_binary(cmd, path, ptr, len, mode, cb, errcb, arg) \
+ jsonrpc_set_datastore_((cmd), (path), (ptr), (len), (mode), \
typesafe_cb_preargs(struct command_result *, void *, \
(cb), (arg), \
struct command *command, \
Why this scored 16/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.