The -upx release assets are now packed with UPX 4.2.4 instead of 5.2.0, so they start on the older
kernels router firmwares ship.
Why
Every UPX 5.x unpacking stub calls memfd_create before anything else, and that syscall needs Linux
3.17 (October 2014). On an older kernel a 5.x-packed binary dies with Trace/breakpoint trap before
the proxy's first instruction — measured on kernel 3.4.113: execve succeeds, the stub makes a couple
of syscalls, not one of them a network call, then the kernel raises SIGTRAP. UPX closed that report as
"kernel too old" and points at 4.2.4, whose stub works through /proc/self/exe and mmap instead
(upx/upx#904 for mipsel on 3.4, upx/upx#902 for arm32 on 3.14). No 5.x stub can be talked out of it.
The newest lines are no better here: 5.0.2, 5.1.1 and 5.2.0 also mis-pack an armv7 executable
PT_LOAD whose p_filesz is an exact multiple of the page size into a binary that segfaults at
startup (upx/upx#18898, fixed in 5.2.1) — and 5.2.1 still needs memfd_create.
For a flash-constrained router the -upx asset is the whole point of this path, so an asset that
cannot start on the firmware it is meant for is worse than no asset at all.
Changed
release.ymlandrelease-dryrun.ymlinstall UPX 4.2.4, with the checksum for the 4.2.4 asset.docs/Building.mdtells anyone packing a binary themselves to use 4.2.4 and why, and notes that
upx -tpasses on either version and will not catch this.
Notes
- The pin costs almost nothing in size on this project's assets: the mipsel binary packs to 1 471 436
bytes with 4.2.4 against 1 471 168 with 5.2.0 (4 930 100 unpacked, 29.85% either way), and the packed
file starts on a Keenetic (MT7621, kernel 4.9) and prints its version. - Do not move this to
latest, and check both an old and a new kernel before considering a bump.