/*
 * ktr_entropy.c — force kernel-stack variance between PSIG records.
 * Tests Council/ChatGPT's high-value condition: does the padding hole
 * carry different values across invocations when interleaved with
 * other syscalls?
 */
#include <sys/types.h>
#include <sys/ktrace.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

static void noop(int s) { (void)s; }

int
main(void)
{
	pid_t pid = getpid();
	unlink("/tmp/ktr_entropy.out");
	int fd = open("/tmp/ktr_entropy.out", O_CREAT|O_WRONLY|O_TRUNC, 0600);
	if (fd < 0) { perror("open"); return 1; }
	close(fd);

	if (ktrace("/tmp/ktr_entropy.out", KTROP_SET,
	           KTRFAC_PSIG, pid) < 0) { perror("ktrace"); return 1; }

	signal(SIGUSR1, noop);
	signal(SIGUSR2, noop);
	signal(SIGHUP,  noop);
	signal(SIGURG,  noop);

	/* 32 iterations, each preceded by a DIFFERENT syscall path to
	 * vary what's left on the kernel stack before sendsig() runs. */
	int sigs[] = { SIGUSR1, SIGUSR2, SIGHUP, SIGURG };
	for (int i = 0; i < 32; i++) {
		switch (i % 8) {
		case 0: { struct stat st; stat("/etc/passwd", &st); break; }
		case 1: { int s = socket(AF_UNIX, SOCK_STREAM, 0); close(s); break; }
		case 2: { getppid(); getpgrp(); getsid(0); break; }
		case 3: { char buf[64]; getcwd(buf, sizeof buf); break; }
		case 4: { int f = open("/dev/null", O_RDONLY);
		          if (f >= 0) { read(f, (char[16]){0}, 16); close(f); }
		          break; }
		case 5: { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); break; }
		case 6: { char nm[64]; gethostname(nm, sizeof nm); break; }
		case 7: { (void)getuid(); (void)getgid(); break; }
		}
		kill(pid, sigs[i % 4]);
	}

	ktrace(NULL, KTROP_CLEAR, KTRFAC_PSIG, pid);

	/* Parse and dump padding bytes per record */
	fd = open("/tmp/ktr_entropy.out", O_RDONLY);
	if (fd < 0) { perror("open ro"); return 1; }
	unsigned char b[224];   /* one record */
	int rec = 0, hits = 0, zeros = 0;
	unsigned int seen[64] = {0}; int n_seen = 0;
	while (read(fd, b, sizeof b) == (ssize_t)sizeof b) {
		unsigned int pad = b[60] | (b[61]<<8) | (b[62]<<16) | (b[63]<<24);
		printf("rec %02d  signo=%-3d  PAD=0x%08x  action=...\n",
		       rec++, b[56], pad);
		if (pad == 0) zeros++;
		else { hits++;
			int dup = 0;
			for (int k = 0; k < n_seen; k++) if (seen[k] == pad) dup = 1;
			if (!dup && n_seen < 64) seen[n_seen++] = pad;
		}
	}
	close(fd);
	printf("\nSummary: %d records, %d non-zero, %d zero, %d unique non-zero values\n",
	       rec, hits, zeros, n_seen);
	if (n_seen > 1) printf("ENTROPY CONFIRMED: padding carries varying kernel data\n");
	return 0;
}
