|
@@ -381,8 +381,26 @@ int handle_userfault(struct vm_fault *vmf, unsigned long reason)
|
|
|
* in __get_user_pages if userfaultfd_release waits on the
|
|
|
* caller of handle_userfault to release the mmap_sem.
|
|
|
*/
|
|
|
- if (unlikely(ACCESS_ONCE(ctx->released)))
|
|
|
+ if (unlikely(ACCESS_ONCE(ctx->released))) {
|
|
|
+ /*
|
|
|
+ * Don't return VM_FAULT_SIGBUS in this case, so a non
|
|
|
+ * cooperative manager can close the uffd after the
|
|
|
+ * last UFFDIO_COPY, without risking to trigger an
|
|
|
+ * involuntary SIGBUS if the process was starting the
|
|
|
+ * userfaultfd while the userfaultfd was still armed
|
|
|
+ * (but after the last UFFDIO_COPY). If the uffd
|
|
|
+ * wasn't already closed when the userfault reached
|
|
|
+ * this point, that would normally be solved by
|
|
|
+ * userfaultfd_must_wait returning 'false'.
|
|
|
+ *
|
|
|
+ * If we were to return VM_FAULT_SIGBUS here, the non
|
|
|
+ * cooperative manager would be instead forced to
|
|
|
+ * always call UFFDIO_UNREGISTER before it can safely
|
|
|
+ * close the uffd.
|
|
|
+ */
|
|
|
+ ret = VM_FAULT_NOPAGE;
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
/*
|
|
|
* Check that we can return VM_FAULT_RETRY.
|