Skip to content

mtd: fix use-after-free in find_ubi_for_mtd (segfault on musl arm64)#171

Merged
widgetii merged 1 commit into
masterfrom
mtd-fix-find-ubi-use-after-free
Jun 2, 2026
Merged

mtd: fix use-after-free in find_ubi_for_mtd (segfault on musl arm64)#171
widgetii merged 1 commit into
masterfrom
mtd-fix-find-ubi-use-after-free

Conversation

@widgetii
Copy link
Copy Markdown
Member

@widgetii widgetii commented Jun 2, 2026

Found while validating the arm64 release binary on a Hi3519DV500 board: the published ipctool-arm64 (Bootlin musl static) segfaults with exit 139 immediately after detection, but only on ipctool (full YAML); subcommands like -c, -s, clocks all work.

The bug

find_ubi_for_mtd() reads de->d_name after closedir(d):

closedir(d);
int ubi_num;
sscanf(de->d_name, "ubi%d", &ubi_num);   // de invalid after closedir
return ubi_num;

POSIX explicitly leaves struct dirent invalid after closedir(). glibc happens to keep the buffer alive across the close (so the bug never surfaced on the old arm32/mips32 release artifacts or on the local glibc dev build); musl invalidates it immediately, which is what the published Bootlin-musl arm64 binary hits.

Reproduction

Bisected build_yaml()get_mtd_infocb_mtd_infofind_ubi_for_mtd(4):

[fub] dirent='ubi0'
[fub] fopen /sys/class/ubi/ubi0/mtd_num
[fub] fscanf ret=1 num=4
Segmentation fault

num=4 matches mtd_num=4 (the rootfs ubifs volume), so the function enters the "match" branch where it closes the dir and then derefs de. Local repro with /opt/aarch64--musl--stable-2025.08-1/bin/aarch64-buildroot-linux-musl-gcc confirms the same crash; glibc-built binary doesn't.

Fix

Restructure to parse de->d_name before closedir() with a single local ubi_num initialised to -1 returned at the end. Same control-flow shape (early continue on fopen failure) so the diff stays small.

Test plan

  • Bootlin-musl arm64 build now produces full YAML on Hi3519DV500 (was: exit 139)
  • CI green on arm32 / mips32 / arm64 matrix
  • No behavioural change on glibc/arm32/mips32 — same UBI lookup result, only the memory accesses are reordered

Impact

The currently published ipctool-arm64 at latest is broken on bare invocation. Merging this and letting the release workflow re-publish closes the regression. The pre-merge state of master (after #168, #169, #170) does not exhibit the bug on the glibc dev build we used to validate V5 earlier — only the musl-built release artifact.

🤖 Generated with Claude Code

POSIX leaves struct dirent invalid after closedir(); glibc happens to
keep the buffer alive across the close, musl invalidates it
immediately. find_ubi_for_mtd() did:

  closedir(d);
  int ubi_num;
  sscanf(de->d_name, "ubi%d", &ubi_num);   /* <-- read freed memory */
  return ubi_num;

That's a segfault on the Bootlin-musl-built aarch64 release binary
(reproducible in `ipctool` -> "rom" step -> cb_mtd_info -> mtd4 ubifs
volume), while the same source builds clean and runs through to full
YAML on glibc.

Restructure to parse de->d_name BEFORE closedir(), with a single
local `ubi_num` initialised to -1 that's returned at the end. Also
flatten the `if (f)` block to early-`continue` on fopen() failure to
keep the control flow obvious.

Same fix would be the right thing for the equivalent dirent-after-
closedir pattern elsewhere in the tree if it surfaces.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@widgetii widgetii merged commit d780868 into master Jun 2, 2026
4 checks passed
@widgetii widgetii deleted the mtd-fix-find-ubi-use-after-free branch June 2, 2026 15:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant