diag: Prevent out-of-bound access while processing userspace data

Proper buffer length checks are missing in diagchar_write
handlers for userspace data while processing the same buffer.

Change-Id: I5b8095766e09c22f164398089505fe827fee8b54
Signed-off-by: Hardik Arya <harya@codeaurora.org>
This commit is contained in:
Hardik Arya 2019-04-30 12:48:29 +05:30 committed by Manoj Prabhu B
parent 2692bfe650
commit 25e6769daa
2 changed files with 32 additions and 22 deletions

View file

@ -643,7 +643,7 @@ static int diag_cmd_get_build_mask(unsigned char *src_buf, int src_len,
struct diag_build_mask_req_t *req = NULL; struct diag_build_mask_req_t *req = NULL;
struct diag_msg_build_mask_t rsp; struct diag_msg_build_mask_t rsp;
if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || if (!src_buf || !dest_buf || dest_len <= 0 ||
src_len < sizeof(struct diag_build_mask_req_t)) { src_len < sizeof(struct diag_build_mask_req_t)) {
pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d\n", pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d\n",
__func__, src_buf, src_len, dest_buf, dest_len); __func__, src_buf, src_len, dest_buf, dest_len);
@ -705,7 +705,7 @@ static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len,
info = diag_md_session_get_pid(pid); info = diag_md_session_get_pid(pid);
mask_info = (!info) ? &msg_mask : info->msg_mask; mask_info = (!info) ? &msg_mask : info->msg_mask;
if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || if (!src_buf || !dest_buf || dest_len <= 0 ||
!mask_info || (src_len < sizeof(struct diag_build_mask_req_t))) { !mask_info || (src_len < sizeof(struct diag_build_mask_req_t))) {
pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n",
__func__, src_buf, src_len, dest_buf, dest_len, __func__, src_buf, src_len, dest_buf, dest_len,
@ -787,8 +787,8 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len,
info = diag_md_session_get_pid(pid); info = diag_md_session_get_pid(pid);
mask_info = (!info) ? &msg_mask : info->msg_mask; mask_info = (!info) ? &msg_mask : info->msg_mask;
if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || if (!src_buf || !dest_buf || dest_len <= 0 || !mask_info ||
!mask_info) { (src_len < sizeof(struct diag_msg_build_mask_t))) {
pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n",
__func__, src_buf, src_len, dest_buf, dest_len, __func__, src_buf, src_len, dest_buf, dest_len,
mask_info); mask_info);
@ -872,7 +872,9 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len,
break; break;
} }
mask_size = mask_size * sizeof(uint32_t); mask_size = mask_size * sizeof(uint32_t);
memcpy(mask->ptr + offset, src_buf + header_len, mask_size); if (mask_size && src_len >= header_len + mask_size)
memcpy(mask->ptr + offset, src_buf + header_len,
mask_size);
mutex_unlock(&mask->lock); mutex_unlock(&mask->lock);
mask_info->status = DIAG_CTRL_MASK_VALID; mask_info->status = DIAG_CTRL_MASK_VALID;
break; break;
@ -929,8 +931,8 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len,
info = diag_md_session_get_pid(pid); info = diag_md_session_get_pid(pid);
mask_info = (!info) ? &msg_mask : info->msg_mask; mask_info = (!info) ? &msg_mask : info->msg_mask;
if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || if (!src_buf || !dest_buf || dest_len <= 0 || !mask_info ||
!mask_info) { (src_len < sizeof(struct diag_msg_config_rsp_t))) {
pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n",
__func__, src_buf, src_len, dest_buf, dest_len, __func__, src_buf, src_len, dest_buf, dest_len,
mask_info); mask_info);
@ -1049,8 +1051,8 @@ static int diag_cmd_update_event_mask(unsigned char *src_buf, int src_len,
mutex_lock(&driver->md_session_lock); mutex_lock(&driver->md_session_lock);
info = diag_md_session_get_pid(pid); info = diag_md_session_get_pid(pid);
mask_info = (!info) ? &event_mask : info->event_mask; mask_info = (!info) ? &event_mask : info->event_mask;
if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || if (!src_buf || !dest_buf || dest_len <= 0 || !mask_info ||
!mask_info) { src_len < sizeof(struct diag_event_mask_config_t)) {
pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n",
__func__, src_buf, src_len, dest_buf, dest_len, __func__, src_buf, src_len, dest_buf, dest_len,
mask_info); mask_info);
@ -1073,7 +1075,8 @@ static int diag_cmd_update_event_mask(unsigned char *src_buf, int src_len,
} }
mutex_lock(&mask_info->lock); mutex_lock(&mask_info->lock);
memcpy(mask_info->ptr, src_buf + header_len, mask_len); if (src_len >= header_len + mask_len)
memcpy(mask_info->ptr, src_buf + header_len, mask_len);
mask_info->status = DIAG_CTRL_MASK_VALID; mask_info->status = DIAG_CTRL_MASK_VALID;
mutex_unlock(&mask_info->lock); mutex_unlock(&mask_info->lock);
mutex_unlock(&driver->md_session_lock); mutex_unlock(&driver->md_session_lock);
@ -1117,8 +1120,8 @@ static int diag_cmd_toggle_events(unsigned char *src_buf, int src_len,
mutex_lock(&driver->md_session_lock); mutex_lock(&driver->md_session_lock);
info = diag_md_session_get_pid(pid); info = diag_md_session_get_pid(pid);
mask_info = (!info) ? &event_mask : info->event_mask; mask_info = (!info) ? &event_mask : info->event_mask;
if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || if (!src_buf || !dest_buf || src_len <= sizeof(uint8_t) ||
!mask_info) { dest_len <= 0 || !mask_info) {
pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n",
__func__, src_buf, src_len, dest_buf, dest_len, __func__, src_buf, src_len, dest_buf, dest_len,
mask_info); mask_info);
@ -1185,8 +1188,8 @@ static int diag_cmd_get_log_mask(unsigned char *src_buf, int src_len,
info = diag_md_session_get_pid(pid); info = diag_md_session_get_pid(pid);
mask_info = (!info) ? &log_mask : info->log_mask; mask_info = (!info) ? &log_mask : info->log_mask;
if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || if (!src_buf || !dest_buf || dest_len <= 0 || !mask_info ||
!mask_info) { src_len < sizeof(struct diag_log_config_req_t)) {
pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n",
__func__, src_buf, src_len, dest_buf, dest_len, __func__, src_buf, src_len, dest_buf, dest_len,
mask_info); mask_info);
@ -1329,8 +1332,8 @@ static int diag_cmd_set_log_mask(unsigned char *src_buf, int src_len,
info = diag_md_session_get_pid(pid); info = diag_md_session_get_pid(pid);
mask_info = (!info) ? &log_mask : info->log_mask; mask_info = (!info) ? &log_mask : info->log_mask;
if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || if (!src_buf || !dest_buf || dest_len <= 0 || !mask_info ||
!mask_info) { src_len < sizeof(struct diag_log_config_req_t)) {
pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n", pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n",
__func__, src_buf, src_len, dest_buf, dest_len, __func__, src_buf, src_len, dest_buf, dest_len,
mask_info); mask_info);
@ -1404,7 +1407,7 @@ static int diag_cmd_set_log_mask(unsigned char *src_buf, int src_len,
mask->range_tools = mask_size; mask->range_tools = mask_size;
} }
req->num_items = mask->num_items_tools; req->num_items = mask->num_items_tools;
if (mask_size > 0) if (mask_size > 0 && src_len >= read_len + mask_size)
memcpy(mask->ptr, src_buf + read_len, mask_size); memcpy(mask->ptr, src_buf + read_len, mask_size);
DIAG_LOG(DIAG_DEBUG_MASKS, DIAG_LOG(DIAG_DEBUG_MASKS,
"copying log mask, e %d num %d range %d size %d\n", "copying log mask, e %d num %d range %d size %d\n",

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved. /* Copyright (c) 2008-2019, 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
@ -1187,15 +1187,19 @@ static int diag_process_userspace_remote(int proc, void *buf, int len)
} }
#endif #endif
static int mask_request_validate(unsigned char mask_buf[]) static int mask_request_validate(unsigned char mask_buf[], int len)
{ {
uint8_t packet_id; uint8_t packet_id;
uint8_t subsys_id; uint8_t subsys_id;
uint16_t ss_cmd; uint16_t ss_cmd;
if (len <= 0)
return 0;
packet_id = mask_buf[0]; packet_id = mask_buf[0];
if (packet_id == DIAG_CMD_DIAG_SUBSYS_DELAY) { if (packet_id == DIAG_CMD_DIAG_SUBSYS_DELAY) {
if (len < 2*sizeof(uint8_t) + sizeof(uint16_t))
return 0;
subsys_id = mask_buf[1]; subsys_id = mask_buf[1];
ss_cmd = *(uint16_t *)(mask_buf + 2); ss_cmd = *(uint16_t *)(mask_buf + 2);
switch (subsys_id) { switch (subsys_id) {
@ -1211,6 +1215,8 @@ static int mask_request_validate(unsigned char mask_buf[])
return 0; return 0;
} }
} else if (packet_id == 0x4B) { } else if (packet_id == 0x4B) {
if (len < 2*sizeof(uint8_t) + sizeof(uint16_t))
return 0;
subsys_id = mask_buf[1]; subsys_id = mask_buf[1];
ss_cmd = *(uint16_t *)(mask_buf + 2); ss_cmd = *(uint16_t *)(mask_buf + 2);
/* Packets with SSID which are allowed */ /* Packets with SSID which are allowed */
@ -2892,7 +2898,8 @@ static int diag_user_process_raw_data(const char __user *buf, int len)
} }
/* Check for proc_type */ /* Check for proc_type */
remote_proc = diag_get_remote(*(int *)user_space_data); if (len >= sizeof(int))
remote_proc = diag_get_remote(*(int *)user_space_data);
if (remote_proc) { if (remote_proc) {
token_offset = sizeof(int); token_offset = sizeof(int);
if (len <= MIN_SIZ_ALLOW) { if (len <= MIN_SIZ_ALLOW) {
@ -2906,7 +2913,7 @@ static int diag_user_process_raw_data(const char __user *buf, int len)
} }
if (driver->mask_check) { if (driver->mask_check) {
if (!mask_request_validate(user_space_data + if (!mask_request_validate(user_space_data +
token_offset)) { token_offset, len)) {
pr_alert("diag: mask request Invalid\n"); pr_alert("diag: mask request Invalid\n");
diagmem_free(driver, user_space_data, mempool); diagmem_free(driver, user_space_data, mempool);
user_space_data = NULL; user_space_data = NULL;
@ -2984,7 +2991,7 @@ static int diag_user_process_userspace_data(const char __user *buf, int len)
/* Check masks for On-Device logging */ /* Check masks for On-Device logging */
if (driver->mask_check) { if (driver->mask_check) {
if (!mask_request_validate(driver->user_space_data_buf + if (!mask_request_validate(driver->user_space_data_buf +
token_offset)) { token_offset, len)) {
pr_alert("diag: mask request Invalid\n"); pr_alert("diag: mask request Invalid\n");
return -EFAULT; return -EFAULT;
} }