Skip to content

Commit d780868

Browse files
widgetiiclaude
andauthored
mtd: fix use-after-free in find_ubi_for_mtd (segfault on musl arm64) (#171)
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>
1 parent d18902f commit d780868

1 file changed

Lines changed: 15 additions & 11 deletions

File tree

src/mtd.c

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ int find_ubi_for_mtd(int mtd_num) {
125125
DIR *d = opendir("/sys/class/ubi");
126126
if (!d)
127127
return -1;
128+
int ubi_num = -1;
128129
struct dirent *de;
129130
while ((de = readdir(d))) {
130131
if (strncmp(de->d_name, "ubi", 3) != 0)
@@ -134,20 +135,23 @@ int find_ubi_for_mtd(int mtd_num) {
134135
char path[128];
135136
snprintf(path, sizeof(path), "/sys/class/ubi/%s/mtd_num", de->d_name);
136137
FILE *f = fopen(path, "r");
137-
if (f) {
138-
int num;
139-
if (fscanf(f, "%d", &num) == 1 && num == mtd_num) {
140-
fclose(f);
141-
closedir(d);
142-
int ubi_num;
143-
sscanf(de->d_name, "ubi%d", &ubi_num);
144-
return ubi_num;
145-
}
146-
fclose(f);
138+
if (!f)
139+
continue;
140+
int num;
141+
bool match = fscanf(f, "%d", &num) == 1 && num == mtd_num;
142+
fclose(f);
143+
if (match) {
144+
/* Parse the number BEFORE closedir(): POSIX leaves the
145+
* dirent invalid after closedir, and musl actively
146+
* invalidates it (where glibc happens to keep it alive),
147+
* so reading de->d_name after closedir is a segfault on
148+
* the aarch64 musl build. */
149+
sscanf(de->d_name, "ubi%d", &ubi_num);
150+
break;
147151
}
148152
}
149153
closedir(d);
150-
return -1;
154+
return ubi_num;
151155
}
152156

153157
int enum_ubi_volumes(int ubi_num, ubi_vol_info_t *vols, int max_vols) {

0 commit comments

Comments
 (0)