/*
 * DF-5451 PoC — nexus_get_resource() debug kprintf leaks kernel pointers.
 *
 * sys/platform/pc64/x86_64/nexus.c:567 unconditionally prints
 *   "type %d rid %d startp %p countp %p - got %p\n"
 * via device_printf() for EVERY bus_get_resource() on a direct nexus child:
 *   - startp/countp are kernel stack addresses of the caller
 *   - the last %p is the kmalloc'd struct resource_list_entry (kernel heap)
 * The line lands on the console and in the message buffer; on this system
 * /var/log/messages is mode 644, i.e. readable by every local user.
 *
 * This module is a nexus child that performs one ordinary
 * bus_get_resource() call and nothing else.
 */
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/bus.h>
#include <sys/systm.h>

static int	nxget_probe(device_t);
static int	nxget_attach(device_t);
static void	nxget_identify(driver_t *, device_t);

static device_method_t nxget_methods[] = {
	DEVMETHOD(device_identify,	nxget_identify),
	DEVMETHOD(device_probe,		nxget_probe),
	DEVMETHOD(device_attach,	nxget_attach),
	DEVMETHOD_END
};

static driver_t nxget_driver = { "nxget", nxget_methods, 0 };
static devclass_t nxget_devclass;
DRIVER_MODULE(nxget, nexus, nxget_driver, nxget_devclass, NULL, NULL);

static void
nxget_identify(driver_t *drv, device_t parent)
{
	if (device_find_child(parent, "nxget", 0) == NULL)
		BUS_ADD_CHILD(parent, parent, 0, "nxget", 0);
}

static int
nxget_probe(device_t dev)
{
	device_set_desc(dev, "nexus get_resource printf PoC");
	return (0);
}

static int
nxget_attach(device_t dev)
{
	u_long start = 0, count = 0;
	int rid, error;

	if (bus_set_resource(dev, SYS_RES_MEMORY, 7, 0xE0000000UL, 0x1000UL, -1)) {
		kprintf("nxget: set_resource failed\n");
		return (ENXIO);
	}

	rid = 7;
	error = bus_get_resource(dev, SYS_RES_MEMORY, rid, &start, &count);
	kprintf("DF-5451: bus_get_resource returned %d start=%#lx count=%#lx "
	    "(the leaked-pointer line above came from nexus.c:567)\n",
	    error, start, count);
	return (0);
}
