โฌข DragonFlyBSD Kernel Audit
DF-4429 / victim_bo.c
โ† back to finding โ†“ download raw
/*
 * DF-4429 PoC companion โ€” victim: allocates a radeon GTT GEM BO filled with a
 * marker pattern and parks, so a second (attacker) user can sweep the card's
 * vma space and find the marker in a BO it holds no handle for.
 *
 * Uses only the public radeon DRM ioctls (no libdrm): DRM_IOCTL_RADEON_GEM_CREATE
 * + DRM_IOCTL_RADEON_GEM_MMAP would hand us our own offset โ€” we deliberately
 * do NOT print it as a hint; the attacker must find the BO by sweeping.
 *
 * Build:  cc -O2 -o victim_bo victim_bo.c
 */
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

#include <drm/radeon_drm.h>
/* build with -I/usr/src/sys/dev/drm/include/uapi (uapi headers not installed
 * into /usr/include on DFly); see build.sh */

int main(void)
{
	const char *card = "/dev/dri/card0";
	struct drm_radeon_gem_create gc = {
		.size = 4UL * 1024 * 1024,
		.alignment = 0,
		.initial_domain = RADEON_GEM_DOMAIN_GTT, /* user-visible TT BO */
		.flags = 0,
	};
	struct drm_radeon_gem_mmap mm = { 0 };
	int fd = open(card, O_RDWR);
	unsigned int i;
	int r;

	if (fd < 0) {
		perror("open card");
		return 1;
	}
	r = ioctl(fd, DRM_IOCTL_RADEON_GEM_CREATE, &gc);
	if (r) {
		perror("GEM_CREATE");
		return 1;
	}
	mm.handle = gc.handle;
	r = ioctl(fd, DRM_IOCTL_RADEON_GEM_MMAP, &mm);
	if (r) {
		perror("GEM_MMAP");
		return 1;
	}
	printf("victim: BO handle=%u size=%llu โ€” filling marker DF4429MARK...\n",
	       gc.handle, (unsigned long long)gc.size);
	{
		char *p = mmap(NULL, gc.size, PROT_READ | PROT_WRITE,
			       MAP_SHARED, fd, mm.addr_ptr);
		if (p == MAP_FAILED) {
			perror("victim mmap own BO");
			return 1;
		}
		for (i = 0; i + 10 < gc.size; i += 4096)
			memcpy(p + i, "DF4429MARK", 10);
	}
	printf("victim: parked. attacker may now run ./poc_mmap_bo --read\n");
	for (;;)
		pause();
	return 0;
}