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

Commit 6d4f3d01 authored by Manoj Prabhu B's avatar Manoj Prabhu B
Browse files

diag: Copy length and buffer locally to send to userspace client



To prevent possible use after free case of accessing buffers
when mhi goes down copy the buffer content and length locally
which can be used to copy to userspace.

Change-Id: Iada4ab1756a2b3792a45547eec4e47869c8eb94d
Signed-off-by: default avatarManoj Prabhu B <bmanoj@codeaurora.org>
parent 42c46585
Loading
Loading
Loading
Loading
+25 −24
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2014-2020, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2021, The Linux Foundation. All rights reserved.
 */

#include <linux/slab.h>
@@ -330,13 +330,19 @@ int diag_md_copy_to_user(char __user *buf, int *pret, size_t buf_size,
	struct diag_md_info *ch = NULL;
	struct diag_buf_tbl_t *entry = NULL;
	uint8_t drain_again = 0;
	int peripheral = 0;
	int peripheral = 0, tmp_len = 0;
	struct diag_md_session_t *session_info = NULL;
	struct pid *pid_struct = NULL;
	struct task_struct *task_s = NULL;
	unsigned char *tmp_buf = NULL;

	if (!info)
		return -EINVAL;

	tmp_buf = vzalloc(MAX_PERIPHERAL_HDLC_BUF_SZ);
	if (!tmp_buf)
		return -ENOMEM;

	for (i = 0; i < NUM_DIAG_MD_DEV && !err; i++) {
		ch = &diag_md[i];
		if (!ch->md_info_inited)
@@ -348,6 +354,8 @@ int diag_md_copy_to_user(char __user *buf, int *pret, size_t buf_size,
				spin_unlock_irqrestore(&ch->lock, flags);
				continue;
			}
			tmp_len = entry->len;
			memcpy(tmp_buf, entry->buf, entry->len);
			peripheral = diag_md_get_peripheral(entry->ctx);
			if (peripheral < 0) {
				spin_unlock_irqrestore(&ch->lock, flags);
@@ -383,14 +391,6 @@ int diag_md_copy_to_user(char __user *buf, int *pret, size_t buf_size,
					drain_again = 1;
					break;
				}
			} else {
				if ((ret + (2 * sizeof(int)) + entry->len) >=
						buf_size) {
					drain_again = 1;
					break;
				}
			}
			if (i > 0) {
				remote_token = diag_get_remote(i);
				task_s = get_pid_task(pid_struct, PIDTYPE_PID);
				if (task_s) {
@@ -404,23 +404,20 @@ int diag_md_copy_to_user(char __user *buf, int *pret, size_t buf_size,
					ret += sizeof(int);
					put_task_struct(task_s);
				}
			} else {
				if ((ret + (2 * sizeof(int)) + entry->len) >=
						buf_size) {
					drain_again = 1;
					break;
				}
			}

			task_s = get_pid_task(pid_struct, PIDTYPE_PID);
			if (task_s) {
				spin_lock_irqsave(&ch->lock, flags);
				entry = &ch->tbl[j];
				if (entry->len <= 0 || entry->buf == NULL) {
					spin_unlock_irqrestore(&ch->lock,
						flags);
					continue;
				}
				spin_unlock_irqrestore(&ch->lock,
						flags);
				/* Copy the length of data being passed */
				if (entry->len) {
				if (tmp_len) {
					err = copy_to_user(buf + ret,
							(void *)&(entry->len),
							(void *)&(tmp_len),
							sizeof(int));
					if (err) {
						put_task_struct(task_s);
@@ -430,10 +427,10 @@ int diag_md_copy_to_user(char __user *buf, int *pret, size_t buf_size,
				}

				/* Copy the actual data being passed */
				if (entry->buf) {
				if (tmp_buf) {
					err = copy_to_user(buf + ret,
							(void *)entry->buf,
							entry->len);
							(void *)tmp_buf,
							tmp_len);
					if (err) {
						put_task_struct(task_s);
						goto drop_data;
@@ -467,6 +464,8 @@ int diag_md_copy_to_user(char __user *buf, int *pret, size_t buf_size,
			spin_unlock_irqrestore(&ch->lock, flags);

			put_pid(pid_struct);
			memset(tmp_buf, 0, MAX_PERIPHERAL_HDLC_BUF_SZ);
			tmp_len = 0;
		}
	}

@@ -482,6 +481,8 @@ int diag_md_copy_to_user(char __user *buf, int *pret, size_t buf_size,
		}
		put_pid(pid_struct);
	}
	vfree(tmp_buf);
	tmp_buf = NULL;
	diag_ws_on_copy_complete(DIAG_WS_MUX);
	if (drain_again)
		chk_logging_wakeup();