Merge "diag: Validate copying length against source buffer length"
This commit is contained in:
commit
d633b247ea
1 changed files with 70 additions and 27 deletions
|
@ -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
|
* 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
|
* 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 list_head *start, *temp;
|
||||||
struct diag_dci_client_tbl *entry = NULL;
|
struct diag_dci_client_tbl *entry = NULL;
|
||||||
|
|
||||||
length = *(uint16_t *)(buf + 1); /* total length of event series */
|
if (!buf) {
|
||||||
if (length == 0) {
|
pr_err("diag: In %s buffer is NULL\n", __func__);
|
||||||
pr_err("diag: Incoming dci event length is invalid\n");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Move directly to the start of the event series. 1 byte for
|
* 1 byte for event code and 2 bytes for the length field.
|
||||||
* event code and 2 bytes for the length field.
|
|
||||||
* The length field indicates the total length removing the cmd_code
|
* The length field indicates the total length removing the cmd_code
|
||||||
* and the lenght field. The event parsing in that case should happen
|
* and the lenght field. The event parsing in that case should happen
|
||||||
* till the end.
|
* 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;
|
temp_len = 3;
|
||||||
while (temp_len < length) {
|
while (temp_len < length) {
|
||||||
event_id_packet = *(uint16_t *)(buf + temp_len);
|
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.
|
* necessary.
|
||||||
*/
|
*/
|
||||||
timestamp_len = 8;
|
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 */
|
/* 13th and 14th bit represent the payload length */
|
||||||
if (((event_id_packet & 0x6000) >> 13) == 3) {
|
if (((event_id_packet & 0x6000) >> 13) == 3) {
|
||||||
payload_len_field = 1;
|
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);
|
(buf + temp_len + 2 + timestamp_len);
|
||||||
if (payload_len < (MAX_EVENT_SIZE - 13)) {
|
} else {
|
||||||
/* copy the payload length and the payload */
|
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 +
|
memcpy(event_data + 12, buf + temp_len + 2 +
|
||||||
timestamp_len, 1);
|
timestamp_len, 1);
|
||||||
memcpy(event_data + 13, buf + temp_len + 2 +
|
memcpy(event_data + 13, buf + temp_len + 2 +
|
||||||
timestamp_len + 1, payload_len);
|
timestamp_len + 1, payload_len);
|
||||||
} else {
|
} else {
|
||||||
pr_err("diag: event > %d, payload_len = %d\n",
|
pr_err("diag: event > %d, payload_len = %d, temp_len = %d\n",
|
||||||
(MAX_EVENT_SIZE - 13), payload_len);
|
(MAX_EVENT_SIZE - 13), payload_len, temp_len);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
payload_len_field = 0;
|
payload_len_field = 0;
|
||||||
payload_len = (event_id_packet & 0x6000) >> 13;
|
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);
|
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
|
/* 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__);
|
pr_err("diag: In %s buffer is NULL\n", __func__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
/* The first six bytes for the incoming log packet contains
|
* The first eight bytes for the incoming log packet contains
|
||||||
* Command code (2), the length of the packet (2) and the length
|
* Command code (2), the length of the packet (2), the length
|
||||||
* of the log (2)
|
* of the log (2) and log code (2)
|
||||||
*/
|
*/
|
||||||
log_code = *(uint16_t *)(buf + 6);
|
if (len < 8) {
|
||||||
read_bytes += sizeof(uint16_t) + 6;
|
pr_err("diag: In %s invalid len: %d\n", __func__, len);
|
||||||
if (read_bytes > len) {
|
|
||||||
pr_err("diag: Invalid length in %s, len: %d, read: %d",
|
|
||||||
__func__, len, read_bytes);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_code = *(uint16_t *)(buf + 6);
|
||||||
|
read_bytes += sizeof(uint16_t) + 6;
|
||||||
|
|
||||||
/* parse through log mask table of each client and check mask */
|
/* parse through log mask table of each client and check mask */
|
||||||
mutex_lock(&driver->dci_mutex);
|
mutex_lock(&driver->dci_mutex);
|
||||||
list_for_each_safe(start, temp, &driver->dci_client_list) {
|
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__);
|
pr_err("diag: In %s buffer is NULL\n", __func__);
|
||||||
return;
|
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;
|
version = *(uint8_t *)buf + 1;
|
||||||
if (version < EXT_HDR_VERSION) {
|
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 = buf + EXT_HDR_LEN;
|
||||||
pkt_cmd_code = *(uint8_t *)pkt;
|
pkt_cmd_code = *(uint8_t *)pkt;
|
||||||
len -= EXT_HDR_LEN;
|
len -= EXT_HDR_LEN;
|
||||||
if (len < 0) {
|
|
||||||
pr_err("diag: %s, Invalid length len: %d\n", __func__, len);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (pkt_cmd_code) {
|
switch (pkt_cmd_code) {
|
||||||
case LOG_CMD_CODE:
|
case LOG_CMD_CODE:
|
||||||
|
|
Loading…
Add table
Reference in a new issue