From: Peter E. Berger Date: Fri, 31 Jul 2015 06:55:07 +0000 (-0500) Subject: USB: io_ti: Add firmware image sanity checks X-Git-Tag: firefly_0821_release~176^2~1219^2~15^2~1 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=dcb8e99dbc8a8a7825e39a43e79558d46b20d1e5;p=firefly-linux-kernel-4.4.55.git USB: io_ti: Add firmware image sanity checks Do what we can to verify that the driver's firmware image is valid (before attempting to download it to the Edgeport) by adding a new function, check_fw_sanity(), and a call to it in in download_fw(). Note: It looks like some Edgeports (models like the EP/416 with on-board E2PROM) may be able to function even if the on-disk firmware image is bad or missing, iff their local E2PROM versions are valid. But most Edgeport models (I've tried EP/1 and EP/8) do not appear to have this capability and they always rely on the on-disk firmware image. I tested an implementation that calls the new check_fw_sanity() function at the top of download_fw() and, rather than simply returning an error if the firmware image is bad or missing, it saves the result and defers the decision until later when it may find that it is running on a E2PROM-equipped device with a valid image. But I think this is messier than it is worth (adding still more messiness to the already very messy download_fw()) for such a marginal possible benefit. So, at least for now, I have chosen the much simpler approach of returning an error whenever edge_startup() fails to load an on-disk firmware image, or check_fw_sanity() indicates that it is unusable. Signed-off-by: Peter E. Berger [johan: drop redundant checksum mask ] Signed-off-by: Johan Hovold --- diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index b562665e9fb1..422423671ee4 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -928,6 +928,41 @@ static int ti_cpu_rev(struct edge_ti_manuf_descriptor *desc) return TI_GET_CPU_REVISION(desc->CpuRev_BoardRev); } +static int check_fw_sanity(struct edgeport_serial *serial, + const struct firmware *fw) +{ + u16 length_total; + u8 checksum = 0; + int pos; + struct device *dev = &serial->serial->interface->dev; + struct edgeport_fw_hdr *fw_hdr = (struct edgeport_fw_hdr *)fw->data; + + if (fw->size < sizeof(struct edgeport_fw_hdr)) { + dev_err(dev, "incomplete fw header\n"); + return -EINVAL; + } + + length_total = le16_to_cpu(fw_hdr->length) + + sizeof(struct edgeport_fw_hdr); + + if (fw->size != length_total) { + dev_err(dev, "bad fw size (expected: %u, got: %zu)\n", + length_total, fw->size); + return -EINVAL; + } + + for (pos = sizeof(struct edgeport_fw_hdr); pos < fw->size; ++pos) + checksum += fw->data[pos]; + + if (checksum != fw_hdr->checksum) { + dev_err(dev, "bad fw checksum (expected: 0x%x, got: 0x%x)\n", + fw_hdr->checksum, checksum); + return -EINVAL; + } + + return 0; +} + /** * DownloadTIFirmware - Download run-time operating firmware to the TI5052 * @@ -946,11 +981,8 @@ static int download_fw(struct edgeport_serial *serial, int download_new_ver; struct edgeport_fw_hdr *fw_hdr = (struct edgeport_fw_hdr *)fw->data; - if (fw->size < sizeof(struct edgeport_fw_hdr)) { - dev_err(&serial->serial->interface->dev, - "Incomplete firmware header.\n"); + if (check_fw_sanity(serial, fw)) return -EINVAL; - } /* If on-board version is newer, "fw_version" will be updated below. */ serial->fw_version = (fw_hdr->major_version << 8) +