<feed xmlns='http://www.w3.org/2005/Atom'>
<title>ubus, branch master</title>
<subtitle>OpenWrt system message/RPC bus</subtitle>
<id>https://git.openwrt.org/project/ubus/atom?h=master</id>
<link rel='self' href='https://git.openwrt.org/project/ubus/atom?h=master'/>
<link rel='alternate' type='text/html' href='https://git.openwrt.org/project/ubus/'/>
<updated>2026-05-23T00:48:52Z</updated>
<entry>
<title>ubusd: use fixed-width types for sequence counters</title>
<updated>2026-05-23T00:48:52Z</updated>
<author>
<name>Hauke Mehrtens</name>
</author>
<published>2026-05-21T21:46:14Z</published>
<link rel='alternate' type='text/html' href='https://git.openwrt.org/project/ubus/commit/?id=795b32bb96b611493f423666236e9c1e49e0736c'/>
<id>urn:sha1:795b32bb96b611493f423666236e9c1e49e0736c</id>
<content type='text'>
The message sequence number is a uint16_t on the wire (ubus_msghdr),
and ubusd_acl_seq is emitted as a u32. Declaring the counters with
the matching fixed-width types removes the implicit conversion that
happened on every store or send:

  event_seq               int          -&gt; uint16_t
  ubus_object.invoke_seq  unsigned int -&gt; uint16_t
  ubus_monitor.seq        uint32_t     -&gt; uint16_t
  ubusd_acl_seq           int          -&gt; uint32_t

The values placed on the wire are unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;
Link: https://github.com/openwrt/ubus/pull/20
Signed-off-by: Hauke Mehrtens &lt;hauke@hauke-m.de&gt;
</content>
</entry>
<entry>
<title>ubusd: use size_t for string and blob length variables</title>
<updated>2026-05-23T00:48:47Z</updated>
<author>
<name>Hauke Mehrtens</name>
</author>
<published>2026-05-21T21:45:59Z</published>
<link rel='alternate' type='text/html' href='https://git.openwrt.org/project/ubus/commit/?id=f92ffd289dcc07b20d0fcf34e10e5c685240e5bd'/>
<id>urn:sha1:f92ffd289dcc07b20d0fcf34e10e5c685240e5bd</id>
<content type='text'>
strlen() and blob_raw_len() return size_t; storing their result in
an int relies on an implicit narrowing conversion. Use size_t for
the affected length variables in ubusd_alloc_event_pattern(),
ubus_create_obj_method() and __ubusd_handle_lookup().

ubusd_alloc_event_pattern() checked the length with "&lt;= 0", which is
only ever true for 0 once the variable is unsigned; replace it with
"!len".

Co-Authored-By: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;
Link: https://github.com/openwrt/ubus/pull/20
Signed-off-by: Hauke Mehrtens &lt;hauke@hauke-m.de&gt;
</content>
</entry>
<entry>
<title>ubusd_acl: use size_t for strlen result in ubusd_acl_alloc_obj</title>
<updated>2026-05-23T00:48:42Z</updated>
<author>
<name>Hauke Mehrtens</name>
</author>
<published>2026-05-21T21:21:55Z</published>
<link rel='alternate' type='text/html' href='https://git.openwrt.org/project/ubus/commit/?id=020a64b9b1693295a3fde34147aef48bf47c76ae'/>
<id>urn:sha1:020a64b9b1693295a3fde34147aef48bf47c76ae</id>
<content type='text'>
len held the result of strlen() in an int. It is later passed as
len + 1 to calloc_a(), whose variadic length arguments are read via
va_arg as size_t in __calloc_a(). Passing an int where size_t is
expected is undefined behaviour and can yield a wrong allocation
size on LP64 platforms.

Co-Authored-By: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;
Link: https://github.com/openwrt/ubus/pull/20
Signed-off-by: Hauke Mehrtens &lt;hauke@hauke-m.de&gt;
</content>
</entry>
<entry>
<title>libubus-io: reset sock.fd to -1 after close on ubus_reconnect error path</title>
<updated>2026-05-23T00:48:37Z</updated>
<author>
<name>Hauke Mehrtens</name>
</author>
<published>2026-05-03T21:02:05Z</published>
<link rel='alternate' type='text/html' href='https://git.openwrt.org/project/ubus/commit/?id=747013f6ea05a168d000531553f8de90f8b87b7f'/>
<id>urn:sha1:747013f6ea05a168d000531553f8de90f8b87b7f</id>
<content type='text'>
If ubus_reconnect() fails after the new socket has been opened (HELLO
read failure, header validation, OOM, body read failure, ID validation),
the out_close: handler closes ctx-&gt;sock.fd but leaves the field pointing
at the now-closed descriptor.

