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

Commit 53bf345c 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 and wrong length update for
user PD buffer avoiding further buffer corruption.

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

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

	spin_lock_irqsave(&ch->lock, flags);
	for (i = 0; i < ch->num_tbl_entries && !found; i++) {
		if (ch->tbl[i].buf != buf)
			continue;
		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",
				   buf, ctx, ch->tbl[i].len,
				   i, id, driver->logging_mode);
		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, ch->tbl[i].len, GET_BUF_PERIPHERAL(ctx),
				   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);

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

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

struct data_header {
	uint8_t control_char;
@@ -187,8 +188,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)
{
	int i, ctx = 0;
	uint32_t max_size = 0;
	unsigned char *temp_buf = NULL;
	struct diag_md_info *ch = NULL;

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

		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 +
						APF_DIAG_PADDING,
					    GFP_KERNEL);
			if (!temp_buf)
				return -ENOMEM;
			DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
			"Reallocated data buffer: %pK with size: %d\n",
			temp_buf, max_size);
			buf->data = temp_buf;
			buf->len = max_size;
		}
@@ -377,6 +400,10 @@ static void diagfwd_data_process_done(struct diagfwd_info *fwd_info,
	mutex_unlock(&fwd_info->data_mutex);
	mutex_unlock(&driver->hdlc_disable_mutex);
	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,
				   GET_BUF_NUM(buf->ctxt));
	}
@@ -483,17 +510,27 @@ static void diagfwd_data_read_untag_done(struct diagfwd_info *fwd_info,
			temp_buf_main += (packet_len + 4);
			processed += packet_len;
		}
		for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
			if (fwd_info->type == TYPE_DATA && len_upd[i]) {

		if (flag_buf_1) {
			fwd_info->cpd_len_1 = len_cpd;
			for (i = 0; i <= (fwd_info->num_pd - 2); i++)
				if (fwd_info->type == TYPE_DATA)
					fwd_info->upd_len[i][0] = len_upd[i];
		} else if (flag_buf_2) {
			fwd_info->cpd_len_2 = len_cpd;
			for (i = 0; i <= (fwd_info->num_pd - 2); i++)
				if (fwd_info->type == TYPE_DATA)
					fwd_info->upd_len[i][1] = len_upd[i];
		}

		for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
			if (fwd_info->type == TYPE_DATA && len_upd[i]) {
				if (flag_buf_1)
					temp_fwdinfo_upd =
						fwd_info->buf_upd[i][0];
				} else {
					fwd_info->upd_len[i][1] = len_upd[i];
				else
					temp_fwdinfo_upd =
						fwd_info->buf_upd[i][1];
				}
				temp_fwdinfo_upd->ctxt &= 0x00FFFFFF;
				temp_fwdinfo_upd->ctxt |=
					(SET_PD_CTXT(ctxt_upd[i]));
@@ -508,26 +545,9 @@ static void diagfwd_data_read_untag_done(struct diagfwd_info *fwd_info,
			}
		}

		if (flag_buf_1) {
			fwd_info->cpd_len_1 = len_cpd;
			for (i = 0; i <= (fwd_info->num_pd - 2); i++)
				if (fwd_info->type == TYPE_DATA)
					fwd_info->upd_len[i][0] = len_upd[i];
		} else if (flag_buf_2) {
			fwd_info->cpd_len_2 = len_cpd;
			for (i = 0; i <= (fwd_info->num_pd - 2); i++)
				if (fwd_info->type == TYPE_DATA)
					fwd_info->upd_len[i][1] = len_upd[i];
		}

		if (len_cpd) {
			if (flag_buf_1)
				fwd_info->cpd_len_1 = len_cpd;
			else
				fwd_info->cpd_len_2 = len_cpd;
			temp_fwdinfo_cpd->ctxt &= 0x00FFFFFF;
			temp_fwdinfo_cpd->ctxt |=
				(SET_PD_CTXT(ctxt_cpd));
			temp_fwdinfo_cpd->ctxt |= (SET_PD_CTXT(ctxt_cpd));
			diagfwd_data_process_done(fwd_info,
				temp_fwdinfo_cpd, len_cpd);
		} else {
@@ -543,6 +563,10 @@ static void diagfwd_data_read_untag_done(struct diagfwd_info *fwd_info,
end:
	diag_ws_release();
	if (temp_fwdinfo_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_fwdinfo_cpd->ctxt));
		diagfwd_write_done(fwd_info->peripheral, fwd_info->type,
				   GET_BUF_NUM(temp_fwdinfo_cpd->ctxt));
	}
