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

Commit 7f2bebe8 authored by Hardik Arya's avatar Hardik Arya
Browse files

diag: Flush mdlog table entries while reallocation of data buffer



Currently there is a possibility of accessing freed up buffer
address after reallocation due to availability of old address
in mdlog entry table. The patch flushes table entries before
reallocating data buffer. Additional case of entries cleanup
during erroneous buffer free avoiding further buffer corruption.

CRs-Fixed: 2063721
Change-Id: I8424598ad34b809414518a1f7f5b1737ebe51e53
Signed-off-by: default avatarHardik Arya <harya@codeaurora.org>
parent 22b400ed
Loading
Loading
Loading
Loading
+9 −4
Original line number Original line Diff line number Diff line
@@ -155,15 +155,20 @@ int diag_md_write(int id, unsigned char *buf, int len, int ctx)
		return -EIO;
		return -EIO;


	ch = &diag_md[id];
	ch = &diag_md[id];
	if (!ch)
		return -EINVAL;


	spin_lock_irqsave(&ch->lock, flags);
	spin_lock_irqsave(&ch->lock, flags);
	for (i = 0; i < ch->num_tbl_entries && !found; i++) {
	for (i = 0; i < ch->num_tbl_entries && !found; i++) {
		if (ch->tbl[i].buf != buf)
		if (ch->tbl[i].buf != buf)
			continue;
			continue;
		found = 1;
		found = 1;
		pr_err_ratelimited("diag: trying to write the same buffer buf: %pK, ctxt: %d len: %d at i: %d back to the table, proc: %d, mode: %d\n",
		pr_err_ratelimited("diag: trying to write the same buffer buf: %pK, len: %d, back to the table for p: %d, t: %d, buf_num: %d, proc: %d, i: %d\n",
				   buf, ctx, ch->tbl[i].len,
				   buf, ch->tbl[i].len, GET_BUF_PERIPHERAL(ctx),
				   i, id, driver->logging_mode);
				   GET_BUF_TYPE(ctx), GET_BUF_NUM(ctx), id, i);
		ch->tbl[i].buf = NULL;
		ch->tbl[i].len = 0;
		ch->tbl[i].ctx = 0;
	}
	}
	spin_unlock_irqrestore(&ch->lock, flags);
	spin_unlock_irqrestore(&ch->lock, flags);


