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

Commit 32300174 authored by Manoj Prabhu B's avatar Manoj Prabhu B
Browse files

diag: Prevent resource leakage while copying to userspace



Possibility of resource leakage while checking for validity of
pid and its task structures is prevented by proper update of pid
reference count.

Change-Id: Ifb38f91a5c3e45248bb08c5341c8a3095585c16f
Signed-off-by: default avatarManoj Prabhu B <bmanoj@codeaurora.org>
parent a1c55d77
Loading
Loading
Loading
Loading
+37 −15
Original line number Diff line number Diff line
/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2020, 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
@@ -16,6 +16,7 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/sched.h>
#include <linux/sched/task.h>
#include <linux/ratelimit.h>
#include <linux/workqueue.h>
#include <linux/diagchar.h>
@@ -296,7 +297,10 @@ int diag_md_copy_to_user(char __user *buf, int *pret, size_t buf_size,
	int peripheral = 0;
	struct diag_md_session_t *session_info = NULL;
	struct pid *pid_struct = NULL;
	struct task_struct *task_s = NULL;

	if (!info)
		return -EINVAL;
	for (i = 0; i < NUM_DIAG_MD_DEV && !err; i++) {
		ch = &diag_md[i];
		if (!ch->md_info_inited)
@@ -314,11 +318,11 @@ int diag_md_copy_to_user(char __user *buf, int *pret, size_t buf_size,
			if (!session_info)
				goto drop_data;

			if (session_info && info &&
			if (session_info &&
				(session_info->pid != info->pid))
				continue;
			if ((info && (info->peripheral_mask[i] &
			    MD_PERIPHERAL_MASK(peripheral)) == 0))
			if ((info->peripheral_mask[i] &
			    MD_PERIPHERAL_MASK(peripheral)) == 0)
				goto drop_data;
			pid_struct = find_get_pid(session_info->pid);
			if (!pid_struct) {
@@ -347,35 +351,45 @@ int diag_md_copy_to_user(char __user *buf, int *pret, size_t buf_size,
			}
			if (i > 0) {
				remote_token = diag_get_remote(i);
				if (get_pid_task(pid_struct, PIDTYPE_PID)) {
				task_s = get_pid_task(pid_struct, PIDTYPE_PID);
				if (task_s) {
					err = copy_to_user(buf + ret,
							&remote_token,
							sizeof(int));
					if (err)
					if (err) {
						put_task_struct(task_s);
						goto drop_data;
					}
					ret += sizeof(int);
					put_task_struct(task_s);
				}
			}

			task_s = get_pid_task(pid_struct, PIDTYPE_PID);
			if (task_s) {

				/* Copy the length of data being passed */
			if (get_pid_task(pid_struct, PIDTYPE_PID)) {
				err = copy_to_user(buf + ret,
						(void *)&(entry->len),
						sizeof(int));
				if (err)
				if (err) {
					put_task_struct(task_s);
					goto drop_data;
				ret += sizeof(int);
				}
				ret += sizeof(int);

				/* Copy the actual data being passed */
			if (get_pid_task(pid_struct, PIDTYPE_PID)) {
				err = copy_to_user(buf + ret,
						(void *)entry->buf,
						entry->len);
				if (err)
				if (err) {
					put_task_struct(task_s);
					goto drop_data;
				}
				ret += entry->len;
				put_task_struct(task_s);
			}

			/*
			 * The data is now copied to the user space client,
			 * Notify that the write is complete and delete its
@@ -393,14 +407,22 @@ int diag_md_copy_to_user(char __user *buf, int *pret, size_t buf_size,
			entry->len = 0;
			entry->ctx = 0;
			spin_unlock_irqrestore(&ch->lock, flags);

			put_pid(pid_struct);
		}
	}

	*pret = ret;
	if (pid_struct && get_pid_task(pid_struct, PIDTYPE_PID)) {
	pid_struct = find_get_pid(info->pid);
	if (pid_struct) {
		task_s = get_pid_task(pid_struct, PIDTYPE_PID);
		if (task_s) {
			err = copy_to_user(buf + sizeof(int),
				(void *)&num_data,
				sizeof(int));
			put_task_struct(task_s);
		}
		put_pid(pid_struct);
	}
	diag_ws_on_copy_complete(DIAG_WS_MUX);
	if (drain_again)