DragonFlyBSD Kernel Audit
DF-2733 / pollclamp.c
← back to finding ↓ download raw
/*
 * DF-2733 PoC: poll() silently truncates nfds to kern.maxfilesperproc*2
 * (sys/kern/sys_generic.c dopoll(), lines 1639-1640) instead of returning
 * EINVAL. Descriptors whose pollfd index is beyond the clamp are silently
 * ignored -- the only ready descriptor in the set is dropped without any
 * error.
 *
 * Build:  cc -O -o pollclamp pollclamp.c
 */
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/sysctl.h>
#include <poll.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main(void)
{
	size_t mfp = 0;
	size_t len = sizeof(mfp);
	long clamp, nfds;
	struct pollfd *fds;
	int pf[2];
	int nready, i;

	if (sysctlbyname("kern.maxfilesperproc", &mfp, &len, NULL, 0) < 0) {
		perror("sysctl kern.maxfilesperproc"); return 1;
	}
	clamp = (long)mfp * 2;
	nfds = clamp + 32;
	printf("kern.maxfilesperproc = %zu -> dopoll clamp = %ld; requesting nfds = %ld\n",
	       mfp, clamp, nfds);

	if (pipe(pf) < 0) { perror("pipe"); return 1; }
	if (write(pf[1], "x", 1) != 1) { perror("write pipe"); return 1; }

	fds = mmap(NULL, nfds * sizeof(struct pollfd), PROT_READ | PROT_WRITE,
		   MAP_ANON | MAP_PRIVATE, -1, 0);
	if (fds == MAP_FAILED) { perror("mmap"); return 1; }
	for (i = 0; i < nfds; i++) {
		fds[i].fd = -1;
		fds[i].events = 0;
		fds[i].revents = 0x5a5a;
	}

	/* control: ready fd INSIDE the clamp */
	fds[5].fd = pf[0];
	fds[5].events = POLLIN;
	nready = poll(fds, nfds, 0);
	printf("poll() with ready fd at index 5      -> %d (errno %d)\n",
	       nready, errno);

	fds[5].fd = -1;
	fds[5].events = 0;
	fds[5].revents = 0x5a5a;

	/* ready fd BEYOND the clamp: silently dropped? */
	fds[clamp + 16].fd = pf[0];
	fds[clamp + 16].events = POLLIN;
	errno = 0;
	nready = poll(fds, nfds, 0);
	printf("poll() with ready fd at idx clamp+16 -> %d (errno %d)  %s\n",
	       nready, errno,
	       nready == 0 ? "<-- SILENTLY IGNORED (POSIX: EINVAL or report)" :
	       "reported");
	printf("DONE df2733\n");
	return 0;
}