diff options
author | Andrew Chant <achant@google.com> | 2016-11-13 17:03:13 -0800 |
---|---|---|
committer | Devin Kim <dojip.kim@lge.com> | 2017-01-26 14:29:40 -0800 |
commit | cad495d7b3829516e09f120f5d64e8cad53cc6de (patch) | |
tree | 86f8c5f9edc11013c9942a6ca16ae02a584a39bf | |
parent | ee5f16f49eb5da519f8846a272edf1cdeeb96bb3 (diff) |
input: synaptics_dsx: add update bounds checks.android-wear-7.1.1_r0.3
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: Andrew Chant <achant@google.com>
-rw-r--r-- | drivers/input/touchscreen/synaptics_fw_update.c | 70 |
1 files changed, 62 insertions, 8 deletions
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c index 517bf76136b7..14f1f0225169 100644 --- a/drivers/input/touchscreen/synaptics_fw_update.c +++ b/drivers/input/touchscreen/synaptics_fw_update.c @@ -260,6 +260,7 @@ struct synaptics_rmi4_fwu_handle { bool interrupt_flag; bool polling_mode; char product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE + 1]; + unsigned int full_update_size; unsigned int image_size; unsigned int data_pos; unsigned char intr_mask; @@ -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) { return (unsigned int)ptr[0] + @@ -374,11 +391,17 @@ static void synaptics_rmi4_update_debug_info(void) 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_header_data *data = (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->bootloader_version = data->bootloader_version; img->image_size = extract_uint(data->firmware_size); @@ -418,12 +441,29 @@ static void parse_header(void) img->config_size); /* 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; + } /* 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->image_size; + } /* get lockdown offset*/ switch (img->bootloader_version) { case 3: @@ -442,6 +482,14 @@ static void parse_header(void) 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 + FW_IMAGE_OFFSET - img->lockdown_block_count * fwu->block_size; @@ -450,7 +498,7 @@ static void parse_header(void) fwu->lockdown_data = img->lockdown_data; fwu->config_data = img->config_data; fwu->firmware_data = img->firmware_data; - return; + return 0; } static int fwu_read_f01_device_status(struct f01_device_status *status) @@ -1343,8 +1391,8 @@ static int fwu_start_write_config(void) "%s: write config from config file\n", __func__); fwu->config_data = fwu->data_buffer; - } else { - parse_header(); + } else if (parse_header()) { + return -EINVAL; } pr_notice("%s: Start of write config process\n", __func__); @@ -1411,7 +1459,8 @@ exit: static int fwu_start_write_lockdown(void) { - parse_header(); + if (parse_header()) + return -EINVAL; return fwu_do_write_lockdown(true); } @@ -1627,9 +1676,13 @@ static int fwu_start_reflash(void) __func__, fw_entry->size); 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(); if (fwu->rmi4_data->sensor_sleep) { @@ -2019,6 +2072,7 @@ static ssize_t fwu_sysfs_image_size_store(struct device *dev, if (retval) return retval; + fwu->full_update_size = size; fwu->image_size = size; fwu->data_pos = 0; |