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:
parent
577a674bb7
commit
142fc006e7
|
@ -481,7 +481,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);
|
||||||
|
@ -537,7 +537,7 @@ static int diag_cmd_get_msg_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",
|
pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d",
|
||||||
__func__, src_buf, src_len, dest_buf, dest_len);
|
__func__, src_buf, src_len, dest_buf, dest_len);
|
||||||
|
@ -591,7 +591,8 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len,
|
||||||
struct diag_msg_build_mask_t rsp;
|
struct diag_msg_build_mask_t rsp;
|
||||||
uint32_t *temp = NULL;
|
uint32_t *temp = NULL;
|
||||||
|
|
||||||
if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0) {
|
if (!src_buf || !dest_buf || dest_len <= 0 ||
|
||||||
|
(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",
|
pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d",
|
||||||
__func__, src_buf, src_len, dest_buf, dest_len);
|
__func__, src_buf, src_len, dest_buf, dest_len);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -646,7 +647,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);
|
||||||
msg_mask.status = DIAG_CTRL_MASK_VALID;
|
msg_mask.status = DIAG_CTRL_MASK_VALID;
|
||||||
break;
|
break;
|
||||||
|
@ -690,7 +693,8 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len,
|
||||||
struct diag_msg_config_rsp_t *req = NULL;
|
struct diag_msg_config_rsp_t *req = NULL;
|
||||||
struct diag_msg_mask_t *mask = (struct diag_msg_mask_t *)msg_mask.ptr;
|
struct diag_msg_mask_t *mask = (struct diag_msg_mask_t *)msg_mask.ptr;
|
||||||
|
|
||||||
if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0) {
|
if (!src_buf || !dest_buf || dest_len <= 0 ||
|
||||||
|
(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",
|
pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d",
|
||||||
__func__, src_buf, src_len, dest_buf, dest_len);
|
__func__, src_buf, src_len, dest_buf, dest_len);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -777,7 +781,8 @@ static int diag_cmd_update_event_mask(unsigned char *src_buf, int src_len,
|
||||||
struct diag_event_mask_config_t rsp;
|
struct diag_event_mask_config_t rsp;
|
||||||
struct diag_event_mask_config_t *req;
|
struct diag_event_mask_config_t *req;
|
||||||
|
|
||||||
if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0) {
|
if (!src_buf || !dest_buf || dest_len <= 0 ||
|
||||||
|
(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",
|
pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d",
|
||||||
__func__, src_buf, src_len, dest_buf, dest_len);
|
__func__, src_buf, src_len, dest_buf, dest_len);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -792,7 +797,8 @@ static int diag_cmd_update_event_mask(unsigned char *src_buf, int src_len,
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&event_mask.lock);
|
mutex_lock(&event_mask.lock);
|
||||||
memcpy(event_mask.ptr, src_buf + header_len, mask_len);
|
if (src_len >= header_len + mask_len)
|
||||||
|
memcpy(event_mask.ptr, src_buf + header_len, mask_len);
|
||||||
event_mask.status = DIAG_CTRL_MASK_VALID;
|
event_mask.status = DIAG_CTRL_MASK_VALID;
|
||||||
mutex_unlock(&event_mask.lock);
|
mutex_unlock(&event_mask.lock);
|
||||||
diag_update_userspace_clients(EVENT_MASKS_TYPE);
|
diag_update_userspace_clients(EVENT_MASKS_TYPE);
|
||||||
|
@ -824,7 +830,8 @@ static int diag_cmd_toggle_events(unsigned char *src_buf, int src_len,
|
||||||
uint8_t toggle = 0;
|
uint8_t toggle = 0;
|
||||||
struct diag_event_report_t header;
|
struct diag_event_report_t header;
|
||||||
|
|
||||||
if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0) {
|
if (!src_buf || !dest_buf || dest_len <= 0 ||
|
||||||
|
(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",
|
pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d",
|
||||||
__func__, src_buf, src_len, dest_buf, dest_len);
|
__func__, src_buf, src_len, dest_buf, dest_len);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -870,7 +877,8 @@ static int diag_cmd_get_log_mask(unsigned char *src_buf, int src_len,
|
||||||
struct diag_log_config_req_t *req;
|
struct diag_log_config_req_t *req;
|
||||||
struct diag_log_config_rsp_t rsp;
|
struct diag_log_config_rsp_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_msg_build_mask_t))) {
|
||||||
pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d",
|
pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d",
|
||||||
__func__, src_buf, src_len, dest_buf, dest_len);
|
__func__, src_buf, src_len, dest_buf, dest_len);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -981,7 +989,8 @@ static int diag_cmd_set_log_mask(unsigned char *src_buf, int src_len,
|
||||||
struct diag_log_config_req_t *req;
|
struct diag_log_config_req_t *req;
|
||||||
struct diag_log_config_set_rsp_t rsp;
|
struct diag_log_config_set_rsp_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_msg_build_mask_t))) {
|
||||||
pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d",
|
pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d",
|
||||||
__func__, src_buf, src_len, dest_buf, dest_len);
|
__func__, src_buf, src_len, dest_buf, dest_len);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -1016,7 +1025,7 @@ static int diag_cmd_set_log_mask(unsigned char *src_buf, int src_len,
|
||||||
mask->num_items = LOG_SIZE_TO_ITEMS(mask_size);
|
mask->num_items = LOG_SIZE_TO_ITEMS(mask_size);
|
||||||
req->num_items = mask->num_items;
|
req->num_items = mask->num_items;
|
||||||
}
|
}
|
||||||
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);
|
||||||
mutex_unlock(&mask->lock);
|
mutex_unlock(&mask->lock);
|
||||||
log_mask.status = DIAG_CTRL_MASK_VALID;
|
log_mask.status = DIAG_CTRL_MASK_VALID;
|
||||||
|
|
|
@ -1121,15 +1121,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) {
|
||||||
|
@ -1145,6 +1149,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 */
|
||||||
|
@ -2267,7 +2273,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) {
|
||||||
|
@ -2281,7 +2288,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;
|
||||||
|
@ -2355,7 +2362,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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue