Skip to content

Commit 20224d7

Browse files
committed
drm/msm/submit: Move copy_from_user ahead of locking bos
We cannot switch to using obj->resv for locking without first moving all the copy_from_user() ahead of submit_lock_objects(). Otherwise in the mm fault path we aquire mm->mmap_sem before obj lock, but in the submit path the order is reversed. Signed-off-by: Rob Clark <[email protected]> Reviewed-by: Kristian H. Kristensen <[email protected]> Signed-off-by: Rob Clark <[email protected]>
1 parent 599089c commit 20224d7

File tree

2 files changed

+82
-48
lines changed

2 files changed

+82
-48
lines changed

drivers/gpu/drm/msm/msm_gem.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,10 @@ struct msm_gem_submit {
240240
uint32_t type;
241241
uint32_t size; /* in dwords */
242242
uint64_t iova;
243+
uint32_t offset;/* in dwords */
243244
uint32_t idx; /* cmdstream buffer idx in bos[] */
245+
uint32_t nr_relocs;
246+
struct drm_msm_gem_submit_reloc *relocs;
244247
} *cmd; /* array of size nr_cmds */
245248
struct {
246249
uint32_t flags;

drivers/gpu/drm/msm/msm_gem_submit.c

Lines changed: 79 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,16 @@ static struct msm_gem_submit *submit_create(struct drm_device *dev,
6262

6363
void msm_gem_submit_free(struct msm_gem_submit *submit)
6464
{
65+
unsigned i;
66+
6567
dma_fence_put(submit->fence);
6668
list_del(&submit->node);
6769
put_pid(submit->pid);
6870
msm_submitqueue_put(submit->queue);
6971

72+
for (i = 0; i < submit->nr_cmds; i++)
73+
kfree(submit->cmd[i].relocs);
74+
7075
kfree(submit);
7176
}
7277

@@ -150,6 +155,66 @@ static int submit_lookup_objects(struct msm_gem_submit *submit,
150155
return ret;
151156
}
152157

158+
static int submit_lookup_cmds(struct msm_gem_submit *submit,
159+
struct drm_msm_gem_submit *args, struct drm_file *file)
160+
{
161+
unsigned i, sz;
162+
int ret = 0;
163+
164+
for (i = 0; i < args->nr_cmds; i++) {
165+
struct drm_msm_gem_submit_cmd submit_cmd;
166+
void __user *userptr =
167+
u64_to_user_ptr(args->cmds + (i * sizeof(submit_cmd)));
168+
169+
ret = copy_from_user(&submit_cmd, userptr, sizeof(submit_cmd));
170+
if (ret) {
171+
ret = -EFAULT;
172+
goto out;
173+
}
174+
175+
/* validate input from userspace: */
176+
switch (submit_cmd.type) {
177+
case MSM_SUBMIT_CMD_BUF:
178+
case MSM_SUBMIT_CMD_IB_TARGET_BUF:
179+
case MSM_SUBMIT_CMD_CTX_RESTORE_BUF:
180+
break;
181+
default:
182+
DRM_ERROR("invalid type: %08x\n", submit_cmd.type);
183+
return -EINVAL;
184+
}
185+
186+
if (submit_cmd.size % 4) {
187+
DRM_ERROR("non-aligned cmdstream buffer size: %u\n",
188+
submit_cmd.size);
189+
ret = -EINVAL;
190+
goto out;
191+
}
192+
193+
submit->cmd[i].type = submit_cmd.type;
194+
submit->cmd[i].size = submit_cmd.size / 4;
195+
submit->cmd[i].offset = submit_cmd.submit_offset / 4;
196+
submit->cmd[i].idx = submit_cmd.submit_idx;
197+
submit->cmd[i].nr_relocs = submit_cmd.nr_relocs;
198+
199+
sz = array_size(submit_cmd.nr_relocs,
200+
sizeof(struct drm_msm_gem_submit_reloc));
201+
/* check for overflow: */
202+
if (sz == SIZE_MAX) {
203+
ret = -ENOMEM;
204+
goto out;
205+
}
206+
submit->cmd[i].relocs = kmalloc(sz, GFP_KERNEL);
207+
ret = copy_from_user(submit->cmd[i].relocs, userptr, sz);
208+
if (ret) {
209+
ret = -EFAULT;
210+
goto out;
211+
}
212+
}
213+
214+
out:
215+
return ret;
216+
}
217+
153218
static void submit_unlock_unpin_bo(struct msm_gem_submit *submit,
154219
int i, bool backoff)
155220
{
@@ -301,7 +366,7 @@ static int submit_bo(struct msm_gem_submit *submit, uint32_t idx,
301366

302367
/* process the reloc's and patch up the cmdstream as needed: */
303368
static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *obj,
304-
uint32_t offset, uint32_t nr_relocs, uint64_t relocs)
369+
uint32_t offset, uint32_t nr_relocs, struct drm_msm_gem_submit_reloc *relocs)
305370
{
306371
uint32_t i, last_offset = 0;
307372
uint32_t *ptr;
@@ -327,18 +392,11 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob
327392
}
328393

329394
for (i = 0; i < nr_relocs; i++) {
330-
struct drm_msm_gem_submit_reloc submit_reloc;
331-
void __user *userptr =
332-
u64_to_user_ptr(relocs + (i * sizeof(submit_reloc)));
395+
struct drm_msm_gem_submit_reloc submit_reloc = relocs[i];
333396
uint32_t off;
334397
uint64_t iova;
335398
bool valid;
336399

337-
if (copy_from_user(&submit_reloc, userptr, sizeof(submit_reloc))) {
338-
ret = -EFAULT;
339-
goto out;
340-
}
341-
342400
if (submit_reloc.submit_offset % 4) {
343401
DRM_ERROR("non-aligned reloc offset: %u\n",
344402
submit_reloc.submit_offset);
@@ -694,6 +752,10 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
694752
if (ret)
695753
goto out;
696754

755+
ret = submit_lookup_cmds(submit, args, file);
756+
if (ret)
757+
goto out;
758+
697759
/* copy_*_user while holding a ww ticket upsets lockdep */
698760
ww_acquire_init(&submit->ticket, &reservation_ww_class);
699761
has_ww_ticket = true;
@@ -710,60 +772,29 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
710772
goto out;
711773

712774
for (i = 0; i < args->nr_cmds; i++) {
713-
struct drm_msm_gem_submit_cmd submit_cmd;
714-
void __user *userptr =
715-
u64_to_user_ptr(args->cmds + (i * sizeof(submit_cmd)));
716775
struct msm_gem_object *msm_obj;
717776
uint64_t iova;
718777

719-
ret = copy_from_user(&submit_cmd, userptr, sizeof(submit_cmd));
720-
if (ret) {
721-
ret = -EFAULT;
722-
goto out;
723-
}
724-
725-
/* validate input from userspace: */
726-
switch (submit_cmd.type) {
727-
case MSM_SUBMIT_CMD_BUF:
728-
case MSM_SUBMIT_CMD_IB_TARGET_BUF:
729-
case MSM_SUBMIT_CMD_CTX_RESTORE_BUF:
730-
break;
731-
default:
732-
DRM_ERROR("invalid type: %08x\n", submit_cmd.type);
733-
ret = -EINVAL;
734-
goto out;
735-
}
736-
737-
ret = submit_bo(submit, submit_cmd.submit_idx,
778+
ret = submit_bo(submit, submit->cmd[i].idx,
738779
&msm_obj, &iova, NULL);
739780
if (ret)
740781
goto out;
741782

742-
if (submit_cmd.size % 4) {
743-
DRM_ERROR("non-aligned cmdstream buffer size: %u\n",
744-
submit_cmd.size);
783+
if (!submit->cmd[i].size ||
784+
((submit->cmd[i].size + submit->cmd[i].offset) >
785+
msm_obj->base.size / 4)) {
786+
DRM_ERROR("invalid cmdstream size: %u\n", submit->cmd[i].size * 4);
745787
ret = -EINVAL;
746788
goto out;
747789
}
748790

749-
if (!submit_cmd.size ||
750-
((submit_cmd.size + submit_cmd.submit_offset) >
751-
msm_obj->base.size)) {
752-
DRM_ERROR("invalid cmdstream size: %u\n", submit_cmd.size);
753-
ret = -EINVAL;
754-
goto out;
755-
}
756-
757-
submit->cmd[i].type = submit_cmd.type;
758-
submit->cmd[i].size = submit_cmd.size / 4;
759-
submit->cmd[i].iova = iova + submit_cmd.submit_offset;
760-
submit->cmd[i].idx = submit_cmd.submit_idx;
791+
submit->cmd[i].iova = iova + (submit->cmd[i].offset * 4);
761792

762793
if (submit->valid)
763794
continue;
764795

765-
ret = submit_reloc(submit, msm_obj, submit_cmd.submit_offset,
766-
submit_cmd.nr_relocs, submit_cmd.relocs);
796+
ret = submit_reloc(submit, msm_obj, submit->cmd[i].offset * 4,
797+
submit->cmd[i].nr_relocs, submit->cmd[i].relocs);
767798
if (ret)
768799
goto out;
769800
}

0 commit comments

Comments
 (0)