summaryrefslogtreecommitdiff
path: root/drivers/char/diag
diff options
context:
space:
mode:
authorHardik Arya <harya@codeaurora.org>2018-01-17 21:03:52 +0530
committerHardik Arya <harya@codeaurora.org>2018-02-20 15:13:44 +0530
commit63b076dbd015a085dac09306b9fb6546fdb2dec1 (patch)
tree3b67e6baee7eb390235377bbdd3d09c5654739b9 /drivers/char/diag
parent3fe4f284c8977031fd3c3f0729b9a7772b48aeca (diff)
diag: Validate copying length against source buffer length
There a possibility of out-of-bound read because of not validating source buffer length against length that about to be copied. The patch adds proper check for validating length before copying data CRs-Fixed: 2163793 Change-Id: I7c93839d0c4d83024ce23a0ce494d09dd08567a9 Signed-off-by: Hardik Arya <harya@codeaurora.org>
Diffstat (limited to 'drivers/char/diag')
-rw-r--r--drivers/char/diag/diag_dci.c97
1 files changed, 70 insertions, 27 deletions
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 196e87b61705..6b8b00809cd3 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -1162,18 +1162,31 @@ void extract_dci_events(unsigned char *buf, int len, int data_source,
struct list_head *start, *temp;
struct diag_dci_client_tbl *entry = NULL;
- length = *(uint16_t *)(buf + 1); /* total length of event series */
- if (length == 0) {
- pr_err("diag: Incoming dci event length is invalid\n");
+ if (!buf) {
+ pr_err("diag: In %s buffer is NULL\n", __func__);
return;
}
/*
- * Move directly to the start of the event series. 1 byte for
- * event code and 2 bytes for the length field.
+ * 1 byte for event code and 2 bytes for the length field.
* The length field indicates the total length removing the cmd_code
* and the lenght field. The event parsing in that case should happen
* till the end.
*/
+ if (len < 3) {
+ pr_err("diag: In %s invalid len: %d\n", __func__, len);
+ return;
+ }
+ length = *(uint16_t *)(buf + 1); /* total length of event series */
+ if ((length == 0) || (len != (length + 3))) {
+ pr_err("diag: Incoming dci event length: %d is invalid\n",
+ length);
+ return;
+ }
+ /*
+ * Move directly to the start of the event series.
+ * The event parsing should happen from start of event
+ * series till the end.
+ */
temp_len = 3;
while (temp_len < length) {
event_id_packet = *(uint16_t *)(buf + temp_len);
@@ -1190,30 +1203,60 @@ void extract_dci_events(unsigned char *buf, int len, int data_source,
* necessary.
*/
timestamp_len = 8;
- memcpy(timestamp, buf + temp_len + 2, timestamp_len);
+ if ((temp_len + timestamp_len + 2) <= len)
+ memcpy(timestamp, buf + temp_len + 2,
+ timestamp_len);
+ else {
+ pr_err("diag: Invalid length in %s, len: %d, temp_len: %d",
+ __func__, len, temp_len);
+ return;
+ }
}
/* 13th and 14th bit represent the payload length */
if (((event_id_packet & 0x6000) >> 13) == 3) {
payload_len_field = 1;
- payload_len = *(uint8_t *)
+ if ((temp_len + timestamp_len + 3) <= len) {
+ payload_len = *(uint8_t *)
(buf + temp_len + 2 + timestamp_len);
- if (payload_len < (MAX_EVENT_SIZE - 13)) {
- /* copy the payload length and the payload */
+ } else {
+ pr_err("diag: Invalid length in %s, len: %d, temp_len: %d",
+ __func__, len, temp_len);
+ return;
+ }
+ if ((payload_len < (MAX_EVENT_SIZE - 13)) &&
+ ((temp_len + timestamp_len + payload_len + 3) <= len)) {
+ /*
+ * Copy the payload length and the payload
+ * after skipping temp_len bytes for already
+ * parsed packet, timestamp_len for timestamp
+ * buffer, 2 bytes for event_id_packet.
+ */
memcpy(event_data + 12, buf + temp_len + 2 +
timestamp_len, 1);
memcpy(event_data + 13, buf + temp_len + 2 +
timestamp_len + 1, payload_len);
} else {
- pr_err("diag: event > %d, payload_len = %d\n",
- (MAX_EVENT_SIZE - 13), payload_len);
+ pr_err("diag: event > %d, payload_len = %d, temp_len = %d\n",
+ (MAX_EVENT_SIZE - 13), payload_len, temp_len);
return;
}
} else {
payload_len_field = 0;
payload_len = (event_id_packet & 0x6000) >> 13;
- /* copy the payload */
- memcpy(event_data + 12, buf + temp_len + 2 +
+ /*
+ * Copy the payload after skipping temp_len bytes
+ * for already parsed packet, timestamp_len for
+ * timestamp buffer, 2 bytes for event_id_packet.
+ */
+ if ((payload_len < (MAX_EVENT_SIZE - 12)) &&
+ ((temp_len + timestamp_len + payload_len + 2) <= len))
+ memcpy(event_data + 12, buf + temp_len + 2 +
timestamp_len, payload_len);
+ else {
+ pr_err("diag: event > %d, payload_len = %d, temp_len = %d\n",
+ (MAX_EVENT_SIZE - 12), payload_len, temp_len);
+ return;
+ }
}
/* Before copying the data to userspace, check if we are still
@@ -1337,19 +1380,19 @@ void extract_dci_log(unsigned char *buf, int len, int data_source, int token,
pr_err("diag: In %s buffer is NULL\n", __func__);
return;
}
-
- /* The first six bytes for the incoming log packet contains
- * Command code (2), the length of the packet (2) and the length
- * of the log (2)
+ /*
+ * The first eight bytes for the incoming log packet contains
+ * Command code (2), the length of the packet (2), the length
+ * of the log (2) and log code (2)
*/
- log_code = *(uint16_t *)(buf + 6);
- read_bytes += sizeof(uint16_t) + 6;
- if (read_bytes > len) {
- pr_err("diag: Invalid length in %s, len: %d, read: %d",
- __func__, len, read_bytes);
+ if (len < 8) {
+ pr_err("diag: In %s invalid len: %d\n", __func__, len);
return;
}
+ log_code = *(uint16_t *)(buf + 6);
+ read_bytes += sizeof(uint16_t) + 6;
+
/* parse through log mask table of each client and check mask */
mutex_lock(&driver->dci_mutex);
list_for_each_safe(start, temp, &driver->dci_client_list) {
@@ -1376,6 +1419,10 @@ void extract_dci_ext_pkt(unsigned char *buf, int len, int data_source,
pr_err("diag: In %s buffer is NULL\n", __func__);
return;
}
+ if (len < (EXT_HDR_LEN + sizeof(uint8_t))) {
+ pr_err("diag: In %s invalid len: %d\n", __func__, len);
+ return;
+ }
version = *(uint8_t *)buf + 1;
if (version < EXT_HDR_VERSION) {
@@ -1387,10 +1434,6 @@ void extract_dci_ext_pkt(unsigned char *buf, int len, int data_source,
pkt = buf + EXT_HDR_LEN;
pkt_cmd_code = *(uint8_t *)pkt;
len -= EXT_HDR_LEN;
- if (len < 0) {
- pr_err("diag: %s, Invalid length len: %d\n", __func__, len);
- return;
- }
switch (pkt_cmd_code) {
case LOG_CMD_CODE: