/*
 * DF-2674 - vm_map_growstack() maps grown stack pages VM_PROT_ALL (RWX),
 * ignoring the original stack protection (RW, set by exec at
 * sys/kern/kern_exec.c:991-995).  The grown region is silently executable.
 *
 * Uses /proc/self/map (DragonFly procfs format:
 *   0xSTART 0xEND res res obj PERM ref 0 flags COW type path )
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

typedef struct { unsigned long s, e; char perm[8]; } reg_t;

static int
read_regs(reg_t *regs, int max, unsigned long lo, unsigned long hi)
{
	FILE *f = fopen("/proc/self/map", "r");
	char line[512];
	int n = 0;

	if (!f) { perror("/proc/self/map"); exit(1); }
	while (fgets(line, sizeof(line), f) && n < max) {
		reg_t r;
		char perm[8] = { 0 };
		unsigned long s, e;
		if (sscanf(line, "0x%lx 0x%lx %*d %*d %*p %7s",
			   &s, &e, perm) != 3)
			continue;
		if (e <= lo || s >= hi)
			continue;
		r.s = s; r.e = e;
		strncpy(r.perm, perm, sizeof(r.perm) - 1);
		regs[n++] = r;
	}
	fclose(f);
	return n;
}

static void
show(const char *tag, reg_t *regs, int n)
{
	int i;
	printf("---- %s ----\n", tag);
	for (i = 0; i < n; i++)
		printf("0x%016lx-0x%016lx %s\n", regs[i].s, regs[i].e,
		       regs[i].perm);
}

int
main(void)
{
	reg_t regs[64];
	volatile char probe;
	unsigned long sp = (unsigned long)&probe;
	unsigned long lo = sp - (64UL << 20), hi = sp + (16UL * 1024);
	int n, i, exec_before = 0, exec_after = 0;
	unsigned long lowest;

	n = read_regs(regs, 64, lo, hi);
	show("before growth", regs, n);
	lowest = regs[0].s;
	for (i = 0; i < n; i++) {
		if (strchr(regs[i].perm, 'x'))
			exec_before++;
		if (regs[i].s < lowest)
			lowest = regs[i].s;
	}

	/* fault below the current stack mapping -> vm_map_growstack */
	*(volatile char *)(lowest - 4096) = 1;

	n = read_regs(regs, 64, lo, hi);
	show("after growth", regs, n);
	for (i = 0; i < n; i++)
		if (strchr(regs[i].perm, 'x'))
			exec_after++;

	printf("executable regions near stack: before=%d after=%d\n",
	       exec_before, exec_after);
	if (exec_after > exec_before) {
		printf
		    ("VERDICT: REPRODUCED - stack growth created executable "
		     "(rwx) stack mapping\n");
		return (0);
	}
	printf("VERDICT: not reproduced\n");
	return (1);
}
