[openwrt/openwrt] ucode: add ubus fixes

LEDE Commits lede-commits at lists.infradead.org
Mon Feb 16 00:21:04 PST 2026


nbd pushed a commit to openwrt/openwrt.git, branch openwrt-25.12:
https://git.openwrt.org/29c2315b1dc41e524d395f2c046fa0d632639f27

commit 29c2315b1dc41e524d395f2c046fa0d632639f27
Author: Felix Fietkau <nbd at nbd.name>
AuthorDate: Sat Feb 7 07:47:36 2026 +0000

    ucode: add ubus fixes
    
    - avoid double close of externally owned channel fds
    - fix refcounting bug
    
    Signed-off-by: Felix Fietkau <nbd at nbd.name>
    (cherry picked from commit e9d6025725fabf0def17651160819651243c2aa1)
---
 .../patches/120-ubus-fix-refcounting-bug.patch     |  25 ++++
 ...double-close-of-externally-owned-channel-.patch | 130 +++++++++++++++++++++
 2 files changed, 155 insertions(+)

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 0000000000..1f3218a3c8
--- /dev/null
+++ b/package/utils/ucode/patches/120-ubus-fix-refcounting-bug.patch
@@ -0,0 +1,25 @@
+From: Felix Fietkau <nbd at nbd.name>
+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 <nbd at nbd.name>
+---
+
+--- 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 0000000000..51e3bf2bf2
--- /dev/null
+++ b/package/utils/ucode/patches/121-ubus-avoid-double-close-of-externally-owned-channel-.patch
@@ -0,0 +1,130 @@
+From: Felix Fietkau <nbd at nbd.name>
+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 <nbd at nbd.name>
+---
+
+--- 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) {




More information about the lede-commits mailing list