A flaw was found in the Linux kernels handling of fork failure when dealing with event messages in the userfaultfd code. Failure to fork correctly can lead to a situation where a fork event will be removed from an already freed list of events with userfaultfd_ctx_put(). The userfault events are part of the slab cache, and the secondary free could only free other event list objects as the free mechanism uses the underlying kmem_cache_* implementation making generic use-after-free style attacks less effective. While technically a use after free style flaw, at this time Red Hat Product security believes this flaw to be difficult to exploit but this may change in the future. From the commit: When reading the event from the uffd, we put it on a temporary fork_event list to detect if we can still access it after releasing and retaking the event_wqh.lock. If fork aborts and removes the event from the fork_event all is fine as long as we're still in the userfault read context and fork_event head is still alive. We've [forgotten] to put the event allocated in the fork kernel stack, back from fork_event list-head to the event_wqh head, before returning from userfaultfd_ctx_read, because the fork_event head lifetime is limited to the userfaultfd_ctx_read stack lifetime. Forgetting to move the event back to its event_wqh place then results in __remove_wait_queue(&ctx->event_wqh, &ewq->wq); in userfaultfd_event_wait_completion to remove it from a head that has been already freed from the reader stack. This could only happen if resolve_userfault_fork failed (for example if there are no file descriptors available to allocate the fork uffd). If it succeeded it was put back correctly. Furthermore, after find_userfault_evt receives a fork event, the forked userfault context in fork_nctx and uwq->msg.arg.reserved.reserved1 can be released by the fork thread as soon as the event_wqh.lock is released. Taking a reference on the fork_nctx before dropping the lock prevents an use after free in resolve_userfault_fork(). If the fork side aborted and it already released everything, we still try to succeed resolve_userfault_fork(), if possible. -- end --- References: https://marc.info/?t=150351212000001&r=1&w=2 An upstream patch: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=384632e67e0829deb8015ee6ad916b180049d252
Acknowledgments: Name: Andrea Arcangeli (Red Hat Engineering)
Statement: This issue does not affect the Linux kernel packages as shipped with Red Hat Enterprise Linux 5 and 6. This issue affects the Linux kernel packages as shipped with Red Hat Enterprise Linux 7, realtime, MRG-2 prior to version kernel-3.10.0-781. The kernel-alt package already as shipped contains this fix.
Created kernel tracking bugs for this issue: Affects: fedora-all [bug 1545039]
This was fixed for Fedora with the 4.14.13 stable kernel updates.
Also, the commit in the first comment is only a partial fix, https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=0cbb4b4f4c44f54af268969b18d8deda63aded59 finishes the job
This issue has been addressed in the following products: Red Hat Enterprise Linux 7 Via RHSA-2018:0676 https://access.redhat.com/errata/RHSA-2018:0676
This issue has been addressed in the following products: Red Hat Enterprise Linux 7 Via RHSA-2018:1062 https://access.redhat.com/errata/RHSA-2018:1062