DF-2685 / mlockswap.c
/* * DF-2685 trigger: mlock() zero-fill of swapped-out anonymous memory. * * Mechanism (stock DragonFly): * mlock() -> vm_map_wire() -> vm_fault_wire(user_wire=TRUE) * -> vm_fault(map, va, VM_PROT_READ, VM_FAULT_USER_WIRE) * In vm_fault_object(), TRYPAGER(fs) is FALSE for every fault that has * any VM_FAULT_WIRE_MASK flag set, so the swap/vnode pager is never asked * for the page. The fault falls through to the terminal-object path and * vm_page_zero_fill()s a freshly allocated page (vm_fault.c:2327). * Result: mlock() returns success and the process observes ZEROS where * its (swapped-out) data was. Silent memory destruction. * * Fix validated: TRYPAGER additionally allows VM_FAULT_USER_WIRE faults. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/mman.h> #define CHUNK (4UL<<20) static unsigned int pat(size_t off, size_t i){ return (unsigned int)(off>>12) ^ (unsigned int)i; } int main(void){ size_t total = (size_t)4.6*1024*1024*1024; /* RAM is 4GB + 4GB swap */ char *m = mmap(NULL, total, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); if (m == MAP_FAILED) { perror("mmap"); return 1; } for (size_t off = 0; off < total; off += CHUNK) { unsigned int *p = (unsigned int *)(m + off); for (size_t i = 0; i < CHUNK/4; i++) p[i] = pat(off,i); } printf("touched %zu MB; sleeping 8s for pageout\n", total>>20); fflush(stdout); sleep(8); system("swapinfo -h"); size_t lk = 64UL<<20; /* earliest-touched region */ if (mlock(m, lk) != 0) { printf("mlock: %s\n", strerror(errno)); return 1; } long bad = 0; for (size_t off = 0; off < lk; off += CHUNK) { unsigned int *p = (unsigned int *)(m + off); for (size_t i = 0; i < CHUNK/4; i++) if (p[i] != pat(off,i)) { bad++; if (bad < 4) printf("mismatch off=%zx i=%zx got=%08x want=%08x\n", off, i, p[i], pat(off,i)); } } printf("mlock-verify: bad=%ld of %d words\n", bad, (int)(lk/4)); if (bad) { printf("BUG REPRODUCED: mlock zero-filled swapped pages (silent data destruction)\n"); return 2; } printf("OK: data intact after mlock\n"); return 0; } |