@@ -227,7 +232,7 @@ int diag_md_copy_to_user(char __user *buf, int *pret, size_t buf_size,
		ch = &diag_md[i];
		ch = &diag_md[i];
		for (j = 0; j < ch->num_tbl_entries && !err; j++) {
		for (j = 0; j < ch->num_tbl_entries && !err; j++) {
			entry = &ch->tbl[j];
			entry = &ch->tbl[j];
			if (entry->len <= 0)
			if (entry->len <= 0 || entry->buf == NULL)
				continue;
				continue;


			peripheral = diag_md_get_peripheral(entry->ctx);
			peripheral = diag_md_get_peripheral(entry->ctx);
+3 −0
Original line number Original line Diff line number Diff line
@@ -1572,6 +1572,9 @@ static int diagfwd_mux_write_done(unsigned char *buf, int len, int buf_ctxt,
	switch (type) {
	switch (type) {
	case TYPE_DATA:
	case TYPE_DATA:
		if (peripheral >= 0 && peripheral < NUM_PERIPHERALS) {
		if (peripheral >= 0 && peripheral < NUM_PERIPHERALS) {
			DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
			"Marking buffer as free after write done p: %d, t: %d, buf_num: %d\n",
				peripheral, type, num);
			diagfwd_write_done(peripheral, type, num);
			diagfwd_write_done(peripheral, type, num);
			diag_ws_on_copy(DIAG_WS_MUX);
			diag_ws_on_copy(DIAG_WS_MUX);
		} else if (peripheral == APPS_DATA) {
		} else if (peripheral == APPS_DATA) {
+108 −16
Original line number Original line Diff line number Diff line
@@ -31,6 +31,7 @@
#include "diag_mux.h"
#include "diag_mux.h"
#include "diag_ipc_logging.h"
#include "diag_ipc_logging.h"
#include "diagfwd_glink.h"
#include "diagfwd_glink.h"
#include "diag_memorydevice.h"


struct data_header {
struct data_header {
	uint8_t control_char;
	uint8_t control_char;
@@ -188,8 +189,10 @@ static int diag_add_hdlc_encoding(unsigned char *dest_buf, int *dest_len,


static int check_bufsize_for_encoding(struct diagfwd_buf_t *buf, uint32_t len)
static int check_bufsize_for_encoding(struct diagfwd_buf_t *buf, uint32_t len)
{
{
	int i, ctx = 0;
	uint32_t max_size = 0;
	uint32_t max_size = 0;
	unsigned char *temp_buf = NULL;
	unsigned char *temp_buf = NULL;
	struct diag_md_info *ch = NULL;


	if (!buf || len == 0)
	if (!buf || len == 0)
		return -EINVAL;
		return -EINVAL;
@@ -203,11 +206,31 @@ static int check_bufsize_for_encoding(struct diagfwd_buf_t *buf, uint32_t len)
		}
		}


		if (buf->len < max_size) {
		if (buf->len < max_size) {
			if (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE) {
				ch = &diag_md[DIAG_LOCAL_PROC];
				for (i = 0; ch != NULL &&
						i < ch->num_tbl_entries; i++) {
					if (ch->tbl[i].buf == buf->data) {
						ctx = ch->tbl[i].ctx;
						ch->tbl[i].buf = NULL;
						ch->tbl[i].len = 0;
						ch->tbl[i].ctx = 0;
						DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
						"Flushed mdlog table entries before reallocating data buffer, p:%d, t:%d\n",
						GET_BUF_PERIPHERAL(ctx),
						GET_BUF_TYPE(ctx));
						break;
					}
				}
			}
			temp_buf = krealloc(buf->data, max_size +
			temp_buf = krealloc(buf->data, max_size +
						APF_DIAG_PADDING,
						APF_DIAG_PADDING,
					    GFP_KERNEL);
					    GFP_KERNEL);
			if (!temp_buf)
			if (!temp_buf)
				return -ENOMEM;
				return -ENOMEM;
			DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
			"Reallocated data buffer: %pK with size: %d\n",
			temp_buf, max_size);
			buf->data = temp_buf;
			buf->data = temp_buf;
			buf->len = max_size;
			buf->len = max_size;
		}
		}
@@ -360,6 +383,10 @@ end:
	mutex_unlock(&fwd_info->data_mutex);
	mutex_unlock(&fwd_info->data_mutex);
	mutex_unlock(&driver->hdlc_disable_mutex);
	mutex_unlock(&driver->hdlc_disable_mutex);
	if (buf) {
	if (buf) {
		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
		"Marking buffer as free p: %d, t: %d, buf_num: %d\n",
			fwd_info->peripheral, fwd_info->type,
			GET_BUF_NUM(buf->ctxt));
		diagfwd_write_done(fwd_info->peripheral, fwd_info->type,
		diagfwd_write_done(fwd_info->peripheral, fwd_info->type,
				   GET_BUF_NUM(buf->ctxt));
				   GET_BUF_NUM(buf->ctxt));
	}
	}
@@ -572,6 +599,10 @@ static void diagfwd_data_read_untag_done(struct diagfwd_info *fwd_info,
end:
end:
	diag_ws_release();
	diag_ws_release();
	if (temp_ptr_cpd) {
	if (temp_ptr_cpd) {
		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
		"Marking buffer as free p: %d, t: %d, buf_num: %d\n",
			fwd_info->peripheral, fwd_info->type,
			GET_BUF_NUM(temp_ptr_cpd->ctxt));
		diagfwd_write_done(fwd_info->peripheral, fwd_info->type,
		diagfwd_write_done(fwd_info->peripheral, fwd_info->type,
				   GET_BUF_NUM(temp_ptr_cpd->ctxt));
				   GET_BUF_NUM(temp_ptr_cpd->ctxt));
	}
	}
@@ -692,6 +723,10 @@ end:
	mutex_unlock(&fwd_info->data_mutex);
	mutex_unlock(&fwd_info->data_mutex);
	mutex_unlock(&driver->hdlc_disable_mutex);
	mutex_unlock(&driver->hdlc_disable_mutex);
	if (temp_buf) {
	if (temp_buf) {
		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
		"Marking buffer as free p: %d, t: %d, buf_num: %d\n",
			fwd_info->peripheral, fwd_info->type,
			GET_BUF_NUM(temp_buf->ctxt));
		diagfwd_write_done(fwd_info->peripheral, fwd_info->type,
		diagfwd_write_done(fwd_info->peripheral, fwd_info->type,
				   GET_BUF_NUM(temp_buf->ctxt));
				   GET_BUF_NUM(temp_buf->ctxt));
	}
	}
@@ -772,6 +807,16 @@ static void diagfwd_reset_buffers(struct diagfwd_info *fwd_info,
		else if (fwd_info->buf_2 && fwd_info->buf_2->data_raw == buf)
		else if (fwd_info->buf_2 && fwd_info->buf_2->data_raw == buf)
			atomic_set(&fwd_info->buf_2->in_busy, 0);
			atomic_set(&fwd_info->buf_2->in_busy, 0);
	}
	}
	if (fwd_info->buf_1 && !atomic_read(&(fwd_info->buf_1->in_busy))) {
		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
		"Buffer 1 for core PD is marked free, p: %d, t: %d\n",
			fwd_info->peripheral, fwd_info->type);
	}
	if (fwd_info->buf_2 && !atomic_read(&(fwd_info->buf_2->in_busy))) {
		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
		"Buffer 2 for core PD is marked free, p: %d, t: %d\n",
			fwd_info->peripheral, fwd_info->type);
	}
}
}


int diagfwd_peripheral_init(void)
int diagfwd_peripheral_init(void)
@@ -1158,10 +1203,18 @@ static void __diag_fwd_open(struct diagfwd_info *fwd_info)


	if ((driver->logging_mode != DIAG_USB_MODE) ||
	if ((driver->logging_mode != DIAG_USB_MODE) ||
		driver->usb_connected) {
		driver->usb_connected) {
		if (fwd_info->buf_1)
		if (fwd_info->buf_1) {
			atomic_set(&fwd_info->buf_1->in_busy, 0);
			atomic_set(&fwd_info->buf_1->in_busy, 0);
		if (fwd_info->buf_2)
			DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
			"Buffer 1 for core PD is marked free, p: %d, t: %d\n",
				fwd_info->peripheral, fwd_info->type);
		}
		if (fwd_info->buf_2) {
			atomic_set(&fwd_info->buf_2->in_busy, 0);
			atomic_set(&fwd_info->buf_2->in_busy, 0);
			DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
			"Buffer 2 for core PD is marked free, p: %d, t: %d\n",
				fwd_info->peripheral, fwd_info->type);
		}
	}
	}


	if (fwd_info->p_ops && fwd_info->p_ops->open)
	if (fwd_info->p_ops && fwd_info->p_ops->open)
