diag: Add protection while processing non-hdlc packets
Currently, there is possibility of out-of-bound accesses during handling of data in non-hdlc path. The patch adds proper protection when processing non-hdlc packet information to fix the issue. CRs-Fixed: 2029216 Change-Id: I07c466f85bd8ac08226948fea86b1d8567e68431 Signed-off-by: Hardik Arya <harya@codeaurora.org>
This commit is contained in:
parent
959abd171b
commit
c36e61af0f
3 changed files with 35 additions and 9 deletions
|
@ -578,6 +578,7 @@ struct diagchar_dev {
|
||||||
unsigned char *buf_feature_mask_update;
|
unsigned char *buf_feature_mask_update;
|
||||||
uint8_t hdlc_disabled;
|
uint8_t hdlc_disabled;
|
||||||
struct mutex hdlc_disable_mutex;
|
struct mutex hdlc_disable_mutex;
|
||||||
|
struct mutex hdlc_recovery_mutex;
|
||||||
struct timer_list hdlc_reset_timer;
|
struct timer_list hdlc_reset_timer;
|
||||||
struct mutex diag_hdlc_mutex;
|
struct mutex diag_hdlc_mutex;
|
||||||
unsigned char *hdlc_buf;
|
unsigned char *hdlc_buf;
|
||||||
|
|
|
@ -3621,6 +3621,7 @@ static int __init diagchar_init(void)
|
||||||
mutex_init(&driver->delayed_rsp_mutex);
|
mutex_init(&driver->delayed_rsp_mutex);
|
||||||
mutex_init(&apps_data_mutex);
|
mutex_init(&apps_data_mutex);
|
||||||
mutex_init(&driver->msg_mask_lock);
|
mutex_init(&driver->msg_mask_lock);
|
||||||
|
mutex_init(&driver->hdlc_recovery_mutex);
|
||||||
for (i = 0; i < NUM_PERIPHERALS; i++)
|
for (i = 0; i < NUM_PERIPHERALS; i++)
|
||||||
mutex_init(&driver->diagfwd_channel_mutex[i]);
|
mutex_init(&driver->diagfwd_channel_mutex[i]);
|
||||||
init_waitqueue_head(&driver->wait_q);
|
init_waitqueue_head(&driver->wait_q);
|
||||||
|
|
|
@ -1405,7 +1405,9 @@ static void diag_hdlc_start_recovery(unsigned char *buf, int len,
|
||||||
|
|
||||||
if (start_ptr) {
|
if (start_ptr) {
|
||||||
/* Discard any partial packet reads */
|
/* Discard any partial packet reads */
|
||||||
|
mutex_lock(&driver->hdlc_recovery_mutex);
|
||||||
driver->incoming_pkt.processing = 0;
|
driver->incoming_pkt.processing = 0;
|
||||||
|
mutex_unlock(&driver->hdlc_recovery_mutex);
|
||||||
diag_process_non_hdlc_pkt(start_ptr, len - i, info);
|
diag_process_non_hdlc_pkt(start_ptr, len - i, info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1419,18 +1421,24 @@ void diag_process_non_hdlc_pkt(unsigned char *buf, int len,
|
||||||
const uint32_t header_len = sizeof(struct diag_pkt_frame_t);
|
const uint32_t header_len = sizeof(struct diag_pkt_frame_t);
|
||||||
struct diag_pkt_frame_t *actual_pkt = NULL;
|
struct diag_pkt_frame_t *actual_pkt = NULL;
|
||||||
unsigned char *data_ptr = NULL;
|
unsigned char *data_ptr = NULL;
|
||||||
struct diag_partial_pkt_t *partial_pkt = &driver->incoming_pkt;
|
struct diag_partial_pkt_t *partial_pkt = NULL;
|
||||||
|
|
||||||
if (!buf || len <= 0)
|
mutex_lock(&driver->hdlc_recovery_mutex);
|
||||||
|
if (!buf || len <= 0) {
|
||||||
|
mutex_unlock(&driver->hdlc_recovery_mutex);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
if (!partial_pkt->processing)
|
partial_pkt = &driver->incoming_pkt;
|
||||||
|
if (!partial_pkt->processing) {
|
||||||
|
mutex_unlock(&driver->hdlc_recovery_mutex);
|
||||||
goto start;
|
goto start;
|
||||||
|
}
|
||||||
|
|
||||||
if (partial_pkt->remaining > len) {
|
if (partial_pkt->remaining > len) {
|
||||||
if ((partial_pkt->read_len + len) > partial_pkt->capacity) {
|
if ((partial_pkt->read_len + len) > partial_pkt->capacity) {
|
||||||
pr_err("diag: Invalid length %d, %d received in %s\n",
|
pr_err("diag: Invalid length %d, %d received in %s\n",
|
||||||
partial_pkt->read_len, len, __func__);
|
partial_pkt->read_len, len, __func__);
|
||||||
|
mutex_unlock(&driver->hdlc_recovery_mutex);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
memcpy(partial_pkt->data + partial_pkt->read_len, buf, len);
|
memcpy(partial_pkt->data + partial_pkt->read_len, buf, len);
|
||||||
|
@ -1444,6 +1452,7 @@ void diag_process_non_hdlc_pkt(unsigned char *buf, int len,
|
||||||
pr_err("diag: Invalid length during partial read %d, %d received in %s\n",
|
pr_err("diag: Invalid length during partial read %d, %d received in %s\n",
|
||||||
partial_pkt->read_len,
|
partial_pkt->read_len,
|
||||||
partial_pkt->remaining, __func__);
|
partial_pkt->remaining, __func__);
|
||||||
|
mutex_unlock(&driver->hdlc_recovery_mutex);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
memcpy(partial_pkt->data + partial_pkt->read_len, buf,
|
memcpy(partial_pkt->data + partial_pkt->read_len, buf,
|
||||||
|
@ -1457,20 +1466,27 @@ void diag_process_non_hdlc_pkt(unsigned char *buf, int len,
|
||||||
if (partial_pkt->remaining == 0) {
|
if (partial_pkt->remaining == 0) {
|
||||||
actual_pkt = (struct diag_pkt_frame_t *)(partial_pkt->data);
|
actual_pkt = (struct diag_pkt_frame_t *)(partial_pkt->data);
|
||||||
data_ptr = partial_pkt->data + header_len;
|
data_ptr = partial_pkt->data + header_len;
|
||||||
if (*(uint8_t *)(data_ptr + actual_pkt->length) != CONTROL_CHAR)
|
if (*(uint8_t *)(data_ptr + actual_pkt->length) !=
|
||||||
|
CONTROL_CHAR) {
|
||||||
|
mutex_unlock(&driver->hdlc_recovery_mutex);
|
||||||
diag_hdlc_start_recovery(buf, len, info);
|
diag_hdlc_start_recovery(buf, len, info);
|
||||||
|
mutex_lock(&driver->hdlc_recovery_mutex);
|
||||||
|
}
|
||||||
err = diag_process_apps_pkt(data_ptr,
|
err = diag_process_apps_pkt(data_ptr,
|
||||||
actual_pkt->length, info);
|
actual_pkt->length, info);
|
||||||
if (err) {
|
if (err) {
|
||||||
pr_err("diag: In %s, unable to process incoming data packet, err: %d\n",
|
pr_err("diag: In %s, unable to process incoming data packet, err: %d\n",
|
||||||
__func__, err);
|
__func__, err);
|
||||||
|
mutex_unlock(&driver->hdlc_recovery_mutex);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
partial_pkt->read_len = 0;
|
partial_pkt->read_len = 0;
|
||||||
partial_pkt->total_len = 0;
|
partial_pkt->total_len = 0;
|
||||||
partial_pkt->processing = 0;
|
partial_pkt->processing = 0;
|
||||||
|
mutex_unlock(&driver->hdlc_recovery_mutex);
|
||||||
goto start;
|
goto start;
|
||||||
}
|
}
|
||||||
|
mutex_unlock(&driver->hdlc_recovery_mutex);
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
start:
|
start:
|
||||||
|
@ -1483,14 +1499,14 @@ start:
|
||||||
diag_send_error_rsp(buf, len, info);
|
diag_send_error_rsp(buf, len, info);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
mutex_lock(&driver->hdlc_recovery_mutex);
|
||||||
if (pkt_len + header_len > partial_pkt->capacity) {
|
if (pkt_len + header_len > partial_pkt->capacity) {
|
||||||
pr_err("diag: In %s, incoming data is too large for the request buffer %d\n",
|
pr_err("diag: In %s, incoming data is too large for the request buffer %d\n",
|
||||||
__func__, pkt_len);
|
__func__, pkt_len);
|
||||||
|
mutex_unlock(&driver->hdlc_recovery_mutex);
|
||||||
diag_hdlc_start_recovery(buf, len, info);
|
diag_hdlc_start_recovery(buf, len, info);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((pkt_len + header_len) > (len - read_bytes)) {
|
if ((pkt_len + header_len) > (len - read_bytes)) {
|
||||||
partial_pkt->read_len = len - read_bytes;
|
partial_pkt->read_len = len - read_bytes;
|
||||||
partial_pkt->total_len = pkt_len + header_len;
|
partial_pkt->total_len = pkt_len + header_len;
|
||||||
|
@ -1498,19 +1514,27 @@ start:
|
||||||
partial_pkt->read_len;
|
partial_pkt->read_len;
|
||||||
partial_pkt->processing = 1;
|
partial_pkt->processing = 1;
|
||||||
memcpy(partial_pkt->data, buf, partial_pkt->read_len);
|
memcpy(partial_pkt->data, buf, partial_pkt->read_len);
|
||||||
|
mutex_unlock(&driver->hdlc_recovery_mutex);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
data_ptr = buf + header_len;
|
data_ptr = buf + header_len;
|
||||||
if (*(uint8_t *)(data_ptr + actual_pkt->length) != CONTROL_CHAR)
|
if (*(uint8_t *)(data_ptr + actual_pkt->length) !=
|
||||||
|
CONTROL_CHAR) {
|
||||||
|
mutex_unlock(&driver->hdlc_recovery_mutex);
|
||||||
diag_hdlc_start_recovery(buf, len, info);
|
diag_hdlc_start_recovery(buf, len, info);
|
||||||
|
mutex_lock(&driver->hdlc_recovery_mutex);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
hdlc_reset = 0;
|
hdlc_reset = 0;
|
||||||
err = diag_process_apps_pkt(data_ptr,
|
err = diag_process_apps_pkt(data_ptr,
|
||||||
actual_pkt->length, info);
|
actual_pkt->length, info);
|
||||||
if (err)
|
if (err) {
|
||||||
|
mutex_unlock(&driver->hdlc_recovery_mutex);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
read_bytes += header_len + pkt_len + 1;
|
read_bytes += header_len + pkt_len + 1;
|
||||||
buf += header_len + pkt_len + 1; /* advance to next pkt */
|
buf += header_len + pkt_len + 1; /* advance to next pkt */
|
||||||
|
mutex_unlock(&driver->hdlc_recovery_mutex);
|
||||||
}
|
}
|
||||||
end:
|
end:
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Add table
Reference in a new issue