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

Commit ed2dc43e authored by Hardik Arya's avatar Hardik Arya Committed by Gerrit - the friendly Code Review server
Browse files

diag: Do not write buffer to usb when already flushed



Currently while draining the apps data, diag apps buffer is
queued to usb again which was already queued while processing
diag apps data. This race condition is resulting as use-after-free
since apps buffer will be freed on write done completion. The patch
checks flushed status of buffer before submitting it to usb.

Change-Id: I19d99958a14ae9a8483457a5a90c78d527d37fb0
Signed-off-by: default avatarHardik Arya <harya@codeaurora.org>
parent 60638232
Loading
Loading
Loading
Loading
+10 −15
Original line number Diff line number Diff line
@@ -197,6 +197,10 @@ static void diag_drain_apps_data(struct diag_apps_data_t *data)
		return;

	spin_lock_irqsave(&driver->diagmem_lock, flags);
	if (data->flushed) {
		spin_unlock_irqrestore(&driver->diagmem_lock, flags);
		return;
	}
	data->flushed = 1;
	spin_unlock_irqrestore(&driver->diagmem_lock, flags);
	err = diag_mux_write(DIAG_LOCAL_PROC, data->buf, data->len,
@@ -3091,8 +3095,8 @@ static int diag_process_apps_data_hdlc(unsigned char *buf, int len,

	wait_event_interruptible(driver->hdlc_wait_q,
			(data->flushed == 0));
	if (!data->buf) {
	spin_lock_irqsave(&driver->diagmem_lock, flags);
	if (!data->buf) {
		data->buf = diagmem_alloc(driver, DIAG_MAX_HDLC_BUF_SIZE +
					APF_DIAG_PADDING,
					  POOL_TYPE_HDLC);
@@ -3103,11 +3107,9 @@ static int diag_process_apps_data_hdlc(unsigned char *buf, int len,
		}
		data->allocated = 1;
		data->flushed = 0;
		spin_unlock_irqrestore(&driver->diagmem_lock, flags);
	}

	if ((DIAG_MAX_HDLC_BUF_SIZE - data->len) <= max_encoded_size) {
		spin_lock_irqsave(&driver->diagmem_lock, flags);
		data->flushed = 1;
		spin_unlock_irqrestore(&driver->diagmem_lock, flags);
		err = diag_mux_write(DIAG_LOCAL_PROC, data->buf, data->len,
@@ -3129,13 +3131,11 @@ static int diag_process_apps_data_hdlc(unsigned char *buf, int len,
		}
		data->allocated = 1;
		data->flushed = 0;
		spin_unlock_irqrestore(&driver->diagmem_lock, flags);
	}

	enc.dest = data->buf + data->len;
	enc.dest_last = (void *)(data->buf + data->len + max_encoded_size);
	diag_hdlc_encode(&send, &enc);

	/*
	 * This is to check if after HDLC encoding, we are still within
	 * the limits of aggregation buffer. If not, we write out the
@@ -3144,7 +3144,6 @@ static int diag_process_apps_data_hdlc(unsigned char *buf, int len,
	 */
	if ((uintptr_t)enc.dest >= (uintptr_t)(data->buf +
					       DIAG_MAX_HDLC_BUF_SIZE)) {
		spin_lock_irqsave(&driver->diagmem_lock, flags);
		data->flushed = 1;
		spin_unlock_irqrestore(&driver->diagmem_lock, flags);
		err = diag_mux_write(DIAG_LOCAL_PROC, data->buf, data->len,
@@ -3166,7 +3165,6 @@ static int diag_process_apps_data_hdlc(unsigned char *buf, int len,
		}
		data->allocated = 1;
		data->flushed = 0;
		spin_unlock_irqrestore(&driver->diagmem_lock, flags);

		enc.dest = data->buf + data->len;
		enc.dest_last = (void *)(data->buf + data->len +
@@ -3180,7 +3178,6 @@ static int diag_process_apps_data_hdlc(unsigned char *buf, int len,
			DIAG_MAX_HDLC_BUF_SIZE;

	if (pkt_type == DATA_TYPE_RESPONSE) {
		spin_lock_irqsave(&driver->diagmem_lock, flags);
		data->flushed = 1;
		spin_unlock_irqrestore(&driver->diagmem_lock, flags);
		err = diag_mux_write(DIAG_LOCAL_PROC, data->buf, data->len,
@@ -3189,8 +3186,9 @@ static int diag_process_apps_data_hdlc(unsigned char *buf, int len,
			ret = -EIO;
			goto fail_free_buf;
		}
		return PKT_ALLOC;
	}

	spin_unlock_irqrestore(&driver->diagmem_lock, flags);
	return PKT_ALLOC;

fail_free_buf:
@@ -3228,8 +3226,8 @@ static int diag_process_apps_data_non_hdlc(unsigned char *buf, int len,
	}
	wait_event_interruptible(driver->hdlc_wait_q,
			(data->flushed == 0));
	if (!data->buf) {
	spin_lock_irqsave(&driver->diagmem_lock, flags);
	if (!data->buf) {
		data->buf = diagmem_alloc(driver, DIAG_MAX_HDLC_BUF_SIZE +
					APF_DIAG_PADDING,
					  POOL_TYPE_HDLC);
@@ -3240,10 +3238,8 @@ static int diag_process_apps_data_non_hdlc(unsigned char *buf, int len,
		}
		data->allocated = 1;
		data->flushed = 0;
		spin_unlock_irqrestore(&driver->diagmem_lock, flags);
	}
	if ((DIAG_MAX_HDLC_BUF_SIZE - data->len) <= max_pkt_size) {
		spin_lock_irqsave(&driver->diagmem_lock, flags);
		data->flushed = 1;
		spin_unlock_irqrestore(&driver->diagmem_lock, flags);
		err = diag_mux_write(DIAG_LOCAL_PROC, data->buf, data->len,
@@ -3266,7 +3262,6 @@ static int diag_process_apps_data_non_hdlc(unsigned char *buf, int len,
		}
		data->allocated = 1;
		data->flushed = 0;
		spin_unlock_irqrestore(&driver->diagmem_lock, flags);
	}

	header.start = CONTROL_CHAR;
@@ -3279,7 +3274,6 @@ static int diag_process_apps_data_non_hdlc(unsigned char *buf, int len,
	*(uint8_t *)(data->buf + data->len) = CONTROL_CHAR;
	data->len += sizeof(uint8_t);
	if (pkt_type == DATA_TYPE_RESPONSE) {
		spin_lock_irqsave(&driver->diagmem_lock, flags);
		data->flushed = 1;
		spin_unlock_irqrestore(&driver->diagmem_lock, flags);
		err = diag_mux_write(DIAG_LOCAL_PROC, data->buf, data->len,
@@ -3288,8 +3282,9 @@ static int diag_process_apps_data_non_hdlc(unsigned char *buf, int len,
			ret = -EIO;
			goto fail_free_buf;
		}
		return PKT_ALLOC;
	}

	spin_unlock_irqrestore(&driver->diagmem_lock, flags);
	return PKT_ALLOC;

fail_free_buf: