DF-5010 / vkd_bounds.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | /* * DF-5010 — vkernel vdisk (vkd) bounds-check verification trigger. * * Runs as PID 1 inside the vkernel guest: * ./vkernel64 -m 256M -r root.img -r plain.img -R cow.img \ * -e init_path=/poc * /dev/vkd1 = plain.img (non-COW, 16 MB) * /dev/vkd2 = cow.img (COW, 8 MB) * * All I/O 512-byte aligned so the dscheck() sector-alignment rejection * (sys/kern/subr_diskslice.c:131-143) does not mask the bounds behaviour. * Expected on a stock kernel: * in-bounds 512B write/read -> succeeds * OOB write/read @1TB, @size+512 -> -1 EINVAL (dscheck subr_diskslice.c:253) * at-exact-end write -> 0 (EOF semantics) * the vkernel process SURVIVES everything * (init exits afterwards -> "panic: Going nowhere without my init" is * expected and harmless.) */ #include <sys/mount.h> #include <sys/types.h> #include <fcntl.h> #include <stdarg.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <errno.h> static char buf512[512]; static int logfd = 2; /* /marker once opened */ static void logmark(const char *fmt, ...) { char buf[160]; va_list ap; int n; va_start(ap, fmt); n = vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); if (n > 0) { write(logfd, buf, n); write(2, buf, n); } } static void tryop(const char *what, int fd, int wr, off_t off) { ssize_t n; int save; if (wr) n = pwrite(fd, buf512, 512, off); else n = pread(fd, buf512, 512, off); save = (n < 0) ? errno : 0; logmark("[*] %-28s @%#11jx -> %zd%s%s\n", what, (intmax_t)off, n, (n < 0) ? " errno=" : "", (n < 0) ? strerror(save) : ""); } int main(void) { int fd; memset(buf512, 0x5a, sizeof(buf512)); /* markers also go to a file on the root disk (console may be dead) */ logfd = open("/marker", O_WRONLY | O_CREAT | O_TRUNC, 0644); mkdir("/dev", 0755); if (mount("devfs", "/dev", 0, NULL) < 0) logmark("[-] mount devfs failed errno=%d\n", errno); else logmark("[+] devfs mounted\n"); fd = open("/dev/vkd1", O_RDWR); if (fd < 0) { logmark("[-] open /dev/vkd1 failed errno=%d\n", errno); _exit(1); } logmark("[+] vkd1 (non-COW 16MB) open\n"); tryop("vkd1 write in-bounds", fd, 1, 0); tryop("vkd1 write @exact-EOF", fd, 1, 16 * 1024 * 1024); tryop("vkd1 write @1TB", fd, 1, 1LL << 40); close(fd); fd = open("/dev/vkd2", O_RDWR); if (fd < 0) { logmark("[-] open /dev/vkd2 failed errno=%d\n", errno); _exit(1); } logmark("[+] vkd2 (COW 8MB, map_buf) open\n"); tryop("vkd2 write in-bounds", fd, 1, 0); tryop("vkd2 write @size+512", fd, 1, 8 * 1024 * 1024 + 512); tryop("vkd2 write @1TB", fd, 1, 1LL << 40); tryop("vkd2 read @1TB", fd, 0, 1LL << 40); close(fd); logmark("[+] vkernel survived all OOB attempts " "(dscheck bounds enforcement held)\n"); _exit(0); } |