diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
index 1f7409efb1565562efc5effc6d5c805bb6e22d41..b22eb1e98e7ce9f8d14a04344a42a346041b98fe 100644
--- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
@@ -347,6 +347,22 @@ static struct synaptics_rmi4_fwu_handle *fwu;
 DECLARE_COMPLETION(fwu_dsx_remove_complete);
 DEFINE_MUTEX(dsx_fwu_sysfs_mutex);
 
+/* Check offset + size <= bound.  1 if in bounds, 0 otherwise. */
+static int 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_le(const unsigned char *ptr)
 {
 	return (unsigned int)ptr[0] +
@@ -363,10 +379,17 @@ static unsigned int extract_uint_be(const unsigned char *ptr)
 			(unsigned int)ptr[0] * 0x1000000;
 }
 
-static void parse_header(struct image_header_data *header,
-		const unsigned char *fw_image)
+static int parse_header(struct image_header_data *header,
+		const unsigned char *fw_image,
+		const unsigned long fw_image_len)
 {
 	struct image_header *data = (struct image_header *)fw_image;
+	if (fw_image_len < sizeof(*data)) {
+		dev_err(fwu->rmi4_data->pdev->dev.parent,
+				"%s: update too small\n",
+				__func__);
+		return -EINVAL;
+	}
 
 	header->checksum = extract_uint_le(data->checksum);
 
@@ -386,7 +409,7 @@ static void parse_header(struct image_header_data *header,
 	if (header->contains_firmware_id)
 		header->firmware_id = extract_uint_le(data->firmware_id);
 
-	return;
+	return 0;
 }
 
 static int fwu_read_f01_device_status(struct f01_device_status *status)
@@ -1184,9 +1207,29 @@ static int fwu_start_write_config(void)
 	/* Jump to the config area if given a packrat image */
 	if ((fwu->config_area == UI_CONFIG_AREA) &&
 			(fwu->config_size != fwu->image_size)) {
-		parse_header(&header, fwu->ext_data_source);
+		if (parse_header(&header,
+				 fwu->ext_data_source,
+				 fwu->image_size)) {
+			return -EINVAL;
+		}
 
 		if (header.config_size) {
+			if (!in_bounds(FW_IMAGE_OFFSET,
+				       header.firmware_size,
+				       fwu->image_size)) {
+				dev_err(rmi4_data->pdev->dev.parent,
+						"%s: Firmware out of bounds\n",
+						__func__);
+				return -EINVAL;
+			}
+			if (!in_bounds(FW_IMAGE_OFFSET + header.firmware_size,
+				       header.config_size,
+				       fwu->image_size)) {
+				dev_err(rmi4_data->pdev->dev.parent,
+						"%s: Config out of bounds\n",
+						__func__);
+				return -EINVAL;
+			}
 			fwu->config_data = fwu->ext_data_source +
 					FW_IMAGE_OFFSET +
 					header.firmware_size;
@@ -1363,6 +1406,7 @@ static int fwu_start_reflash(void)
 	struct image_header_data header;
 	struct f01_device_status f01_device_status;
 	const unsigned char *fw_image;
+	unsigned long fw_image_len = 0;
 	const struct firmware *fw_entry = NULL;
 	struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
 
@@ -1379,6 +1423,7 @@ static int fwu_start_reflash(void)
 
 	if (fwu->ext_data_source) {
 		fw_image = fwu->ext_data_source;
+		fw_image_len = fwu->image_size;
 	} else {
 		dev_dbg(rmi4_data->pdev->dev.parent,
 				"%s: Requesting firmware image %s\n",
@@ -1399,13 +1444,20 @@ static int fwu_start_reflash(void)
 				__func__, fw_entry->size);
 
 		fw_image = fw_entry->data;
+		fw_image_len = fw_entry->size;
 	}
 
-	parse_header(&header, fw_image);
+	if (parse_header(&header, fw_image, fw_image_len)) {
+		dev_err(rmi4_data->pdev->dev.parent,
+				"%s: couldn't parse header\n",
+				__func__);
+		retval = -EINVAL;
+		goto exit;
+	}
 
 	if (fwu->bl_version != header.bootloader_version) {
 		dev_err(rmi4_data->pdev->dev.parent,
-				"%s: Bootloader version mismatch\n",
+				"%s: bootloader version mismatch\n",
 				__func__);
 		retval = -EINVAL;
 		goto exit;
@@ -1441,9 +1493,26 @@ static int fwu_start_reflash(void)
 		}
 	}
 
-	if (header.firmware_size)
+	if (header.firmware_size) {
+		if (!in_bounds(FW_IMAGE_OFFSET,
+			       header.firmware_size,
+			       fw_image_len)) {
+			dev_err(rmi4_data->pdev->dev.parent,
+					"%s: Firmware out of bounds\n",
+					__func__);
+			return -EINVAL;
+		}
 		fwu->firmware_data = fw_image + FW_IMAGE_OFFSET;
+	}
 	if (header.config_size) {
+		if (!in_bounds(FW_IMAGE_OFFSET + header.firmware_size,
+			       header.config_size,
+			       fw_image_len)) {
+			dev_err(rmi4_data->pdev->dev.parent,
+					"%s: Config out of bounds\n",
+					__func__);
+			return -EINVAL;
+		}
 		fwu->config_data = fw_image + FW_IMAGE_OFFSET +
 				header.firmware_size;
 	}