drm/vc4: kms: Add functions to create the state objects
[platform/kernel/linux-rpi.git] / fs / userfaultfd.c
index fe6d804..d99d166 100644 (file)
@@ -1272,21 +1272,23 @@ static __always_inline void wake_userfault(struct userfaultfd_ctx *ctx,
 }
 
 static __always_inline int validate_range(struct mm_struct *mm,
-                                         __u64 start, __u64 len)
+                                         __u64 *start, __u64 len)
 {
        __u64 task_size = mm->task_size;
 
-       if (start & ~PAGE_MASK)
+       *start = untagged_addr(*start);
+
+       if (*start & ~PAGE_MASK)
                return -EINVAL;
        if (len & ~PAGE_MASK)
                return -EINVAL;
        if (!len)
                return -EINVAL;
-       if (start < mmap_min_addr)
+       if (*start < mmap_min_addr)
                return -EINVAL;
-       if (start >= task_size)
+       if (*start >= task_size)
                return -EINVAL;
-       if (len > task_size - start)
+       if (len > task_size - *start)
                return -EINVAL;
        return 0;
 }
@@ -1336,7 +1338,7 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
                goto out;
        }
 
-       ret = validate_range(mm, uffdio_register.range.start,
+       ret = validate_range(mm, &uffdio_register.range.start,
                             uffdio_register.range.len);
        if (ret)
                goto out;
@@ -1525,7 +1527,7 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
        if (copy_from_user(&uffdio_unregister, buf, sizeof(uffdio_unregister)))
                goto out;
 
-       ret = validate_range(mm, uffdio_unregister.start,
+       ret = validate_range(mm, &uffdio_unregister.start,
                             uffdio_unregister.len);
        if (ret)
                goto out;
@@ -1676,7 +1678,7 @@ static int userfaultfd_wake(struct userfaultfd_ctx *ctx,
        if (copy_from_user(&uffdio_wake, buf, sizeof(uffdio_wake)))
                goto out;
 
-       ret = validate_range(ctx->mm, uffdio_wake.start, uffdio_wake.len);
+       ret = validate_range(ctx->mm, &uffdio_wake.start, uffdio_wake.len);
        if (ret)
                goto out;
 
@@ -1716,7 +1718,7 @@ static int userfaultfd_copy(struct userfaultfd_ctx *ctx,
                           sizeof(uffdio_copy)-sizeof(__s64)))
                goto out;
 
-       ret = validate_range(ctx->mm, uffdio_copy.dst, uffdio_copy.len);
+       ret = validate_range(ctx->mm, &uffdio_copy.dst, uffdio_copy.len);
        if (ret)
                goto out;
        /*
@@ -1772,7 +1774,7 @@ static int userfaultfd_zeropage(struct userfaultfd_ctx *ctx,
                           sizeof(uffdio_zeropage)-sizeof(__s64)))
                goto out;
 
-       ret = validate_range(ctx->mm, uffdio_zeropage.range.start,
+       ret = validate_range(ctx->mm, &uffdio_zeropage.range.start,
                             uffdio_zeropage.range.len);
        if (ret)
                goto out;
@@ -1832,13 +1834,12 @@ static int userfaultfd_api(struct userfaultfd_ctx *ctx,
        if (copy_from_user(&uffdio_api, buf, sizeof(uffdio_api)))
                goto out;
        features = uffdio_api.features;
-       if (uffdio_api.api != UFFD_API || (features & ~UFFD_API_FEATURES)) {
-               memset(&uffdio_api, 0, sizeof(uffdio_api));
-               if (copy_to_user(buf, &uffdio_api, sizeof(uffdio_api)))
-                       goto out;
-               ret = -EINVAL;
-               goto out;
-       }
+       ret = -EINVAL;
+       if (uffdio_api.api != UFFD_API || (features & ~UFFD_API_FEATURES))
+               goto err_out;
+       ret = -EPERM;
+       if ((features & UFFD_FEATURE_EVENT_FORK) && !capable(CAP_SYS_PTRACE))
+               goto err_out;
        /* report all available features and ioctls to userland */
        uffdio_api.features = UFFD_API_FEATURES;
        uffdio_api.ioctls = UFFD_API_IOCTLS;
@@ -1851,6 +1852,11 @@ static int userfaultfd_api(struct userfaultfd_ctx *ctx,
        ret = 0;
 out:
        return ret;
+err_out:
+       memset(&uffdio_api, 0, sizeof(uffdio_api));
+       if (copy_to_user(buf, &uffdio_api, sizeof(uffdio_api)))
+               ret = -EFAULT;
+       goto out;
 }
 
 static long userfaultfd_ioctl(struct file *file, unsigned cmd,