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

Commit 8087b754 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 be965466 682b0d2d
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2019, 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
@@ -347,8 +347,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",
@@ -365,8 +365,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
@@ -613,6 +613,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
/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2008-2019, 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
@@ -214,17 +214,19 @@ static void drain_timer_func(unsigned long data)
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)
@@ -295,6 +297,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)
@@ -2891,6 +2895,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) +
@@ -2995,10 +3000,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;
}
@@ -3010,6 +3016,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
@@ -3074,10 +3081,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
/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2008-2019, 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
@@ -1783,9 +1783,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
/* Copyright (c) 2008-2014, 2016-2017 The Linux Foundation. All rights reserved.
/* Copyright (c) 2008-2014, 2016-2017, 2019 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
@@ -221,7 +221,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 {