A subsequent ubus_shutdown() / ubus_free() then calls close() on that
stale value, and a second reconnect attempt will pass the entry guard at
the top of ubus_reconnect() and close it again. In both cases the kernel
may have recycled the slot for an unrelated descriptor in the meantime,
causing us to close someone else's fd — the same class of bug fixed in
ubus_shutdown() previously.

Set ctx-&gt;sock.fd = -1 alongside the close so the field is a faithful
indicator of socket ownership.

Co-Authored-By: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;
Link: https://github.com/openwrt/ubus/pull/20
Signed-off-by: Hauke Mehrtens &lt;hauke@hauke-m.de&gt;
</content>
</entry>
<entry>
<title>libubus-io: byte-swap peer in HELLO when storing as local_id</title>
<updated>2026-05-23T00:48:32Z</updated>
<author>
<name>Hauke Mehrtens</name>
</author>
<published>2026-05-03T21:01:43Z</published>
<link rel='alternate' type='text/html' href='https://git.openwrt.org/project/ubus/commit/?id=7a068bac5a9b877805f94797915d8d14fd434fb0'/>
<id>urn:sha1:7a068bac5a9b877805f94797915d8d14fd434fb0</id>
<content type='text'>
Every other receive path converts the wire-format ubus_msghdr fields to
host byte order before use (see get_next_msg() and ubusd_main client_cb).
ubus_reconnect() forgot to do this for the HELLO peer field and stored
the raw big-endian value into ctx-&gt;local_id.

On little-endian hosts this means local_id holds a byte-swapped client
id forever:

  - The defensive `if (ctx-&gt;local_id &lt;= UBUS_CLIENT_ID_CHANNEL)` check
    no longer rejects an id of 1, since 0x01000000 &gt; 1. The check was
    intended to catch a server handing out the channel id (1) to a
    regular client.
  - ubus_context_is_channel() can never match an actual non-channel
    local_id by accident, but the value is still semantically wrong and
    breaks any future code that treats local_id as a real id.

Apply be32_to_cpu() to match the other receive paths.

Co-Authored-By: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;
Link: https://github.com/openwrt/ubus/pull/20
Signed-off-by: Hauke Mehrtens &lt;hauke@hauke-m.de&gt;
</content>
</entry>
<entry>
<title>libubus-io: close recv_fd captured before get_next_msg failure</title>
<updated>2026-05-23T00:48:27Z</updated>
<author>
<name>Hauke Mehrtens</name>
</author>
<published>2026-05-03T21:00:25Z</published>
<link rel='alternate' type='text/html' href='https://git.openwrt.org/project/ubus/commit/?id=8188f5ce8564e7f4114e2db2dded1e6361957b2a'/>
<id>urn:sha1:8188f5ce8564e7f4114e2db2dded1e6361957b2a</id>
<content type='text'>
recv_retry() captures any SCM_RIGHTS fd into the caller's *recv_fd as soon
as the first recvmsg succeeds, then continues looping to drain the rest of
the iov. If a subsequent recvmsg in the same call returns 0 (EOF) or
fails fatally, recv_retry returns -1 with the captured fd already written
to the caller's variable. The same hand-off survives errors in the body
read or in the validate/alloc path of get_next_msg().

ubus_handle_data() simply broke out of its loop in those cases, dropping
the fd on the floor. With long-running clients on a flaky link this is a
slow descriptor leak that eventually exhausts the process's fd table.

Reset recv_fd to -1 once it has been handed off to ubus_process_msg(),
and close it at loop exit if anything is still parked there.

Co-Authored-By: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;
Link: https://github.com/openwrt/ubus/pull/20
Signed-off-by: Hauke Mehrtens &lt;hauke@hauke-m.de&gt;
</content>
</entry>
<entry>
<title>libubus: actually set FD_CLOEXEC on the ubus socket</title>
<updated>2026-05-23T00:48:22Z</updated>
<author>
<name>Hauke Mehrtens</name>
</author>
<published>2026-05-03T20:58:55Z</published>
<link rel='alternate' type='text/html' href='https://git.openwrt.org/project/ubus/commit/?id=bcc45ca981fd61e11934776bcee18f628156a7f7'/>
<id>urn:sha1:bcc45ca981fd61e11934776bcee18f628156a7f7</id>
<content type='text'>
fcntl(fd, F_SETFL, ... | O_CLOEXEC) is a no-op for the close-on-exec bit.
F_SETFL only manipulates file *status* flags (O_APPEND, O_ASYNC,
O_NONBLOCK, ...), and silently masks out anything else; close-on-exec is
a file *descriptor* flag that has to be set with F_SETFD/FD_CLOEXEC.

