userfaultfd: check VM_MAYWRITE was set after verifying the uffd is registered
[sfrench/cifs-2.6.git] / fs / userfaultfd.c
index 356d2b8568c1424d1d1935c451e65c7db13aab62..7a85e609fc276f28dd80c8dc481e383094d1dfe9 100644 (file)
@@ -1361,6 +1361,19 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
                ret = -EINVAL;
                if (!vma_can_userfault(cur))
                        goto out_unlock;
+
+               /*
+                * UFFDIO_COPY will fill file holes even without
+                * PROT_WRITE. This check enforces that if this is a
+                * MAP_SHARED, the process has write permission to the backing
+                * file. If VM_MAYWRITE is set it also enforces that on a
+                * MAP_SHARED vma: there is no F_WRITE_SEAL and no further
+                * F_WRITE_SEAL can be taken until the vma is destroyed.
+                */
+               ret = -EPERM;
+               if (unlikely(!(cur->vm_flags & VM_MAYWRITE)))
+                       goto out_unlock;
+
                /*
                 * If this vma contains ending address, and huge pages
                 * check alignment.
@@ -1406,6 +1419,7 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
                BUG_ON(!vma_can_userfault(vma));
                BUG_ON(vma->vm_userfaultfd_ctx.ctx &&
                       vma->vm_userfaultfd_ctx.ctx != ctx);
+               WARN_ON(!(vma->vm_flags & VM_MAYWRITE));
 
                /*
                 * Nothing to do: this vma is already registered into this
@@ -1560,6 +1574,8 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
                if (!vma->vm_userfaultfd_ctx.ctx)
                        goto skip;
 
+               WARN_ON(!(vma->vm_flags & VM_MAYWRITE));
+
                if (vma->vm_start > start)
                        start = vma->vm_start;
                vma_end = min(end, vma->vm_end);