aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/orinoco
diff options
context:
space:
mode:
authorDavid Kilroy <kilroyd@googlemail.com>2009-02-21 11:52:54 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-02-27 14:53:02 -0500
commit3faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85 (patch)
tree7ae57a23a92f4d38580c953a2a4125072b3261ad /drivers/net/wireless/orinoco
parent7e57811ac5b595bdb53f2aef3bcb2b3d72663fa4 (diff)
orinoco: prevent accessing memory outside the firmware image
Do this by indicating the end of the appropriate regions of memory. Note that MAX_PDA_SIZE should only apply to the PDA block read from flash/EEPROM, and has been erronously applied to the pdr elements. Remove the macro, and use the actual PDA size passed down by the caller. We also fix up some of the types used, marking as much as possible const, and using void* for the end pointers. Signed-off-by: David Kilroy <kilroyd@googlemail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/orinoco')
-rw-r--r--drivers/net/wireless/orinoco/fw.c12
-rw-r--r--drivers/net/wireless/orinoco/hermes_dld.c99
-rw-r--r--drivers/net/wireless/orinoco/hermes_dld.h12
3 files changed, 67 insertions, 56 deletions
diff --git a/drivers/net/wireless/orinoco/fw.c b/drivers/net/wireless/orinoco/fw.c
index 9f163feb9362..e7abb45d6753 100644
--- a/drivers/net/wireless/orinoco/fw.c
+++ b/drivers/net/wireless/orinoco/fw.c
@@ -83,7 +83,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
83 const struct firmware *fw_entry; 83 const struct firmware *fw_entry;
84 const struct orinoco_fw_header *hdr; 84 const struct orinoco_fw_header *hdr;
85 const unsigned char *first_block; 85 const unsigned char *first_block;
86 const unsigned char *end; 86 const void *end;
87 const char *firmware; 87 const char *firmware;
88 const char *fw_err; 88 const char *fw_err;
89 struct net_device *dev = priv->ndev; 89 struct net_device *dev = priv->ndev;
@@ -152,7 +152,8 @@ orinoco_dl_firmware(struct orinoco_private *priv,
152 le16_to_cpu(hdr->headersize) + 152 le16_to_cpu(hdr->headersize) +
153 le32_to_cpu(hdr->pdr_offset)); 153 le32_to_cpu(hdr->pdr_offset));
154 154
155 err = hermes_apply_pda_with_defaults(hw, first_block, pda); 155 err = hermes_apply_pda_with_defaults(hw, first_block, end, pda,
156 &pda[fw->pda_size / sizeof(*pda)]);
156 printk(KERN_DEBUG "%s: Apply PDA returned %d\n", dev->name, err); 157 printk(KERN_DEBUG "%s: Apply PDA returned %d\n", dev->name, err);
157 if (err) 158 if (err)
158 goto abort; 159 goto abort;
@@ -184,7 +185,7 @@ free:
184 */ 185 */
185static int 186static int
186symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, 187symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw,
187 const unsigned char *image, const unsigned char *end, 188 const unsigned char *image, const void *end,
188 int secondary) 189 int secondary)
189{ 190{
190 hermes_t *hw = &priv->hw; 191 hermes_t *hw = &priv->hw;
@@ -225,9 +226,10 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw,
225 226
226 /* Write the PDA to the adapter */ 227 /* Write the PDA to the adapter */
227 if (secondary) { 228 if (secondary) {
228 size_t len = hermes_blocks_length(first_block); 229 size_t len = hermes_blocks_length(first_block, end);
229 ptr = first_block + len; 230 ptr = first_block + len;
230 ret = hermes_apply_pda(hw, ptr, pda); 231 ret = hermes_apply_pda(hw, ptr, end, pda,
232 &pda[fw->pda_size / sizeof(*pda)]);
231 kfree(pda); 233 kfree(pda);
232 if (ret) 234 if (ret)
233 return ret; 235 return ret;
diff --git a/drivers/net/wireless/orinoco/hermes_dld.c b/drivers/net/wireless/orinoco/hermes_dld.c
index 5260ceb5cfec..a9ba195cdada 100644
--- a/drivers/net/wireless/orinoco/hermes_dld.c
+++ b/drivers/net/wireless/orinoco/hermes_dld.c
@@ -71,18 +71,6 @@
71#define BLOCK_END 0xFFFFFFFF /* Last image block */ 71#define BLOCK_END 0xFFFFFFFF /* Last image block */
72#define TEXT_END 0x1A /* End of text header */ 72#define TEXT_END 0x1A /* End of text header */
73 73
74/*
75 * PDA == Production Data Area
76 *
77 * In principle, the max. size of the PDA is is 4096 words. Currently,
78 * however, only about 500 bytes of this area are used.
79 *
80 * Some USB implementations can't handle sizes in excess of 1016. Note
81 * that PDA is not actually used in those USB environments, but may be
82 * retrieved by common code.
83 */
84#define MAX_PDA_SIZE 1000
85
86/* Limit the amout we try to download in a single shot. 74/* Limit the amout we try to download in a single shot.
87 * Size is in bytes. 75 * Size is in bytes.
88 */ 76 */
@@ -218,13 +206,14 @@ hermes_aux_control(hermes_t *hw, int enabled)
218 * Scan PDR for the record with the specified RECORD_ID. 206 * Scan PDR for the record with the specified RECORD_ID.
219 * If it's not found, return NULL. 207 * If it's not found, return NULL.
220 */ 208 */
221static struct pdr * 209static const struct pdr *
222hermes_find_pdr(struct pdr *first_pdr, u32 record_id) 210hermes_find_pdr(const struct pdr *first_pdr, u32 record_id, const void *end)
223{ 211{
224 struct pdr *pdr = first_pdr; 212 const struct pdr *pdr = first_pdr;
225 void *end = (void *)first_pdr + MAX_PDA_SIZE;
226 213
227 while (((void *)pdr < end) && 214 end -= sizeof(struct pdr);
215
216 while (((void *) pdr <= end) &&
228 (pdr_id(pdr) != PDI_END)) { 217 (pdr_id(pdr) != PDI_END)) {
229 /* 218 /*
230 * PDR area is currently not terminated by PDI_END. 219 * PDR area is currently not terminated by PDI_END.
@@ -244,12 +233,15 @@ hermes_find_pdr(struct pdr *first_pdr, u32 record_id)
244} 233}
245 234
246/* Scan production data items for a particular entry */ 235/* Scan production data items for a particular entry */
247static struct pdi * 236static const struct pdi *
248hermes_find_pdi(struct pdi *first_pdi, u32 record_id) 237hermes_find_pdi(const struct pdi *first_pdi, u32 record_id, const void *end)
249{ 238{
250 struct pdi *pdi = first_pdi; 239 const struct pdi *pdi = first_pdi;
240
241 end -= sizeof(struct pdi);
251 242
252 while (pdi_id(pdi) != PDI_END) { 243 while (((void *) pdi <= end) &&
244 (pdi_id(pdi) != PDI_END)) {
253 245
254 /* If the record ID matches, we are done */ 246 /* If the record ID matches, we are done */
255 if (pdi_id(pdi) == record_id) 247 if (pdi_id(pdi) == record_id)
@@ -262,12 +254,13 @@ hermes_find_pdi(struct pdi *first_pdi, u32 record_id)
262 254
263/* Process one Plug Data Item - find corresponding PDR and plug it */ 255/* Process one Plug Data Item - find corresponding PDR and plug it */
264static int 256static int
265hermes_plug_pdi(hermes_t *hw, struct pdr *first_pdr, const struct pdi *pdi) 257hermes_plug_pdi(hermes_t *hw, const struct pdr *first_pdr,
258 const struct pdi *pdi, const void *pdr_end)
266{ 259{
267 struct pdr *pdr; 260 const struct pdr *pdr;
268 261
269 /* Find the PDR corresponding to this PDI */ 262 /* Find the PDR corresponding to this PDI */
270 pdr = hermes_find_pdr(first_pdr, pdi_id(pdi)); 263 pdr = hermes_find_pdr(first_pdr, pdi_id(pdi), pdr_end);
271 264
272 /* No match is found, safe to ignore */ 265 /* No match is found, safe to ignore */
273 if (!pdr) 266 if (!pdr)
@@ -345,18 +338,22 @@ int hermes_read_pda(hermes_t *hw,
345 */ 338 */
346int hermes_apply_pda(hermes_t *hw, 339int hermes_apply_pda(hermes_t *hw,
347 const char *first_pdr, 340 const char *first_pdr,
348 const __le16 *pda) 341 const void *pdr_end,
342 const __le16 *pda,
343 const void *pda_end)
349{ 344{
350 int ret; 345 int ret;
351 const struct pdi *pdi; 346 const struct pdi *pdi;
352 struct pdr *pdr; 347 const struct pdr *pdr;
353 348
354 pdr = (struct pdr *) first_pdr; 349 pdr = (const struct pdr *) first_pdr;
350 pda_end -= sizeof(struct pdi);
355 351
356 /* Go through every PDI and plug them into the adapter */ 352 /* Go through every PDI and plug them into the adapter */
357 pdi = (const struct pdi *) (pda + 2); 353 pdi = (const struct pdi *) (pda + 2);
358 while (pdi_id(pdi) != PDI_END) { 354 while (((void *) pdi <= pda_end) &&
359 ret = hermes_plug_pdi(hw, pdr, pdi); 355 (pdi_id(pdi) != PDI_END)) {
356 ret = hermes_plug_pdi(hw, pdr, pdi, pdr_end);
360 if (ret) 357 if (ret)
361 return ret; 358 return ret;
362 359
@@ -370,15 +367,18 @@ int hermes_apply_pda(hermes_t *hw,
370 * including the header data. 367 * including the header data.
371 */ 368 */
372size_t 369size_t
373hermes_blocks_length(const char *first_block) 370hermes_blocks_length(const char *first_block, const void *end)
374{ 371{
375 const struct dblock *blk = (const struct dblock *) first_block; 372 const struct dblock *blk = (const struct dblock *) first_block;
376 int total_len = 0; 373 int total_len = 0;
377 int len; 374 int len;
378 375
376 end -= sizeof(*blk);
377
379 /* Skip all blocks to locate Plug Data References 378 /* Skip all blocks to locate Plug Data References
380 * (Spectrum CS) */ 379 * (Spectrum CS) */
381 while (dblock_addr(blk) != BLOCK_END) { 380 while (((void *) blk <= end) &&
381 (dblock_addr(blk) != BLOCK_END)) {
382 len = dblock_len(blk); 382 len = dblock_len(blk);
383 total_len += sizeof(*blk) + len; 383 total_len += sizeof(*blk) + len;
384 blk = (struct dblock *) &blk->data[len]; 384 blk = (struct dblock *) &blk->data[len];
@@ -476,7 +476,7 @@ int hermesi_program_end(hermes_t *hw)
476} 476}
477 477
478/* Program the data blocks */ 478/* Program the data blocks */
479int hermes_program(hermes_t *hw, const char *first_block, const char *end) 479int hermes_program(hermes_t *hw, const char *first_block, const void *end)
480{ 480{
481 const struct dblock *blk; 481 const struct dblock *blk;
482 u32 blkaddr; 482 u32 blkaddr;
@@ -488,14 +488,14 @@ int hermes_program(hermes_t *hw, const char *first_block, const char *end)
488 488
489 blk = (const struct dblock *) first_block; 489 blk = (const struct dblock *) first_block;
490 490
491 if ((const char *) blk > (end - sizeof(*blk))) 491 if ((void *) blk > (end - sizeof(*blk)))
492 return -EIO; 492 return -EIO;
493 493
494 blkaddr = dblock_addr(blk); 494 blkaddr = dblock_addr(blk);
495 blklen = dblock_len(blk); 495 blklen = dblock_len(blk);
496 496
497 while ((blkaddr != BLOCK_END) && 497 while ((blkaddr != BLOCK_END) &&
498 (((const char *) blk + blklen) <= end)) { 498 (((void *) blk + blklen) <= end)) {
499 printk(KERN_DEBUG PFX 499 printk(KERN_DEBUG PFX
500 "Programming block of length %d to address 0x%08x\n", 500 "Programming block of length %d to address 0x%08x\n",
501 blklen, blkaddr); 501 blklen, blkaddr);
@@ -527,7 +527,7 @@ int hermes_program(hermes_t *hw, const char *first_block, const char *end)
527#endif 527#endif
528 blk = (const struct dblock *) &blk->data[blklen]; 528 blk = (const struct dblock *) &blk->data[blklen];
529 529
530 if ((const char *) blk > (end - sizeof(*blk))) 530 if ((void *) blk > (end - sizeof(*blk)))
531 return -EIO; 531 return -EIO;
532 532
533 blkaddr = dblock_addr(blk); 533 blkaddr = dblock_addr(blk);
@@ -545,9 +545,9 @@ static const struct { \
545 __le16 id; \ 545 __le16 id; \
546 u8 val[length]; \ 546 u8 val[length]; \
547} __attribute__ ((packed)) default_pdr_data_##pid = { \ 547} __attribute__ ((packed)) default_pdr_data_##pid = { \
548 cpu_to_le16((sizeof(default_pdr_data_##pid)/ \ 548 cpu_to_le16((sizeof(default_pdr_data_##pid)/ \
549 sizeof(__le16)) - 1), \ 549 sizeof(__le16)) - 1), \
550 cpu_to_le16(pid), \ 550 cpu_to_le16(pid), \
551 data \ 551 data \
552} 552}
553 553
@@ -616,17 +616,20 @@ DEFINE_DEFAULT_PDR(0x0161, 256,
616 */ 616 */
617int hermes_apply_pda_with_defaults(hermes_t *hw, 617int hermes_apply_pda_with_defaults(hermes_t *hw,
618 const char *first_pdr, 618 const char *first_pdr,
619 const __le16 *pda) 619 const void *pdr_end,
620 const __le16 *pda,
621 const void *pda_end)
620{ 622{
621 const struct pdr *pdr = (const struct pdr *) first_pdr; 623 const struct pdr *pdr = (const struct pdr *) first_pdr;
622 struct pdi *first_pdi = (struct pdi *) &pda[2]; 624 const struct pdi *first_pdi = (const struct pdi *) &pda[2];
623 struct pdi *pdi; 625 const struct pdi *pdi;
624 struct pdi *default_pdi = NULL; 626 const struct pdi *default_pdi = NULL;
625 struct pdi *outdoor_pdi; 627 const struct pdi *outdoor_pdi;
626 void *end = (void *)first_pdr + MAX_PDA_SIZE;
627 int record_id; 628 int record_id;
628 629
629 while (((void *)pdr < end) && 630 pdr_end -= sizeof(struct pdr);
631
632 while (((void *) pdr <= pdr_end) &&
630 (pdr_id(pdr) != PDI_END)) { 633 (pdr_id(pdr) != PDI_END)) {
631 /* 634 /*
632 * For spectrum_cs firmwares, 635 * For spectrum_cs firmwares,
@@ -638,7 +641,7 @@ int hermes_apply_pda_with_defaults(hermes_t *hw,
638 break; 641 break;
639 record_id = pdr_id(pdr); 642 record_id = pdr_id(pdr);
640 643
641 pdi = hermes_find_pdi(first_pdi, record_id); 644 pdi = hermes_find_pdi(first_pdi, record_id, pda_end);
642 if (pdi) 645 if (pdi)
643 printk(KERN_DEBUG PFX "Found record 0x%04x at %p\n", 646 printk(KERN_DEBUG PFX "Found record 0x%04x at %p\n",
644 record_id, pdi); 647 record_id, pdi);
@@ -646,7 +649,8 @@ int hermes_apply_pda_with_defaults(hermes_t *hw,
646 switch (record_id) { 649 switch (record_id) {
647 case 0x110: /* Modem REFDAC values */ 650 case 0x110: /* Modem REFDAC values */
648 case 0x120: /* Modem VGDAC values */ 651 case 0x120: /* Modem VGDAC values */
649 outdoor_pdi = hermes_find_pdi(first_pdi, record_id + 1); 652 outdoor_pdi = hermes_find_pdi(first_pdi, record_id + 1,
653 pda_end);
650 default_pdi = NULL; 654 default_pdi = NULL;
651 if (outdoor_pdi) { 655 if (outdoor_pdi) {
652 pdi = outdoor_pdi; 656 pdi = outdoor_pdi;
@@ -687,7 +691,8 @@ int hermes_apply_pda_with_defaults(hermes_t *hw,
687 691
688 if (pdi) { 692 if (pdi) {
689 /* Lengths of the data in PDI and PDR must match */ 693 /* Lengths of the data in PDI and PDR must match */
690 if (pdi_len(pdi) == pdr_len(pdr)) { 694 if ((pdi_len(pdi) == pdr_len(pdr)) &&
695 ((void *) pdi->data + pdi_len(pdi) < pda_end)) {
691 /* do the actual plugging */ 696 /* do the actual plugging */
692 hermes_aux_setaddr(hw, pdr_addr(pdr)); 697 hermes_aux_setaddr(hw, pdr_addr(pdr));
693 hermes_write_bytes(hw, HERMES_AUXDATA, 698 hermes_write_bytes(hw, HERMES_AUXDATA,
diff --git a/drivers/net/wireless/orinoco/hermes_dld.h b/drivers/net/wireless/orinoco/hermes_dld.h
index 6fcb26277999..583a5bcf9175 100644
--- a/drivers/net/wireless/orinoco/hermes_dld.h
+++ b/drivers/net/wireless/orinoco/hermes_dld.h
@@ -29,7 +29,7 @@
29 29
30int hermesi_program_init(hermes_t *hw, u32 offset); 30int hermesi_program_init(hermes_t *hw, u32 offset);
31int hermesi_program_end(hermes_t *hw); 31int hermesi_program_end(hermes_t *hw);
32int hermes_program(hermes_t *hw, const char *first_block, const char *end); 32int hermes_program(hermes_t *hw, const char *first_block, const void *end);
33 33
34int hermes_read_pda(hermes_t *hw, 34int hermes_read_pda(hermes_t *hw,
35 __le16 *pda, 35 __le16 *pda,
@@ -38,11 +38,15 @@ int hermes_read_pda(hermes_t *hw,
38 int use_eeprom); 38 int use_eeprom);
39int hermes_apply_pda(hermes_t *hw, 39int hermes_apply_pda(hermes_t *hw,
40 const char *first_pdr, 40 const char *first_pdr,
41 const __le16 *pda); 41 const void *pdr_end,
42 const __le16 *pda,
43 const void *pda_end);
42int hermes_apply_pda_with_defaults(hermes_t *hw, 44int hermes_apply_pda_with_defaults(hermes_t *hw,
43 const char *first_pdr, 45 const char *first_pdr,
44 const __le16 *pda); 46 const void *pdr_end,
47 const __le16 *pda,
48 const void *pda_end);
45 49
46size_t hermes_blocks_length(const char *first_block); 50size_t hermes_blocks_length(const char *first_block, const void *end);
47 51
48#endif /* _HERMES_DLD_H */ 52#endif /* _HERMES_DLD_H */