Both ubus_reconnect() and ubus_channel_connect() relied on the broken
form and therefore left the ubus socket inheritable across exec(2). Any
client that fork+exec'd a child (a common pattern in OpenWrt services)
would leak the ubus connection into the new process.

Set FD_CLOEXEC explicitly via F_SETFD in addition to the F_SETFL call
that toggles O_NONBLOCK.

Co-Authored-By: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;
Link: https://github.com/openwrt/ubus/pull/20
Signed-off-by: Hauke Mehrtens &lt;hauke@hauke-m.de&gt;
</content>
</entry>
<entry>
<title>ubusd: fix NULL dereference on OOM in ubus_msg_enqueue</title>
<updated>2026-05-23T00:48:17Z</updated>
<author>
<name>Hauke Mehrtens</name>
</author>
<published>2026-05-03T20:44:02Z</published>
<link rel='alternate' type='text/html' href='https://git.openwrt.org/project/ubus/commit/?id=09d2df45bf3862fc259d5b1e1527c8777e2e5d23'/>
<id>urn:sha1:09d2df45bf3862fc259d5b1e1527c8777e2e5d23</id>
<content type='text'>
ubus_msg_ref() can return NULL when the source message uses an external
buffer and the ubus_msg_new() allocation fails. ubus_msg_enqueue() stored
the result without checking and queued the list entry anyway. Later, when
the queue entry was freed via ubus_msg_list_free() -&gt; ubus_msg_free(NULL),
the NULL message pointer was dereferenced.

Drop the queue entry and return early if the reference cannot be taken,
so we never link a list entry with a NULL message.

Co-Authored-By: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;
Link: https://github.com/openwrt/ubus/pull/20
Signed-off-by: Hauke Mehrtens &lt;hauke@hauke-m.de&gt;
</content>
</entry>
<entry>
<title>ubusd_id: fix continue in do-while skipping random ID retry</title>
<updated>2026-05-23T00:48:12Z</updated>
<author>
<name>Hauke Mehrtens</name>
</author>
<published>2026-05-03T20:43:02Z</published>
<link rel='alternate' type='text/html' href='https://git.openwrt.org/project/ubus/commit/?id=239edcbaaac85fe2dd80c985823a826ad18adabc'/>
<id>urn:sha1:239edcbaaac85fe2dd80c985823a826ad18adabc</id>
<content type='text'>
In ubus_alloc_id() the `continue` statement was intended to discard random
IDs that fall in the reserved system-object range (0..UBUS_SYSTEM_OBJECT_MAX-1)
and retry the read. In a do-while loop, however, `continue` jumps to the
loop-continuation expression, not back to the start of the body. The
expression then calls avl_insert() with the still-reserved ID, and on
success the loop exits — successfully assigning a reserved ID to a client,
object, or object type.

This breaks invariants relied upon elsewhere, e.g. ubusd_alloc_event_pattern()
rejects any object with id &lt; UBUS_SYSTEM_OBJECT_MAX as a permission error,
making event registration fail for any client object that happens to draw a
low random ID.

Wrap the read in an inner do-while so a low ID actually triggers a re-read
before insertion is attempted.

Co-Authored-By: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;
Link: https://github.com/openwrt/ubus/pull/20
Signed-off-by: Hauke Mehrtens &lt;hauke@hauke-m.de&gt;
</content>
</entry>
<entry>
<title>ubusd_main: check strdup return value in mkdir_sockdir</title>
<updated>2026-05-23T00:48:07Z</updated>
<author>
<name>Hauke Mehrtens</name>
</author>
<published>2026-04-16T20:27:38Z</published>
<link rel='alternate' type='text/html' href='https://git.openwrt.org/project/ubus/commit/?id=a564b8dcb395738be3d24750ea41f1dc3a42809d'/>
<id>urn:sha1:a564b8dcb395738be3d24750ea41f1dc3a42809d</id>
<content type='text'>
strdup() can fail and return NULL; the subsequent strrchr() call then
dereferences a NULL pointer.  The impact is limited to startup with a
constant path, but handle the allocation failure gracefully.

Co-Authored-By: Claude Opus 4.6 &lt;noreply@anthropic.com&gt;
Link: https://github.com/openwrt/ubus/pull/20
Signed-off-by: Hauke Mehrtens &lt;hauke@hauke-m.de&gt;
</content>
</entry>
</feed>
