#include #include #include #include #include #include #include #include #include int userfaultfd(int flags) { return syscall(__NR_userfaultfd, flags); } // Only exists since v4.10, so not in most distros... #ifndef UFFD_FEATURE_EVENT_FORK #define UFFD_FEATURE_EVENT_FORK 2 #endif // Arbitrary; needs to be some PAGE_SIZE multiple #define REGION_SIZE (2 * 1024 * 1024) int uffd_setup(void *base, size_t size) { int uffd; struct uffdio_api ufa = { .api = UFFD_API, .features = UFFD_FEATURE_EVENT_FORK, .ioctls = 0, }; struct uffdio_register ufr = { .range.start = (unsigned long)base, .range.len = size, .mode = UFFDIO_REGISTER_MODE_MISSING, .ioctls = 0, }; uffd = userfaultfd(0); ioctl(uffd, UFFDIO_API, &ufa); ioctl(uffd, UFFDIO_REGISTER, &ufr); return uffd; } void *thr_uffd(void *unused) { void *base; int uffd; struct uffd_msg msg; struct rlimit rlimit; base = mmap(NULL, REGION_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); uffd = uffd_setup(base, REGION_SIZE); rlimit.rlim_cur = 0; rlimit.rlim_max = 0; setrlimit(RLIMIT_NOFILE, &rlimit); read(uffd, &msg, sizeof(msg)); return NULL; } void *thr_clone(void *unused) { fork(); return NULL; } int main(int argc, char *argv[]) { pthread_t p_uffd, p_clone; pthread_create(&p_uffd, 0, thr_uffd, NULL); usleep(1000); pthread_create(&p_clone, 0, thr_clone, NULL); usleep(1000); return 0; }