@@ -663,6 +687,10 @@ static void diagfwd_data_read_done(struct diagfwd_info *fwd_info,
	mutex_unlock(&fwd_info->data_mutex);
	mutex_unlock(&driver->hdlc_disable_mutex);
	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,
				   GET_BUF_NUM(temp_buf->ctxt));
	}
@@ -742,6 +770,16 @@ static void diagfwd_reset_buffers(struct diagfwd_info *fwd_info,
		else if (fwd_info->buf_2 && fwd_info->buf_2->data_raw == buf)
			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)
@@ -1146,10 +1184,18 @@ static void __diag_fwd_open(struct diagfwd_info *fwd_info)

	if ((driver->logging_mode != DIAG_USB_MODE) ||
		driver->usb_connected) {
		if (fwd_info->buf_1)
		if (fwd_info->buf_1) {
			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);
			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)
@@ -1275,10 +1321,18 @@ int diagfwd_channel_close(struct diagfwd_info *fwd_info)
	if (fwd_info && fwd_info->c_ops && fwd_info->c_ops->close)
		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);
	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);
		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++) {
		if (fwd_info->buf_ptr[i])
@@ -1304,6 +1358,9 @@ int diagfwd_channel_read_done(struct diagfwd_info *fwd_info,
	 * in_busy flags. No need to queue read in this case.
	 */
	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);
		diag_ws_release();
		return 0;
@@ -1316,7 +1373,7 @@ int diagfwd_channel_read_done(struct diagfwd_info *fwd_info,
	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)
{
	int i = 0, upd_valid_len = 0;
	struct diagfwd_info *fwd_info = NULL;
@@ -1328,7 +1385,7 @@ void diagfwd_write_done(uint8_t peripheral, uint8_t type, int ctxt)
	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 */
		fwd_info->cpd_len_1 = 0;
		for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
@@ -1337,9 +1394,13 @@ void diagfwd_write_done(uint8_t peripheral, uint8_t type, int ctxt)
				break;
			}
		}
		if (!upd_valid_len)
		if (!upd_valid_len) {
			atomic_set(&fwd_info->buf_1->in_busy, 0);
	} else if (ctxt == 2 && fwd_info->buf_2) {
			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 */
		fwd_info->cpd_len_2 = 0;
		for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
@@ -1348,30 +1409,42 @@ void diagfwd_write_done(uint8_t peripheral, uint8_t type, int ctxt)
				break;
			}
		}
		if (!upd_valid_len)
		if (!upd_valid_len) {
			atomic_set(&fwd_info->buf_2->in_busy, 0);
	} else if (ctxt >= 3 && (ctxt % 2)) {
			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 && (buf_num % 2)) {
		for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
			if (fwd_info->buf_upd[i][0]) {
				/* Buffer 1 for ith user PD is freed */
			atomic_set(&fwd_info->buf_upd[i][0]->in_busy, 0);
			fwd_info->upd_len[i][0] = 0;
			}
		if (!fwd_info->cpd_len_1)
			if (!fwd_info->cpd_len_1) {
				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);
			}
		}
	} else if (ctxt >= 4 && !(ctxt % 2)) {
	} else if (buf_num >= 4 && !(buf_num % 2)) {
		for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
			if (fwd_info->buf_upd[i][1]) {
				/* Buffer 2 for ith user PD is freed */
			atomic_set(&fwd_info->buf_upd[i][0]->in_busy, 0);
			atomic_set(&fwd_info->buf_upd[i][1]->in_busy, 0);
			fwd_info->upd_len[i][1] = 0;
			}
		if (!fwd_info->cpd_len_2)
			if (!fwd_info->cpd_len_2) {
				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);
			}
		}
	} 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);
}
+1 −1
Original line number Diff line number Diff line
@@ -113,7 +113,7 @@ int diagfwd_cntl_register(uint8_t transport, uint8_t peripheral, 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);
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);

/*