summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHauke Mehrtens2026-05-31 15:41:10 +0000
committerHauke Mehrtens2026-06-03 23:20:06 +0000
commit0de6668115593f2d316070573d12c29409c89078 (patch)
tree83bbc903ca0bd43bcd6d87e2cc4c2c7691d0ac6f
parentd06d2a81dc29d746c5f13a9cc07ce779b5ed39be (diff)
downloadrpcd-0de6668115593f2d316070573d12c29409c89078.tar.gz
rc: copy list "name" filter to avoid use-after-free
rc_list() stored the "name" argument as a bare pointer into the parsed request message and then deferred the request. The init.d directory is walked asynchronously across multiple uloop iterations (each script's "running" check is a forked child), during which the single per-context ubus receive buffer that backs the message is overwritten by any other incoming ubus request. c->req_name then points at unrelated/freed data and is compared against directory entries, leading to wrong matches or a crash. Duplicate the name into the context and release it when the request completes. Assisted-by: Claude:claude-opus-4-8 Link: https://github.com/openwrt/rpcd/pull/34 Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
-rw-r--r--rc.c8
1 files changed, 6 insertions, 2 deletions
diff --git a/rc.c b/rc.c
index ae54a10..818e457 100644
--- a/rc.c
+++ b/rc.c
@@ -50,7 +50,7 @@ struct rc_list_context {
struct blob_buf *buf;
DIR *dir;
bool skip_running_check;
- const char *req_name;
+ char *req_name;
/* Info about currently processed init.d entry */
struct {
@@ -193,6 +193,7 @@ static void rc_list_readdir(struct rc_list_context *c)
closedir(c->dir);
ubus_send_reply(c->ctx, &c->req, c->buf->head);
ubus_complete_deferred_request(c->ctx, &c->req, UBUS_STATUS_OK);
+ free(c->req_name);
free(c);
return;
}
@@ -283,8 +284,11 @@ static int rc_list(struct ubus_context *ctx, struct ubus_object *obj,
}
if (tb[RC_LIST_SKIP_RUNNING_CHECK])
c->skip_running_check = blobmsg_get_bool(tb[RC_LIST_SKIP_RUNNING_CHECK]);
+ /* Copy the requested name: msg (and the ctx receive buffer it points
+ * into) is only valid during this call, but req_name is dereferenced
+ * later from the deferred, asynchronous directory walk. */
if (tb[RC_LIST_NAME])
- c->req_name = blobmsg_get_string(tb[RC_LIST_NAME]);
+ c->req_name = strdup(blobmsg_get_string(tb[RC_LIST_NAME]));
ubus_defer_request(ctx, req, &c->req);