orinoco: validate firmware header
authorDavid Kilroy <kilroyd@googlemail.com>
Sat, 21 Feb 2009 16:52:53 +0000 (16:52 +0000)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 27 Feb 2009 19:53:02 +0000 (14:53 -0500)
Check the Agere firmware headers for validity before attempting to
download it.

Signed-off-by: David Kilroy <kilroyd@googlemail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/orinoco/fw.c

index 7d2292d6ce09fa1a894488fdbabc943beaa541e1..9f163feb9362d3d06dda1d3c0a6c7686c47fb995 100644 (file)
@@ -43,6 +43,33 @@ struct orinoco_fw_header {
        char signature[0];      /* FW signature length headersize-20 */
 } __attribute__ ((packed));
 
+/* Check the range of various header entries. Return a pointer to a
+ * description of the problem, or NULL if everything checks out. */
+static const char *validate_fw(const struct orinoco_fw_header *hdr, size_t len)
+{
+       u16 hdrsize;
+
+       if (len < sizeof(*hdr))
+               return "image too small";
+       if (memcmp(hdr->hdr_vers, "HFW", 3) != 0)
+               return "format not recognised";
+
+       hdrsize = le16_to_cpu(hdr->headersize);
+       if (hdrsize > len)
+               return "bad headersize";
+       if ((hdrsize + le32_to_cpu(hdr->block_offset)) > len)
+               return "bad block offset";
+       if ((hdrsize + le32_to_cpu(hdr->pdr_offset)) > len)
+               return "bad PDR offset";
+       if ((hdrsize + le32_to_cpu(hdr->pri_offset)) > len)
+               return "bad PRI offset";
+       if ((hdrsize + le32_to_cpu(hdr->compat_offset)) > len)
+               return "bad compat offset";
+
+       /* TODO: consider adding a checksum or CRC to the firmware format */
+       return NULL;
+}
+
 /* Download either STA or AP firmware into the card. */
 static int
 orinoco_dl_firmware(struct orinoco_private *priv,
@@ -58,6 +85,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
        const unsigned char *first_block;
        const unsigned char *end;
        const char *firmware;
+       const char *fw_err;
        struct net_device *dev = priv->ndev;
        int err = 0;
 
@@ -93,6 +121,15 @@ orinoco_dl_firmware(struct orinoco_private *priv,
 
        hdr = (const struct orinoco_fw_header *) fw_entry->data;
 
+       fw_err = validate_fw(hdr, fw_entry->size);
+       if (fw_err) {
+               printk(KERN_WARNING "%s: Invalid firmware image detected (%s). "
+                      "Aborting download\n",
+                      dev->name, fw_err);
+               err = -EINVAL;
+               goto abort;
+       }
+
        /* Enable aux port to allow programming */
        err = hermesi_program_init(hw, le32_to_cpu(hdr->entry_point));
        printk(KERN_DEBUG "%s: Program init returned %d\n", dev->name, err);