[PATCH 3.16 228/346] drm/msm: fix use of copy_from_user() while holding spinlock

From: Ben Hutchings
Date: Sun Nov 13 2016 - 22:36:14 EST


3.16.39-rc1 review patch. If anyone has any objections, please let me know.

------------------

From: Rob Clark <robdclark@xxxxxxxxx>

commit 89f82cbb0d5c0ab768c8d02914188aa2211cd2e3 upstream.

Use instead __copy_from_user_inatomic() and fallback to slow-path where
we drop and re-aquire the lock in case of fault.

Reported-by: Vaishali Thakkar <vaishali.thakkar@xxxxxxxxxx>
Signed-off-by: Rob Clark <robdclark@xxxxxxxxx>
Signed-off-by: Ben Hutchings <ben@xxxxxxxxxxxxxxx>
---
drivers/gpu/drm/msm/msm_gem_submit.c | 27 ++++++++++++++++++++++-----
1 file changed, 22 insertions(+), 5 deletions(-)

--- a/drivers/gpu/drm/msm/msm_gem_submit.c
+++ b/drivers/gpu/drm/msm/msm_gem_submit.c
@@ -55,6 +55,14 @@ static struct msm_gem_submit *submit_cre
return submit;
}

+static inline unsigned long __must_check
+copy_from_user_inatomic(void *to, const void __user *from, unsigned long n)
+{
+ if (access_ok(VERIFY_READ, from, n))
+ return __copy_from_user_inatomic(to, from, n);
+ return -EFAULT;
+}
+
static int submit_lookup_objects(struct msm_gem_submit *submit,
struct drm_msm_gem_submit *args, struct drm_file *file)
{
@@ -62,6 +70,7 @@ static int submit_lookup_objects(struct
int ret = 0;

spin_lock(&file->table_lock);
+ pagefault_disable();

for (i = 0; i < args->nr_bos; i++) {
struct drm_msm_gem_submit_bo submit_bo;
@@ -70,10 +79,15 @@ static int submit_lookup_objects(struct
void __user *userptr =
to_user_ptr(args->bos + (i * sizeof(submit_bo)));

- ret = copy_from_user(&submit_bo, userptr, sizeof(submit_bo));
- if (ret) {
- ret = -EFAULT;
- goto out_unlock;
+ ret = copy_from_user_inatomic(&submit_bo, userptr, sizeof(submit_bo));
+ if (unlikely(ret)) {
+ pagefault_enable();
+ spin_unlock(&file->table_lock);
+ ret = copy_from_user(&submit_bo, userptr, sizeof(submit_bo));
+ if (ret)
+ goto out;
+ spin_lock(&file->table_lock);
+ pagefault_disable();
}

if (submit_bo.flags & ~MSM_SUBMIT_BO_FLAGS) {
@@ -113,9 +127,12 @@ static int submit_lookup_objects(struct
}

out_unlock:
- submit->nr_bos = i;
+ pagefault_enable();
spin_unlock(&file->table_lock);

+out:
+ submit->nr_bos = i;
+
return ret;
}