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-62525: the ltq-ptm kernel module, OpenWrt 24.10.3 to 24.10.4

This repeats the fix of OpenWrt security advisory 2025-10-22-2. The ioctl handler of the PTM driver of the Lantiq xRX200 (VR9) wrote to and read from the address a user gave, with no check, so any local user could read and write kernel memory. The fix (OpenWrt commit e001b31) asks for CAP_NET_ADMIN first, and copies through copy_from_user and copy_to_user.

The module is MIPS32 big endian. OpenWrt’s strip-kmod.sh keeps only the symbols that relocations need, and renames the local ones to numbers, as _7: 8 symbols name 1.5 KiB of the 12 KiB of code, and none of them is the handler. So hereticus reads the module as stripped code: it places each code section after the one before, scans it, takes the starts that tables of callbacks in the data point at, and names each call by the relocation at it.

Get the binaries

$ for v in 24.10.3 24.10.4; do
    base=https://downloads.openwrt.org/releases/$v/targets/lantiq/xrx200/kmods
    kernel=$(curl -s $base/ | grep -o 'href="6[^"]*"' | cut -d'"' -f2)
    ipk=$(curl -s $base/$kernel | grep -o 'href="kmod-ltq-ptm-vr9_[^"]*"' | cut -d'"' -f2)
    mkdir -p $v && curl -s $base/$kernel$ipk | tar xzO ./data.tar.gz | tar xz -C $v
  done

Compare

$ hereticus --format markdown 24.10.3/lib/modules/*/ltq_ptm_vr9.ko 24.10.4/lib/modules/*/ltq_ptm_vr9.ko
FUNCTIONCHANGESCORE+/-/~TOUCHEDMATCHED BY
sub_267cchanged0.7069/37/911 branch, 7 call, 3 jump, 34 mem, 1 constsimilar
  • sub_2b0c: gone

20 matched (10 unchanged, 10 changed), 1 gone, 0 new

The fix is the only changed row. The kernel moved from 6.6.104 to 6.6.110 between the two releases, and the 9 functions that changed only a constant are hidden.

Read the fix

$ hereticus --view il --diff sub_267c 24.10.3/lib/modules/*/ltq_ptm_vr9.ko 24.10.4/lib/modules/*/ltq_ptm_vr9.ko
...
  if (v0 != a0) goto $+0x57c
  a2 = 0
+ call capable
+ a0 = 0xc
+ if (v0 == 0) goto $+0x3c
+ v0 = -0x1
...
+ a0 = s0
+ a1 = sp + 0x24
+ a2 = 0x14
+ at = 0
+ at = at
+ call __raw_copy_to_user
+ nop
+ if (a2 == 0) goto $-0x118
  v0 = 0
+ v0 = -0xe
...

capable(12) asks for CAP_NET_ADMIN, and its failure returns -1, -EPERM. Each answer is now built on the stack and copied out with __raw_copy_to_user, which fails with -14, -EFAULT.

hereticus-cli/tests/truth_cves.rs locks the rank, and fixtures/cve_binaries.py fetches the package and pins the module.