⬢ DragonFlyBSD Kernel Audit
DF-4721 / trigger.c
← back to finding ↓ download raw
/*
 * DF-4721 trigger: the DESIGNED degraded RAID-5 write (ONE down data
 * subdisk, no reborn trickery, no revive) on an md-backed (malloc) vinum
 * drive.  bre5() builds the request group as
 *     rqe[0] = parity read  (launched)
 *     rqe[1] = good data block (launched)
 *     rqe[2] = down data block, XFR_BAD_SUBDISK (skipped at launch)
 * The last LAUNCHED element is rqe[1]; rqe[2] is a TRAILING skipped
 * element.  md completes biodone() inline inside dev_dstrategy(), so
 * rqe[1]'s completion runs complete_raid5_write() (XOR + parity write),
 * whose own inline completion drives rq->active to 0 and freerq()s the
 * whole request - while launch_requests() is still inside its launch
 * loop.  The loop then reads rqg->rqe[2].flags and rqg->next from the
 * FREED group (kmalloc freelist pointer overwrites rqg->next) and
 * dereferences the garbage -> kernel panic.
 *
 * buggy kernel:  panic in launch_requests (Fatal trap 12, fault VA 0x0/garbage)
 * fixed kernel:  write completes (degraded semantics), readback matches.
 */
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define VOL	"/dev/vinum/vol/rv"
#define OFF	(128 * 512)
#define LEN	(64 * 512)

unsigned char wbuf[LEN], rbuf[LEN];

int main(void)
{
	int fd, rc, i;

	for (i = 0; i < LEN / 2; i++) wbuf[i] = 0xC3;         /* block 1 */
	for (i = LEN / 2; i < LEN; i++) wbuf[i] = 0x3C;       /* block 2 */
	fd = open(VOL, O_RDWR);
	if (fd < 0) { perror("open"); return 2; }
	if (lseek(fd, OFF, SEEK_SET) < 0) { perror("lseek"); return 2; }
	rc = write(fd, wbuf, LEN);
	if (rc != LEN) {
		perror("write");
		printf("DF-4721 RESULT: write FAILED (%d)\n", rc);
		return 0;
	}
	printf("DF-4721: write OK (degraded write survived)\n");
	sleep(1);
	if (lseek(fd, OFF, SEEK_SET) < 0) { perror("lseek2"); return 2; }
	rc = read(fd, rbuf, LEN);
	if (rc != LEN) { perror("read"); printf("DF-4721 RESULT: read FAILED\n"); return 0; }
	for (i = 0; i < LEN; i++) if (rbuf[i] != wbuf[i]) {
		printf("DF-4721 RESULT: readback mismatch at %d (%02x != %02x)\n",
		    i, rbuf[i], wbuf[i]);
		return 1;
	}
	printf("DF-4721 RESULT: readback matches, no panic\n");
	return 0;
}