@@ -1285,10 +1338,18 @@ int diagfwd_channel_close(struct diagfwd_info *fwd_info)
	if (fwd_info && fwd_info->c_ops && fwd_info->c_ops->close)
	if (fwd_info && fwd_info->c_ops && fwd_info->c_ops->close)
		fwd_info->c_ops->close(fwd_info);
		fwd_info->c_ops->close(fwd_info);


	if (fwd_info->buf_1 && fwd_info->buf_1->data)
	if (fwd_info->buf_1 && fwd_info->buf_1->data) {
		atomic_set(&fwd_info->buf_1->in_busy, 0);
		atomic_set(&fwd_info->buf_1->in_busy, 0);
	if (fwd_info->buf_2 && fwd_info->buf_2->data)
		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
		"Buffer 1 for core PD is marked free, p: %d, t: %d\n",
			fwd_info->peripheral, fwd_info->type);
	}
	if (fwd_info->buf_2 && fwd_info->buf_2->data) {
		atomic_set(&fwd_info->buf_2->in_busy, 0);
		atomic_set(&fwd_info->buf_2->in_busy, 0);
		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
		"Buffer 2 for core PD is marked free, p: %d, t: %d\n",
				fwd_info->peripheral, fwd_info->type);
	}


	for (i = 0; i < NUM_WRITE_BUFFERS; i++) {
	for (i = 0; i < NUM_WRITE_BUFFERS; i++) {
		if (fwd_info->buf_ptr[i])
		if (fwd_info->buf_ptr[i])
@@ -1314,6 +1375,9 @@ int diagfwd_channel_read_done(struct diagfwd_info *fwd_info,
	 * in_busy flags. No need to queue read in this case.
	 * in_busy flags. No need to queue read in this case.
	 */
	 */
	if (len == 0) {
	if (len == 0) {
		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
		"Read Length is 0, resetting the diag buffers p: %d, t: %d\n",
			fwd_info->peripheral, fwd_info->type);
		diagfwd_reset_buffers(fwd_info, buf);
		diagfwd_reset_buffers(fwd_info, buf);
		diag_ws_release();
		diag_ws_release();
		return 0;
		return 0;
@@ -1326,7 +1390,7 @@ int diagfwd_channel_read_done(struct diagfwd_info *fwd_info,
	return 0;
	return 0;
}
}


void diagfwd_write_done(uint8_t peripheral, uint8_t type, int ctxt)
void diagfwd_write_done(uint8_t peripheral, uint8_t type, int buf_num)
{
{
	struct diagfwd_info *fwd_info = NULL;
	struct diagfwd_info *fwd_info = NULL;


@@ -1334,8 +1398,10 @@ void diagfwd_write_done(uint8_t peripheral, uint8_t type, int ctxt)
		return;
		return;


	fwd_info = &peripheral_info[type][peripheral];
	fwd_info = &peripheral_info[type][peripheral];
	if (!fwd_info)
		return;


	if (ctxt == 1 && fwd_info->buf_1) {
	if (buf_num == 1 && fwd_info->buf_1) {
		/* Buffer 1 for core PD is freed */
		/* Buffer 1 for core PD is freed */
		fwd_info->cpd_len_1 = 0;
		fwd_info->cpd_len_1 = 0;


@@ -1349,7 +1415,12 @@ void diagfwd_write_done(uint8_t peripheral, uint8_t type, int ctxt)
		} else {
		} else {
			atomic_set(&fwd_info->buf_1->in_busy, 0);
			atomic_set(&fwd_info->buf_1->in_busy, 0);
		}
		}
	} else if (ctxt == 2 && fwd_info->buf_2) {
		if (!atomic_read(&(fwd_info->buf_1->in_busy))) {
			DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
			"Buffer 1 for core PD is marked free, p: %d, t: %d, buf_num: %d\n",
				fwd_info->peripheral, fwd_info->type, buf_num);
		}
	} else if (buf_num == 2 && fwd_info->buf_2) {
		/* Buffer 2 for core PD is freed */
		/* Buffer 2 for core PD is freed */
		fwd_info->cpd_len_2 = 0;
		fwd_info->cpd_len_2 = 0;


@@ -1363,8 +1434,12 @@ void diagfwd_write_done(uint8_t peripheral, uint8_t type, int ctxt)
		} else {
		} else {
			atomic_set(&fwd_info->buf_2->in_busy, 0);
			atomic_set(&fwd_info->buf_2->in_busy, 0);
		}
		}

		if (!atomic_read(&(fwd_info->buf_2->in_busy))) {
	} else if (ctxt == 3 && fwd_info->buf_upd_1_a) {
			DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
			"Buffer 2 for core PD is marked free, p: %d, t: %d, buf_num: %d\n",
				fwd_info->peripheral, fwd_info->type, buf_num);
		}
	} else if (buf_num == 3 && fwd_info->buf_upd_1_a && fwd_info->buf_1) {
		/* Buffer 1 for user pd 1  is freed */
		/* Buffer 1 for user pd 1  is freed */
		atomic_set(&fwd_info->buf_upd_1_a->in_busy, 0);
		atomic_set(&fwd_info->buf_upd_1_a->in_busy, 0);


@@ -1382,9 +1457,14 @@ void diagfwd_write_done(uint8_t peripheral, uint8_t type, int ctxt)
			if (!fwd_info->cpd_len_1)
			if (!fwd_info->cpd_len_1)
				atomic_set(&fwd_info->buf_1->in_busy, 0);
				atomic_set(&fwd_info->buf_1->in_busy, 0);
		}
		}
		if (!atomic_read(&(fwd_info->buf_1->in_busy))) {
			DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
			"Buffer 1 for core PD is marked free, p: %d, t: %d, buf_num: %d\n",
				fwd_info->peripheral, fwd_info->type, buf_num);
		}
		fwd_info->upd_len_1_a = 0;
		fwd_info->upd_len_1_a = 0;


	} else if (ctxt == 4 && fwd_info->buf_upd_1_b) {
	} else if (buf_num == 4 && fwd_info->buf_upd_1_b && fwd_info->buf_2) {
		/* Buffer 2 for user pd 1  is freed */
		/* Buffer 2 for user pd 1  is freed */
		atomic_set(&fwd_info->buf_upd_1_b->in_busy, 0);
		atomic_set(&fwd_info->buf_upd_1_b->in_busy, 0);
		if (peripheral == PERIPHERAL_LPASS) {
		if (peripheral == PERIPHERAL_LPASS) {
@@ -1401,34 +1481,46 @@ void diagfwd_write_done(uint8_t peripheral, uint8_t type, int ctxt)
			if (!fwd_info->cpd_len_2)
			if (!fwd_info->cpd_len_2)
				atomic_set(&fwd_info->buf_2->in_busy, 0);
				atomic_set(&fwd_info->buf_2->in_busy, 0);
		}
		}
		if (!atomic_read(&(fwd_info->buf_2->in_busy))) {
			DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
			"Buffer 2 for core PD is marked free, p: %d, t: %d, buf_num: %d\n",
				fwd_info->peripheral, fwd_info->type, buf_num);
		}
		fwd_info->upd_len_1_b = 0;
		fwd_info->upd_len_1_b = 0;


	} else if (ctxt == 5 && fwd_info->buf_upd_2_a) {
	} else if (buf_num == 5 && fwd_info->buf_upd_2_a && fwd_info->buf_1) {
		/* Buffer 1 for user pd 2  is freed */
		/* Buffer 1 for user pd 2  is freed */
		atomic_set(&fwd_info->buf_upd_2_a->in_busy, 0);
		atomic_set(&fwd_info->buf_upd_2_a->in_busy, 0);
		/* if not data in cpd and other user pd
		/* if not data in cpd and other user pd
		 * free the core pd buffer for LPASS
		 * free the core pd buffer for LPASS
		 */
		 */
		if (!fwd_info->cpd_len_1 &&
		if (!fwd_info->cpd_len_1 &&
			!fwd_info->upd_len_1_a)
			!fwd_info->upd_len_1_a) {
			atomic_set(&fwd_info->buf_1->in_busy, 0);
			atomic_set(&fwd_info->buf_1->in_busy, 0);
			DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
			"Buffer 1 for core PD is marked free, p: %d, t: %d, buf_num: %d\n",
				fwd_info->peripheral, fwd_info->type, buf_num);
		}


		fwd_info->upd_len_2_a = 0;
		fwd_info->upd_len_2_a = 0;


	} else if (ctxt == 6 && fwd_info->buf_upd_2_b) {
	} else if (buf_num == 6 && fwd_info->buf_upd_2_b && fwd_info->buf_2) {
		/* Buffer 2 for user pd 2  is freed */
		/* Buffer 2 for user pd 2  is freed */
		atomic_set(&fwd_info->buf_upd_2_b->in_busy, 0);
		atomic_set(&fwd_info->buf_upd_2_b->in_busy, 0);
		/* if not data in cpd and other user pd
		/* if not data in cpd and other user pd
		 * free the core pd buffer for LPASS
		 * free the core pd buffer for LPASS
		 */
		 */
		if (!fwd_info->cpd_len_2 &&
		if (!fwd_info->cpd_len_2 &&
			!fwd_info->upd_len_1_b)
			!fwd_info->upd_len_1_b) {
			atomic_set(&fwd_info->buf_2->in_busy, 0);
			atomic_set(&fwd_info->buf_2->in_busy, 0);

			DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
			"Buffer 2 for core PD is marked free, p: %d, t: %d, buf_num: %d\n",
				fwd_info->peripheral, fwd_info->type, buf_num);
		}
		fwd_info->upd_len_2_b = 0;
		fwd_info->upd_len_2_b = 0;


	} else
	} else
		pr_err("diag: In %s, invalid ctxt %d\n", __func__, ctxt);
		pr_err("diag: In %s, invalid buf_num: %d\n", __func__, buf_num);


	diagfwd_queue_read(fwd_info);
	diagfwd_queue_read(fwd_info);
}
}
+1 −1
Original line number Original line Diff line number Diff line
@@ -117,7 +117,7 @@ int diagfwd_cntl_register(uint8_t transport, uint8_t peripheral, void *ctxt,
void diagfwd_deregister(uint8_t peripheral, uint8_t type, void *ctxt);
void diagfwd_deregister(uint8_t peripheral, uint8_t type, void *ctxt);


int diagfwd_write(uint8_t peripheral, uint8_t type, void *buf, int len);
int diagfwd_write(uint8_t peripheral, uint8_t type, void *buf, int len);
void diagfwd_write_done(uint8_t peripheral, uint8_t type, int ctxt);
void diagfwd_write_done(uint8_t peripheral, uint8_t type, int buf_num);
void diagfwd_buffers_init(struct diagfwd_info *fwd_info);
void diagfwd_buffers_init(struct diagfwd_info *fwd_info);


/*
/*