[PATCH] fsi: master-ast-cf: validate firmware image bounds

Laxman Acharya Padhya posted 1 patch 3 hours ago
drivers/fsi/fsi-master-ast-cf.c | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
[PATCH] fsi: master-ast-cf: validate firmware image bounds
Posted by Laxman Acharya Padhya 3 hours ago
load_copro_firmware() reads the image signature and size from a fixed
offset before checking that the firmware contains the corresponding
header.  A truncated firmware file can therefore cause an out-of-bounds
read.  The image size is also used to advance through the blob and to
copy the selected image to the coprocessor without checking that it is
non-zero, large enough for the header, or contained in the firmware
buffer.

Validate the header and image range before reading or copying any image.
This also prevents a zero image size from making the image scan loop
never advance.

Signed-off-by: Laxman Acharya Padhya <acharyalaxman8848@gmail.com>
---
 drivers/fsi/fsi-master-ast-cf.c | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/drivers/fsi/fsi-master-ast-cf.c b/drivers/fsi/fsi-master-ast-cf.c
index c3ac76bf7e9..410bd600cd7 100644
--- a/drivers/fsi/fsi-master-ast-cf.c
+++ b/drivers/fsi/fsi-master-ast-cf.c
@@ -831,6 +831,8 @@ static int load_copro_firmware(struct fsi_master_acf *master)
 	const struct firmware *fw;
 	uint16_t sig = 0, wanted_sig;
 	const u8 *data;
+	const u8 *end;
+	const size_t image_hdr_size = HDR_OFFSET + HDR_FW_SIZE + sizeof(__be32);
 	size_t size = 0;
 	int rc;
 
@@ -851,9 +853,23 @@ static int load_copro_firmware(struct fsi_master_acf *master)
 	dev_dbg(master->dev, "Looking for image sig %04x\n", wanted_sig);
 
 	/* Try to find it */
-	for (data = fw->data; data < (fw->data + fw->size);) {
+	end = fw->data + fw->size;
+	for (data = fw->data; data < end;) {
+		if (end - data < image_hdr_size) {
+			dev_err(master->dev, "Truncated firmware image header\n");
+			rc = -EINVAL;
+			goto release_fw;
+		}
+
 		sig = be16_to_cpup((__be16 *)(data + HDR_OFFSET + HDR_SYS_SIG));
 		size = be32_to_cpup((__be32 *)(data + HDR_OFFSET + HDR_FW_SIZE));
+		if (size < image_hdr_size ||
+		    size > end - data) {
+			dev_err(master->dev, "Invalid firmware image size %zu\n", size);
+			rc = -EINVAL;
+			goto release_fw;
+		}
+
 		if (sig == wanted_sig)
 			break;
 		data += size;
-- 
2.51.2