/* DF-2912: l64_makevirginlabel unsigned underflow on tiny slices.
 *
 * vn disk with a 1-sector MBR slice -> d_total_size (512) < ressize
 * (4096) -> d_abase = d_total_size - ressize underflows to ~2^64.
 *
 * expect (vulnerable): d_abase = 0xfffffffffffffe00 (512-4096 wrapped)
 * expect (patched):    d_abase sane (clamped, no wrap)
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/disklabel64.h>
#include <sys/types.h>

static void
putle32(uint8_t *p, uint32_t v) { p[0]=v;p[1]=v>>8;p[2]=v>>16;p[3]=v>>24; }

int
main(int argc, char **argv)
{
	const char *dev = argc > 1 ? argv[1] : "/dev/vn0s1";
	struct disklabel64 dl;
	uint8_t img[63 * 512];
	uint8_t *mbr;
	int fd, rv;

	/* build a 31.5KB disk with a 1-sector slice at LBA 16 */
	memset(img, 0, sizeof(img));
	mbr = img;
	mbr[0x1be + 0] = 0x80;		/* bootable */
	mbr[0x1be + 4] = 0xA5;		/* DFly slice type */
	putle32(mbr + 0x1be + 8, 16);	/* start LBA 16 */
	putle32(mbr + 0x1be + 12, 1);	/* size: 1 sector */
	mbr[0x1FE] = 0x55; mbr[0x1FF] = 0xAA;
	{
		FILE *f = fopen("/tmp/df2912.img", "w");
		fwrite(img, 1, sizeof(img), f);
		fclose(f);
	}

	{
		char cmd[256];
		snprintf(cmd, sizeof(cmd), "vnconfig -c vn0 %s 2>/dev/null",
			 "/tmp/df2912.img");
		if (system(cmd) != 0)
				printf("DF2912 vnconfig attach rc!=0\n");
		sleep(1);
	}

	fd = open(dev, O_RDONLY);
	if (fd < 0) {
		printf("DF2912 open %s errno=%d (%s)\n", dev, errno,
		    strerror(errno));
		return 1;
	}
	rv = ioctl(fd, DIOCGDVIRGIN64, &dl);
	if (rv < 0) {
		printf("DF2912 DIOCGDVIRGIN64 rv=%d errno=%d (%s)\n", rv,
		    errno, strerror(errno));
		return 1;
	}
	printf("DF2912 d_total_size = %llu (512 expected)\n",
	    (unsigned long long)dl.d_total_size);
	printf("DF2912 d_abase      = 0x%016llx "
	    "(underflow shows 0xfffffffffffffe00)\n",
	    (unsigned long long)dl.d_abase);
	printf("DF2912 d_pbase      = 0x%016llx\n",
	    (unsigned long long)dl.d_pbase);
	printf("DF2912 d_pstop      = 0x%016llx\n",
	    (unsigned long long)dl.d_pstop);
	close(fd);
	system("vnconfig -u vn0 2>/dev/null");
	return 0;
}
