@@ -1555,10 +1555,10 @@ drm_syncobj_timeline_signal_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_private)
{
struct drm_syncobj_timeline_array *args = data;
+ uint64_t __user *points = u64_to_user_ptr(args->points);
+ uint32_t i, j, count = args->count_handles;
struct drm_syncobj **syncobjs;
struct dma_fence_chain **chains;
- uint64_t *points;
- uint32_t i, j;
int ret;
if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE))
@@ -1570,33 +1570,22 @@ drm_syncobj_timeline_signal_ioctl(struct drm_device *dev, void *data,
if (args->count_handles == 0)
return -EINVAL;
+ if (!access_ok(points, count * sizeof(*points)))
+ return -EFAULT;
+
ret = drm_syncobj_array_find(file_private,
u64_to_user_ptr(args->handles),
- args->count_handles,
+ count,
&syncobjs);
if (ret < 0)
return ret;
- points = kmalloc_array(args->count_handles, sizeof(*points),
- GFP_KERNEL);
- if (!points) {
- ret = -ENOMEM;
- goto out;
- }
- if (!u64_to_user_ptr(args->points)) {
- memset(points, 0, args->count_handles * sizeof(uint64_t));
- } else if (copy_from_user(points, u64_to_user_ptr(args->points),
- sizeof(uint64_t) * args->count_handles)) {
- ret = -EFAULT;
- goto err_points;
- }
-
- chains = kmalloc_array(args->count_handles, sizeof(void *), GFP_KERNEL);
+ chains = kmalloc_array(count, sizeof(void *), GFP_KERNEL);
if (!chains) {
ret = -ENOMEM;
- goto err_points;
+ goto out;
}
- for (i = 0; i < args->count_handles; i++) {
+ for (i = 0; i < count; i++) {
chains[i] = dma_fence_chain_alloc();
if (!chains[i]) {
for (j = 0; j < i; j++)
@@ -1606,19 +1595,24 @@ drm_syncobj_timeline_signal_ioctl(struct drm_device *dev, void *data,
}
}
- for (i = 0; i < args->count_handles; i++) {
+ for (i = 0; i < count; i++) {
struct dma_fence *fence = dma_fence_get_stub();
+ u64 point = 0;
- drm_syncobj_add_point(syncobjs[i], chains[i],
- fence, points[i]);
+ if (points && get_user(point, points++)) {
+ ret = -EFAULT;
+ for (j = i; j < count; j++)
+ dma_fence_chain_free(chains[j]);
+ goto err_chains;
+ }
+
+ drm_syncobj_add_point(syncobjs[i], chains[i], fence, point);
dma_fence_put(fence);
}
err_chains:
kfree(chains);
-err_points:
- kfree(points);
out:
- drm_syncobj_array_free(syncobjs, args->count_handles);
+ drm_syncobj_array_free(syncobjs, count);
return ret;
}