Skip to content

Commit 83271f6

Browse files
colincrossgregkh
authored andcommitted
ion: hold reference to handle after ion_uhandle_get
commit 1262ab1846cf76f7549c66ef709120dbfbe6d49f (ion: replace userspace handle cookies with idr) broke the locking in ion. The ION_IOC_FREE and ION_IOC_MAP ioctls were relying on ion_handle_validate to detect the case where a call raced with another ION_IOC_FREE which may have freed the struct ion_handle. Rename ion_uhandle_get to ion_handle_get_by_id, and have it take the client lock and return with an extra reference to the handle. Make each caller put its reference once it is done with the handle. Also modify users of ion_handle_validate to continue to hold the client lock after calling ion_handle_validate until they are done with the handle, and warn if ion_handle_validate is called without the client lock held. Signed-off-by: Colin Cross <[email protected]> Signed-off-by: John Stultz <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 687258f commit 83271f6

File tree

1 file changed

+41
-15
lines changed
  • drivers/staging/android/ion

1 file changed

+41
-15
lines changed

drivers/staging/android/ion/ion.c

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,14 @@ static void ion_handle_get(struct ion_handle *handle)
383383

384384
static int ion_handle_put(struct ion_handle *handle)
385385
{
386-
return kref_put(&handle->ref, ion_handle_destroy);
386+
struct ion_client *client = handle->client;
387+
int ret;
388+
389+
mutex_lock(&client->lock);
390+
ret = kref_put(&handle->ref, ion_handle_destroy);
391+
mutex_unlock(&client->lock);
392+
393+
return ret;
387394
}
388395

389396
static struct ion_handle *ion_handle_lookup(struct ion_client *client,
@@ -403,14 +410,24 @@ static struct ion_handle *ion_handle_lookup(struct ion_client *client,
403410
return ERR_PTR(-EINVAL);
404411
}
405412

406-
static struct ion_handle *ion_uhandle_get(struct ion_client *client, int id)
413+
static struct ion_handle *ion_handle_get_by_id(struct ion_client *client,
414+
int id)
407415
{
408-
return idr_find(&client->idr, id);
416+
struct ion_handle *handle;
417+
418+
mutex_lock(&client->lock);
419+
handle = idr_find(&client->idr, id);
420+
if (handle)
421+
ion_handle_get(handle);
422+
mutex_unlock(&client->lock);
423+
424+
return handle ? handle : ERR_PTR(-EINVAL);
409425
}
410426

411427
static bool ion_handle_validate(struct ion_client *client, struct ion_handle *handle)
412428
{
413-
return (ion_uhandle_get(client, handle->id) == handle);
429+
WARN_ON(!mutex_is_locked(&client->lock));
430+
return (idr_find(&client->idr, handle->id) == handle);
414431
}
415432

416433
static int ion_handle_add(struct ion_client *client, struct ion_handle *handle)
@@ -503,11 +520,11 @@ struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
503520

504521
mutex_lock(&client->lock);
505522
ret = ion_handle_add(client, handle);
523+
mutex_unlock(&client->lock);
506524
if (ret) {
507525
ion_handle_put(handle);
508526
handle = ERR_PTR(ret);
509527
}
510-
mutex_unlock(&client->lock);
511528

512529
return handle;
513530
}
@@ -527,8 +544,8 @@ void ion_free(struct ion_client *client, struct ion_handle *handle)
527544
mutex_unlock(&client->lock);
528545
return;
529546
}
530-
ion_handle_put(handle);
531547
mutex_unlock(&client->lock);
548+
ion_handle_put(handle);
532549
}
533550
EXPORT_SYMBOL(ion_free);
534551

@@ -1021,14 +1038,15 @@ struct dma_buf *ion_share_dma_buf(struct ion_client *client,
10211038

10221039
mutex_lock(&client->lock);
10231040
valid_handle = ion_handle_validate(client, handle);
1024-
mutex_unlock(&client->lock);
10251041
if (!valid_handle) {
10261042
WARN(1, "%s: invalid handle passed to share.\n", __func__);
1043+
mutex_unlock(&client->lock);
10271044
return ERR_PTR(-EINVAL);
10281045
}
1029-
10301046
buffer = handle->buffer;
10311047
ion_buffer_get(buffer);
1048+
mutex_unlock(&client->lock);
1049+
10321050
dmabuf = dma_buf_export(buffer, &dma_buf_ops, buffer->size, O_RDWR);
10331051
if (IS_ERR(dmabuf)) {
10341052
ion_buffer_put(buffer);
@@ -1081,18 +1099,24 @@ struct ion_handle *ion_import_dma_buf(struct ion_client *client, int fd)
10811099
handle = ion_handle_lookup(client, buffer);
10821100
if (!IS_ERR(handle)) {
10831101
ion_handle_get(handle);
1102+
mutex_unlock(&client->lock);
10841103
goto end;
10851104
}
1105+
mutex_unlock(&client->lock);
1106+
10861107
handle = ion_handle_create(client, buffer);
10871108
if (IS_ERR(handle))
10881109
goto end;
1110+
1111+
mutex_lock(&client->lock);
10891112
ret = ion_handle_add(client, handle);
1113+
mutex_unlock(&client->lock);
10901114
if (ret) {
10911115
ion_handle_put(handle);
10921116
handle = ERR_PTR(ret);
10931117
}
1118+
10941119
end:
1095-
mutex_unlock(&client->lock);
10961120
dma_buf_put(dmabuf);
10971121
return handle;
10981122
}
@@ -1156,12 +1180,11 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
11561180
if (copy_from_user(&data, (void __user *)arg,
11571181
sizeof(struct ion_handle_data)))
11581182
return -EFAULT;
1159-
mutex_lock(&client->lock);
1160-
handle = ion_uhandle_get(client, data.handle);
1161-
mutex_unlock(&client->lock);
1162-
if (!handle)
1163-
return -EINVAL;
1183+
handle = ion_handle_get_by_id(client, data.handle);
1184+
if (IS_ERR(handle))
1185+
return PTR_ERR(handle);
11641186
ion_free(client, handle);
1187+
ion_handle_put(handle);
11651188
break;
11661189
}
11671190
case ION_IOC_SHARE:
@@ -1172,8 +1195,11 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
11721195

11731196
if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
11741197
return -EFAULT;
1175-
handle = ion_uhandle_get(client, data.handle);
1198+
handle = ion_handle_get_by_id(client, data.handle);
1199+
if (IS_ERR(handle))
1200+
return PTR_ERR(handle);
11761201
data.fd = ion_share_dma_buf_fd(client, handle);
1202+
ion_handle_put(handle);
11771203
if (copy_to_user((void __user *)arg, &data, sizeof(data)))
11781204
return -EFAULT;
11791205
if (data.fd < 0)

0 commit comments

Comments
 (0)