Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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
FUNCTIONCHANGESCORE+/-/~TOUCHEDMATCHED BY
sub_4d8c -> sub_4d0cchanged0.8836/7/49 branch, 6 call, 3 jump, 11 mem, 1 constsimilar
sub_33c4 -> sub_32ecchanged0.8114/9/62 branch, 1 call, 3 jump, 10 memsimilar
sub_4ca0 -> sub_4c04changed0.868/0/01 branch, 1 jump, 4 mem, 1 constsimilar
sub_374c -> sub_3698changed0.967/2/01 branch, 1 jump, 2 constsimilar
sub_4a3c -> sub_49a0changed0.984/5/02 branch, 1 memsimilar
sub_2b58 -> sub_5878changed0.973/1/11 call, 2 mem, 3 constsimilar
sub_3f4c -> sub_3ea8changed0.992/0/01 call, 1 mem, 5 constsimilar
  • 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:

RowFunctionWhat changed
sub_4d8cthe ACL file loaderuser and group by number; the four new if (!o) return;
sub_33c4ubusd_acl_checkcompares the user and the groups by number
sub_4ca0ubusd_acl_alloc_objthe new if (!len) return NULL; after strlen
sub_374c__ubusd_handle_lookupthe new if (!len), which returns UBUS_STATUS_INVALID_ARGUMENT
sub_4a3cubusd_alloc_event_patternthe fix
sub_2b58, sub_3f4cclient set-upthe 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.