DF-2733 / pollclamp.c
/* * 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; } |