From: Felix Fietkau Date: Sat, 7 Feb 2026 07:47:36 +0000 (+0000) Subject: ucode: add ubus fixes X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e9d6025725fabf0def17651160819651243c2aa1;p=thirdparty%2Fopenwrt.git ucode: add ubus fixes - avoid double close of externally owned channel fds - fix refcounting bug Signed-off-by: Felix Fietkau --- diff --git a/package/utils/ucode/patches/120-ubus-fix-refcounting-bug.patch b/package/utils/ucode/patches/120-ubus-fix-refcounting-bug.patch new file mode 100644 index 00000000000..1f3218a3c84 --- /dev/null +++ b/package/utils/ucode/patches/120-ubus-fix-refcounting-bug.patch @@ -0,0 +1,25 @@ +From: Felix Fietkau +Date: Fri, 6 Feb 2026 19:04:54 +0000 +Subject: [PATCH] ubus: fix refcounting bug + +In uc_ubus_channel_req_cb an extra ref is taken for args and method, +which are not used elsewhere. + +Signed-off-by: Felix Fietkau +--- + +--- a/lib/ubus.c ++++ b/lib/ubus.c +@@ -2395,10 +2395,10 @@ uc_ubus_channel_req_cb(struct ubus_conte + + args = blob_array_to_ucv(c->vm, blob_data(msg), blob_len(msg), true); + reqproto = ucv_object_new(c->vm); +- ucv_object_add(reqproto, "args", ucv_get(args)); ++ ucv_object_add(reqproto, "args", args); + + if (method) +- ucv_object_add(reqproto, "type", ucv_get(ucv_string_new(method))); ++ ucv_object_add(reqproto, "type", ucv_string_new(method)); + + return uc_ubus_handle_reply_common(ctx, req, c->vm, c->res, func, reqproto); + } diff --git a/package/utils/ucode/patches/121-ubus-avoid-double-close-of-externally-owned-channel-.patch b/package/utils/ucode/patches/121-ubus-avoid-double-close-of-externally-owned-channel-.patch new file mode 100644 index 00000000000..51e3bf2bf22 --- /dev/null +++ b/package/utils/ucode/patches/121-ubus-avoid-double-close-of-externally-owned-channel-.patch @@ -0,0 +1,130 @@ +From: Felix Fietkau +Date: Fri, 6 Feb 2026 20:19:59 +0000 +Subject: [PATCH] ubus: avoid double close of externally owned channel fds + +When a channel is opened via an fd obtained through fileno(), the fd is +owned by an external resource. Track this in fd_handle and detach from +uloop without closing the fd on disconnect/shutdown. + +Signed-off-by: Felix Fietkau +--- + +--- a/lib/ubus.c ++++ b/lib/ubus.c +@@ -132,6 +132,7 @@ typedef struct { + struct ubus_context ctx; + struct blob_buf buf; + int timeout; ++ bool fd_handle; + + uc_vm_t *vm; + uc_value_t *res; +@@ -739,7 +740,7 @@ uc_ubus_call_timeout_cb(struct uloop_tim + } + + static int +-get_fd(uc_vm_t *vm, uc_value_t *val) ++get_fd(uc_vm_t *vm, uc_value_t *val, bool *handle) + { + uc_value_t *fn; + int64_t n; +@@ -747,6 +748,9 @@ get_fd(uc_vm_t *vm, uc_value_t *val) + fn = ucv_property_get(val, "fileno"); + + if (ucv_is_callable(fn)) { ++ if (handle) ++ *handle = true; ++ + uc_vm_stack_push(vm, ucv_get(val)); + uc_vm_stack_push(vm, ucv_get(fn)); + +@@ -816,7 +820,7 @@ uc_ubus_call_common(uc_vm_t *vm, uc_ubus + ucv_object_to_blob(funargs, &c->buf); + + if (fd) { +- fd_val = get_fd(vm, fd); ++ fd_val = get_fd(vm, fd, NULL); + + if (fd_val < 0) + errval_return(UBUS_STATUS_INVALID_ARGUMENT, +@@ -938,7 +942,7 @@ uc_ubus_defer_common(uc_vm_t *vm, uc_ubu + ucv_object_to_blob(funargs, &c->buf); + + if (fd) { +- fd_val = get_fd(vm, fd); ++ fd_val = get_fd(vm, fd, NULL); + + if (fd_val < 0) + errval_return(UBUS_STATUS_INVALID_ARGUMENT, +@@ -1174,7 +1178,7 @@ uc_ubus_request_set_fd(uc_vm_t *vm, size + if (!callctx) + err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid call context"); + +- fd = get_fd(vm, uc_fn_arg(0)); ++ fd = get_fd(vm, uc_fn_arg(0), NULL); + + if (fd < 0) + err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid file descriptor"); +@@ -2313,6 +2317,10 @@ uc_ubus_disconnect(uc_vm_t *vm, size_t n + #ifdef HAVE_UBUS_FLUSH_REQUESTS + ubus_flush_requests(&c->ctx); + #endif ++ if (c->fd_handle) { ++ uloop_fd_delete(&c->ctx.sock); ++ c->ctx.sock.fd = -1; ++ } + ubus_shutdown(&c->ctx); + c->ctx.sock.fd = -1; + uc_ubus_put_res(&c->res); +@@ -2422,6 +2430,10 @@ uc_ubus_channel_disconnect_cb(struct ubu + blob_buf_free(&c->buf); + + if (c->ctx.sock.fd >= 0) { ++ if (c->fd_handle) { ++ uloop_fd_delete(&c->ctx.sock); ++ c->ctx.sock.fd = -1; ++ } + ubus_shutdown(&c->ctx); + c->ctx.sock.fd = -1; + } +@@ -2486,6 +2498,7 @@ uc_ubus_channel_connect(uc_vm_t *vm, siz + { + #ifdef HAVE_UBUS_CHANNEL_SUPPORT + uc_value_t *fd, *cb, *disconnect_cb, *timeout; ++ bool handle = false; + uc_ubus_connection_t *c; + int fd_val; + +@@ -2495,7 +2508,7 @@ uc_ubus_channel_connect(uc_vm_t *vm, siz + "disconnect_cb", UC_CLOSURE, true, &disconnect_cb, + "timeout", UC_INTEGER, true, &timeout); + +- fd_val = get_fd(vm, fd); ++ fd_val = get_fd(vm, fd, &handle); + + if (fd_val < 0) + err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid file descriptor argument"); +@@ -2505,6 +2518,8 @@ uc_ubus_channel_connect(uc_vm_t *vm, siz + if (!c) + return NULL; + ++ c->fd_handle = handle; ++ + if (ubus_channel_connect(&c->ctx, fd_val, cb ? uc_ubus_channel_req_cb : NULL)) { + ucv_put(c->res); + err_return(UBUS_STATUS_UNKNOWN_ERROR, "Unable to create ubus channel"); +@@ -2602,8 +2617,13 @@ static void free_connection(void *ud) { + + blob_buf_free(&conn->buf); + +- if (conn->ctx.sock.fd >= 0) ++ if (conn->ctx.sock.fd >= 0) { ++ if (conn->fd_handle) { ++ uloop_fd_delete(&conn->ctx.sock); ++ conn->ctx.sock.fd = -1; ++ } + ubus_shutdown(&conn->ctx); ++ } + } + + static void free_deferred(void *ud) {