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

Commit fa4fdbe1 authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "diag: Add protection while freeing diag mempool buffer"

parents fe9eec80 253f0c6e
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved.
 */

#include <linux/slab.h>
@@ -339,8 +339,8 @@ static void diag_usb_write_done(struct diag_usb_info *ch,
		DIAG_LOG(DIAG_DEBUG_MUX, "partial write_done ref %d\n",
			 atomic_read(&entry->ref_count));
		diag_ws_on_copy_complete(DIAG_WS_MUX);
		spin_unlock_irqrestore(&ch->write_lock, flags);
		diagmem_free(driver, req, ch->mempool);
		spin_unlock_irqrestore(&ch->write_lock, flags);
		return;
	}
	DIAG_LOG(DIAG_DEBUG_MUX, "full write_done, ctxt: %d\n",
@@ -357,8 +357,8 @@ static void diag_usb_write_done(struct diag_usb_info *ch,
	buf = NULL;
	len = 0;
	ctxt = 0;
	spin_unlock_irqrestore(&ch->write_lock, flags);
	diagmem_free(driver, req, ch->mempool);
	spin_unlock_irqrestore(&ch->write_lock, flags);
}

static void diag_usb_notifier(void *priv, unsigned int event,
+1 −0
Original line number Diff line number Diff line
@@ -604,6 +604,7 @@ struct diagchar_dev {
	unsigned int poolsize_hdlc;
	unsigned int poolsize_dci;
	unsigned int poolsize_user;
	spinlock_t diagmem_lock;
	/* Buffers for masks */
	struct mutex diag_cntl_mutex;
	/* Members for Sending response */
+12 −4
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2008-2019, The Linux Foundation. All rights reserved.
 */

#include <linux/slab.h>
@@ -195,17 +195,19 @@ static void drain_timer_func(struct timer_list *tlist)
static void diag_drain_apps_data(struct diag_apps_data_t *data)
{
	int err = 0;
	unsigned long flags;

	if (!data || !data->buf)
		return;

	err = diag_mux_write(DIAG_LOCAL_PROC, data->buf, data->len,
			     data->ctxt);
	spin_lock_irqsave(&driver->diagmem_lock, flags);
	if (err)
		diagmem_free(driver, data->buf, POOL_TYPE_HDLC);

	data->buf = NULL;
	data->len = 0;
	spin_unlock_irqrestore(&driver->diagmem_lock, flags);
}

void diag_update_user_client_work_fn(struct work_struct *work)
@@ -276,6 +278,8 @@ static void diag_mempool_init(void)
	diagmem_init(driver, POOL_TYPE_HDLC);
	diagmem_init(driver, POOL_TYPE_USER);
	diagmem_init(driver, POOL_TYPE_DCI);

	spin_lock_init(&driver->diagmem_lock);
}

static void diag_mempool_exit(void)
@@ -2872,6 +2876,7 @@ static int diag_process_apps_data_hdlc(unsigned char *buf, int len,
	struct diag_apps_data_t *data = &hdlc_data;
	struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
	struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
	unsigned long flags;
	/*
	 * The maximum encoded size of the buffer can be atmost twice the length
	 * of the packet. Add three bytes foe footer - 16 bit CRC (2 bytes) +
@@ -2976,10 +2981,11 @@ static int diag_process_apps_data_hdlc(unsigned char *buf, int len,
	return PKT_ALLOC;

fail_free_buf:
	spin_lock_irqsave(&driver->diagmem_lock, flags);
	diagmem_free(driver, data->buf, POOL_TYPE_HDLC);
	data->buf = NULL;
	data->len = 0;

	spin_unlock_irqrestore(&driver->diagmem_lock, flags);
fail_ret:
	return ret;
}
@@ -2991,6 +2997,7 @@ static int diag_process_apps_data_non_hdlc(unsigned char *buf, int len,
	int ret = PKT_DROP;
	struct diag_pkt_frame_t header;
	struct diag_apps_data_t *data = &non_hdlc_data;
	unsigned long flags;
	/*
	 * The maximum packet size, when the data is non hdlc encoded is equal
	 * to the size of the packet frame header and the length. Add 1 for the
@@ -3055,10 +3062,11 @@ static int diag_process_apps_data_non_hdlc(unsigned char *buf, int len,
	return PKT_ALLOC;

fail_free_buf:
	spin_lock_irqsave(&driver->diagmem_lock, flags);
	diagmem_free(driver, data->buf, POOL_TYPE_HDLC);
	data->buf = NULL;
	data->len = 0;

	spin_unlock_irqrestore(&driver->diagmem_lock, flags);
fail_ret:
	return ret;
}
+3 −1
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2008-2019, The Linux Foundation. All rights reserved.
 */
#include <linux/slab.h>
#include <linux/init.h>
@@ -1777,9 +1777,11 @@ static int diagfwd_mux_write_done(unsigned char *buf, int len, int buf_ctxt,
			diagfwd_write_done(peripheral, type, num);
			diag_ws_on_copy(DIAG_WS_MUX);
		} else if (peripheral == APPS_DATA) {
			spin_lock_irqsave(&driver->diagmem_lock, flags);
			diagmem_free(driver, (unsigned char *)buf,
				     POOL_TYPE_HDLC);
			buf = NULL;
			spin_unlock_irqrestore(&driver->diagmem_lock, flags);
		} else {
			pr_err_ratelimited("diag: Invalid peripheral %d in %s, type: %d\n",
					   peripheral, __func__, type);
+2 −2
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2008-2014, 2016-2018 The Linux Foundation. All rights reserved.
/* Copyright (c) 2008-2014, 2016-2019 The Linux Foundation. All rights reserved.
 */

#include <linux/init.h>
@@ -212,7 +212,7 @@ void diagmem_free(struct diagchar_dev *driver, void *buf, int pool_type)
			break;
		}
		spin_lock_irqsave(&mempool->lock, flags);
		if (mempool->count > 0) {
		if (mempool->count > 0 && buf) {
			mempool_free(buf, mempool->pool);
			atomic_add(-1, (atomic_t *)&mempool->count);
		} else {