Skip to content
Snippets Groups Projects
Commit cad495d7 authored by Andrew Chant's avatar Andrew Chant Committed by Devin Kim
Browse files

input: synaptics_dsx: add update bounds checks.


Firmware updates contain offsets that are parsed
by the kernel driver.  Ensure all offsets are within
the bounds of the firmware update.

TESTED:
successfully parsed update firmware on device boot.

Bug: 31525965
Bug: 31968442
Change-Id: I074d3f26d33f723a0b239b59ebc3a680d991cdae
Signed-off-by: default avatarAndrew Chant <achant@google.com>
parent ee5f16f4
Branches
Tags android-wear-7.1.1_r0.3
No related merge requests found
...@@ -260,6 +260,7 @@ struct synaptics_rmi4_fwu_handle { ...@@ -260,6 +260,7 @@ struct synaptics_rmi4_fwu_handle {
bool interrupt_flag; bool interrupt_flag;
bool polling_mode; bool polling_mode;
char product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE + 1]; char product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE + 1];
unsigned int full_update_size;
unsigned int image_size; unsigned int image_size;
unsigned int data_pos; unsigned int data_pos;
unsigned char intr_mask; unsigned char intr_mask;
...@@ -338,6 +339,22 @@ static void synaptics_rmi4_toupper(char *d, const char *s, size_t sz) ...@@ -338,6 +339,22 @@ static void synaptics_rmi4_toupper(char *d, const char *s, size_t sz)
} }
} }
/* Check offset + size <= bound. 1 if in bounds, 0 otherwise. */
static bool in_bounds(unsigned long offset,
unsigned long size,
unsigned long bound)
{
if (offset > bound || size > bound) {
pr_err("%s: %lu or %lu > %lu\n", __func__, offset, size, bound);
return 0;
}
if (offset > (bound - size)) {
pr_err("%s: %lu > %lu - %lu\n", __func__, offset, size, bound);
return 0;
}
return 1;
}
static unsigned int extract_uint(const unsigned char *ptr) static unsigned int extract_uint(const unsigned char *ptr)
{ {
return (unsigned int)ptr[0] + return (unsigned int)ptr[0] +
...@@ -374,11 +391,17 @@ static void synaptics_rmi4_update_debug_info(void) ...@@ -374,11 +391,17 @@ static void synaptics_rmi4_update_debug_info(void)
pkg_id[3] << 8 | pkg_id[2], build_id); pkg_id[3] << 8 | pkg_id[2], build_id);
} }
static void parse_header(void) static int parse_header(void)
{ {
struct image_content *img = &fwu->image_content; struct image_content *img = &fwu->image_content;
struct image_header_data *data = struct image_header_data *data =
(struct image_header_data *)fwu->data_buffer; (struct image_header_data *)fwu->data_buffer;
if (fwu->full_update_size < sizeof(*data)) {
dev_err(&fwu->rmi4_data->i2c_client->dev,
"Provided update too small");
return -EINVAL;
}
img->checksum = extract_uint(data->file_checksum); img->checksum = extract_uint(data->file_checksum);
img->bootloader_version = data->bootloader_version; img->bootloader_version = data->bootloader_version;
img->image_size = extract_uint(data->firmware_size); img->image_size = extract_uint(data->firmware_size);
...@@ -418,12 +441,29 @@ static void parse_header(void) ...@@ -418,12 +441,29 @@ static void parse_header(void)
img->config_size); img->config_size);
/* get UI firmware offset */ /* get UI firmware offset */
if (img->image_size) if (img->image_size) {
if (!in_bounds(FW_IMAGE_OFFSET, img->image_size,
fwu->full_update_size)) {
dev_err(&fwu->rmi4_data->i2c_client->dev,
"%s: image size out of bounds\n",
__func__);
return -EINVAL;
}
img->firmware_data = fwu->data_buffer + FW_IMAGE_OFFSET; img->firmware_data = fwu->data_buffer + FW_IMAGE_OFFSET;
}
/* get config offset*/ /* get config offset*/
if (img->config_size) if (img->config_size) {
// FW_IMAGE_OFFSET + image_size was ok as above
if (!in_bounds(FW_IMAGE_OFFSET + img->image_size,
img->config_size, fwu->full_update_size)) {
dev_err(&fwu->rmi4_data->i2c_client->dev,
"%s: config size out of bounds\n",
__func__);
return -EINVAL;
}
img->config_data = fwu->data_buffer + FW_IMAGE_OFFSET + img->config_data = fwu->data_buffer + FW_IMAGE_OFFSET +
img->image_size; img->image_size;
}
/* get lockdown offset*/ /* get lockdown offset*/
switch (img->bootloader_version) { switch (img->bootloader_version) {
case 3: case 3:
...@@ -442,6 +482,14 @@ static void parse_header(void) ...@@ -442,6 +482,14 @@ static void parse_header(void)
img->lockdown_data = NULL; img->lockdown_data = NULL;
} }
if (img->lockdown_block_count * fwu->block_size > FW_IMAGE_OFFSET) {
dev_err(&fwu->rmi4_data->i2c_client->dev,
"%s: lockdown size too big\n",
__func__);
return -EINVAL;
}
if (fwu->full_update_size < FW_IMAGE_OFFSET)
return -EINVAL;
img->lockdown_data = fwu->data_buffer + img->lockdown_data = fwu->data_buffer +
FW_IMAGE_OFFSET - FW_IMAGE_OFFSET -
img->lockdown_block_count * fwu->block_size; img->lockdown_block_count * fwu->block_size;
...@@ -450,7 +498,7 @@ static void parse_header(void) ...@@ -450,7 +498,7 @@ static void parse_header(void)
fwu->lockdown_data = img->lockdown_data; fwu->lockdown_data = img->lockdown_data;
fwu->config_data = img->config_data; fwu->config_data = img->config_data;
fwu->firmware_data = img->firmware_data; fwu->firmware_data = img->firmware_data;
return; return 0;
} }
static int fwu_read_f01_device_status(struct f01_device_status *status) static int fwu_read_f01_device_status(struct f01_device_status *status)
...@@ -1343,8 +1391,8 @@ static int fwu_start_write_config(void) ...@@ -1343,8 +1391,8 @@ static int fwu_start_write_config(void)
"%s: write config from config file\n", "%s: write config from config file\n",
__func__); __func__);
fwu->config_data = fwu->data_buffer; fwu->config_data = fwu->data_buffer;
} else { } else if (parse_header()) {
parse_header(); return -EINVAL;
} }
pr_notice("%s: Start of write config process\n", __func__); pr_notice("%s: Start of write config process\n", __func__);
...@@ -1411,7 +1459,8 @@ exit: ...@@ -1411,7 +1459,8 @@ exit:
static int fwu_start_write_lockdown(void) static int fwu_start_write_lockdown(void)
{ {
parse_header(); if (parse_header())
return -EINVAL;
return fwu_do_write_lockdown(true); return fwu_do_write_lockdown(true);
} }
...@@ -1627,9 +1676,13 @@ static int fwu_start_reflash(void) ...@@ -1627,9 +1676,13 @@ static int fwu_start_reflash(void)
__func__, fw_entry->size); __func__, fw_entry->size);
fwu->data_buffer = fw_entry->data; fwu->data_buffer = fw_entry->data;
fwu->full_update_size = fw_entry->size;
} }
parse_header(); if (parse_header()) {
retval = -EINVAL;
goto exit;
}
flash_area = fwu_go_nogo(); flash_area = fwu_go_nogo();
if (fwu->rmi4_data->sensor_sleep) { if (fwu->rmi4_data->sensor_sleep) {
...@@ -2019,6 +2072,7 @@ static ssize_t fwu_sysfs_image_size_store(struct device *dev, ...@@ -2019,6 +2072,7 @@ static ssize_t fwu_sysfs_image_size_store(struct device *dev,
if (retval) if (retval)
return retval; return retval;
fwu->full_update_size = size;
fwu->image_size = size; fwu->image_size = size;
fwu->data_pos = 0; fwu->data_pos = 0;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment