Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit edacadab authored by Harshdeep Dhatt's avatar Harshdeep Dhatt
Browse files

msm: kgsl: Fix race condition in snapshot sysfs read



If there are concurrent sysfs reads of snapshot binary
there can be a race condition where the snapshot data
is prematurely free'd by one reader while the other reader
is still reading it. Fix this by proper refcounting using
an atomic.

CRs-Fixed: 902816
Change-Id: I7a156c3a22f5475df0394ae30328d0fd6140f3da
Signed-off-by: default avatarHarshdeep Dhatt <hdhatt@codeaurora.org>
parent 13848461
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -453,6 +453,7 @@ struct kgsl_device_private {
 * @work: worker to dump the frozen memory
 * @dump_gate: completion gate signaled by worker when it is finished.
 * @process: the process that caused the hang, if known.
 * @sysfs_read: An atomic for concurrent snapshot reads via syfs.
 */
struct kgsl_snapshot {
	u8 *start;
@@ -467,6 +468,7 @@ struct kgsl_snapshot {
	struct work_struct work;
	struct completion dump_gate;
	struct kgsl_process_private *process;
	atomic_t sysfs_read;
};

/**
+25 −11
Original line number Diff line number Diff line
@@ -684,6 +684,7 @@ void kgsl_device_snapshot(struct kgsl_device *device,
	snapshot->start = device->snapshot_memory.ptr;
	snapshot->ptr = device->snapshot_memory.ptr;
	snapshot->remain = device->snapshot_memory.size;
	atomic_set(&snapshot->sysfs_read, 0);

	header = (struct kgsl_snapshot_header *) snapshot->ptr;

@@ -787,6 +788,8 @@ static ssize_t snapshot_show(struct file *filep, struct kobject *kobj,

	mutex_lock(&device->mutex);
	snapshot = device->snapshot;
	if (snapshot != NULL)
		atomic_inc(&snapshot->sysfs_read);
	mutex_unlock(&device->mutex);

	/* Return nothing if we haven't taken a snapshot yet */
@@ -798,8 +801,10 @@ static ssize_t snapshot_show(struct file *filep, struct kobject *kobj,
	 * to allow userspace to bail if things go horribly wrong.
	 */
	ret = wait_for_completion_interruptible(&snapshot->dump_gate);
	if (ret)
	if (ret) {
		atomic_dec(&snapshot->sysfs_read);
		return ret;
	}

	obj_itr_init(&itr, buf, off, count);

@@ -808,7 +813,7 @@ static ssize_t snapshot_show(struct file *filep, struct kobject *kobj,
		goto done;

	/* Dump the memory pool if it exists */
	if (device->snapshot->mempool) {
	if (snapshot->mempool) {
		ret = obj_itr_out(&itr, snapshot->mempool,
				snapshot->mempool_size);
		if (ret == 0)
@@ -827,15 +832,22 @@ static ssize_t snapshot_show(struct file *filep, struct kobject *kobj,
	 * Make sure everything has been written out before destroying things.
	 * The best way to confirm this is to go all the way through without
	 * writing any bytes - so only release if we get this far and
	 * itr->write is 0
	 * itr->write is 0 and there are no concurrent reads pending
	 */

	if (itr.write == 0) {
		bool snapshot_free = false;

		mutex_lock(&device->mutex);
		if (atomic_dec_and_test(&snapshot->sysfs_read)) {
			device->snapshot = NULL;
			snapshot_free = true;
		}
		mutex_unlock(&device->mutex);

		list_for_each_entry_safe(obj, tmp, &snapshot->obj_list, node)
		if (snapshot_free) {
			list_for_each_entry_safe(obj, tmp,
						&snapshot->obj_list, node)
				kgsl_snapshot_put_object(obj);

			if (snapshot->mempool)
@@ -844,9 +856,11 @@ static ssize_t snapshot_show(struct file *filep, struct kobject *kobj,
			kfree(snapshot);
			KGSL_CORE_ERR("snapshot: objects released\n");
		}
		return 0;
	}

done:

	atomic_dec(&snapshot->sysfs_read);
	return itr.write;
}