CVE-2025-62526: ubusd, OpenWrt 24.10.3 to 24.10.4
This repeats the fix of
OpenWrt security advisory 2025-10-22-1.
ubusd_alloc_event_pattern took a pattern to be at least one byte long,
so an empty one wrote out of bounds on the heap, before any ACL check. The
fix rejects it, adds the same check in three more places, and checks the
ACL of a wildcard event too. 24.10.4 also takes two more changes to the
ACLs of ubus: a user and group are compared by number, and a client’s
extra groups count.
OpenWrt runs sstrip on what it ships, which removes the section headers
as well as the symbols, so only the segments of the file are left. The
report diffs AArch64, and the same holds for MIPS16e, which OpenWrt builds
its MIPS user space as.
Get the binaries
The package feed of a release moves on with its fixes, so the binary of 24.10.3 comes from the root file system of that release.
$ for v in 24.10.3 24.10.4; do
mkdir -p $v
curl -s https://downloads.openwrt.org/releases/$v/targets/armsr/armv8/openwrt-$v-armsr-armv8-rootfs.cpio.gz \
| gunzip | (cd $v && cpio -id sbin/ubusd)
done
Compare
$ hereticus --format markdown 24.10.3/sbin/ubusd 24.10.4/sbin/ubusd
| FUNCTION | CHANGE | SCORE | +/-/~ | TOUCHED | MATCHED BY |
|---|---|---|---|---|---|
sub_4d8c -> sub_4d0c | changed | 0.88 | 36/7/4 | 9 branch, 6 call, 3 jump, 11 mem, 1 const | similar |
sub_33c4 -> sub_32ec | changed | 0.81 | 14/9/6 | 2 branch, 1 call, 3 jump, 10 mem | similar |
sub_4ca0 -> sub_4c04 | changed | 0.86 | 8/0/0 | 1 branch, 1 jump, 4 mem, 1 const | similar |
sub_374c -> sub_3698 | changed | 0.96 | 7/2/0 | 1 branch, 1 jump, 2 const | similar |
sub_4a3c -> sub_49a0 | changed | 0.98 | 4/5/0 | 2 branch, 1 mem | similar |
sub_2b58 -> sub_5878 | changed | 0.97 | 3/1/1 | 1 call, 2 mem, 3 const | similar |
sub_3f4c -> sub_3ea8 | changed | 0.99 | 2/0/0 | 1 call, 1 mem, 5 const | similar |
sub_5710: new
67 matched (53 unchanged, 14 changed), 0 gone, 1 new
7 changed only a constant, hidden. Use –show-retouched to list them.
Each row is a part of the change:
| Row | Function | What changed |
|---|---|---|
sub_4d8c | the ACL file loader | user and group by number; the four new if (!o) return; |
sub_33c4 | ubusd_acl_check | compares the user and the groups by number |
sub_4ca0 | ubusd_acl_alloc_obj | the new if (!len) return NULL; after strlen |
sub_374c | __ubusd_handle_lookup | the new if (!len), which returns UBUS_STATUS_INVALID_ARGUMENT |
sub_4a3c | ubusd_alloc_event_pattern | the fix |
sub_2b58, sub_3f4c | client set-up | the client holds the groups now, so its fields moved |
Read the fix
$ hereticus --diff sub_4a3c 24.10.3/sbin/ubusd 24.10.4/sbin/ubusd
...
ldr w0, [x0]
rev w0, w0
cmp w0, #0x3ff
b.hi $+0xc
mov w19, #0x6
...
blr x1
+ mov w23, w0
+ cmp w0, #0x0
+ b.le $-0x40
sxtw x1, w0
sub x1, x1, #0x1
- mov w20, w0
- ldrb w2, [x21, x1]
+ ldrb w2, [x22, x1]
cmp w2, #0x2a
...
- ldrb w0, [x21]
- cbz w0, $+0x1c
...
blr x1 calls strlen on the pattern. Before, the code went on at once to
read the byte before its end, pattern[len - 1], which for an empty
pattern lies before the buffer. Now b.le goes back 16 instructions to
mov w19, #0x6 when the length is 0 or less: the function returns
UBUS_STATUS_PERMISSION_DENIED. The ldrb and cbz that are gone tested
pattern[0] before the ACL check, which the third commit removed so that
a wildcard is checked too.
--view il shows the same diff as IL statements, where the new check
reads as one test, the error path as the status it sets, and the call
by the function it reaches:
$ hereticus --view il --diff sub_4a3c 24.10.3/sbin/ubusd 24.10.4/sbin/ubusd
...
flags = compare(w0, 0x3ff)
if (w0 u> 0x3ff) goto $+0xc
w19 = 6
...
call strlen
+ w23 = w0
+ flags = compare(w0, 0)
+ if (w0 <= 0) goto $-0x40
...
MIPS16e
The MIPS build of OpenWrt, as for the Malta board, holds its user space as
MIPS16e. Read so, ubusd of the big-endian Malta board reports nine
functions changed:
$ hereticus 24.10.3/sbin/ubusd 24.10.4/sbin/ubusd
...
123 matched (104 unchanged, 19 changed), 0 gone, 8 new
10 changed only a constant, hidden. Use --show-retouched to list them.
The lookup is among them, with its new ori v0, zero, 0x2, the
UBUS_STATUS_INVALID_ARGUMENT it returns, and the fix is on row
5. Of
the eight new functions, seven are the lazy binding stubs of the imports
24.10.4 adds to compare a user and a group by number: getpwnam,
getgrnam, fopen, fgets, fclose, snprintf and strtoul. The
stubs are MIPS32 among MIPS16e code, and each is named for the symbol it
resolves. The eighth opens with the global pointer preamble of MIPS16e
and has no match in 24.10.3.