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

Commit 33f9492c authored by Carter Cooper's avatar Carter Cooper Committed by Gerrit - the friendly Code Review server
Browse files

msm: kgsl: Properly remove ref count on gpuobj_sync failure



The user can pass bad data into kgsl_ioctl_gpuobj_sync(). If
_copy_from_user() fails do to bad data, undo any current
references taken through this ioctl call.

Change-Id: I56195520b9dadba20ee419658fc2cbb282b8449c
Signed-off-by: default avatarCarter Cooper <ccooper@codeaurora.org>
Signed-off-by: default avatarsamit vats <svats@codeaurora.org>
parent 68c107d9
Loading
Loading
Loading
Loading
+15 −19
Original line number Diff line number Diff line
/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -2839,7 +2839,7 @@ long kgsl_ioctl_gpuobj_sync(struct kgsl_device_private *dev_priv,
	long ret = 0;
	bool full_flush = false;
	uint64_t size = 0;
	int i, count = 0;
	int i;
	void __user *ptr;

	if (param->count == 0 || param->count > 128)
@@ -2851,8 +2851,8 @@ long kgsl_ioctl_gpuobj_sync(struct kgsl_device_private *dev_priv,

	entries = kzalloc(param->count * sizeof(*entries), GFP_KERNEL);
	if (entries == NULL) {
		ret = -ENOMEM;
		goto out;
		kfree(objs);
		return -ENOMEM;
	}

	ptr = to_user_ptr(param->objs);
@@ -2869,36 +2869,32 @@ long kgsl_ioctl_gpuobj_sync(struct kgsl_device_private *dev_priv,
		if (entries[i] == NULL)
			continue;

		count++;

		if (!(objs[i].op & KGSL_GPUMEM_CACHE_RANGE))
			size += entries[i]->memdesc.size;
		else if (objs[i].offset < entries[i]->memdesc.size)
			size += (entries[i]->memdesc.size - objs[i].offset);

		full_flush = check_full_flush(size, objs[i].op);
		if (full_flush)
			break;
		if (full_flush) {
			trace_kgsl_mem_sync_full_cache(i, size);
			flush_cache_all();
			goto out;
		}

		ptr += sizeof(*objs);
	}

	if (full_flush) {
		trace_kgsl_mem_sync_full_cache(count, size);
		flush_cache_all();
	} else {
	for (i = 0; !ret && i < param->count; i++)
		if (entries[i])
			ret = _kgsl_gpumem_sync_cache(entries[i],
					objs[i].offset, objs[i].length,
					objs[i].op);
	}

out:
	for (i = 0; i < param->count; i++)
		if (entries[i])
			kgsl_mem_entry_put(entries[i]);

out:
	kfree(entries);
	kfree(objs);