diff options
Diffstat (limited to 'drivers/firewire')
-rw-r--r-- | drivers/firewire/core-device.c | 32 |
1 files changed, 22 insertions, 10 deletions
diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c index eecd52dc8e9..e02bf2dff84 100644 --- a/drivers/firewire/core-device.c +++ b/drivers/firewire/core-device.c | |||
@@ -18,6 +18,7 @@ | |||
18 | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 18 | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/bug.h> | ||
21 | #include <linux/ctype.h> | 22 | #include <linux/ctype.h> |
22 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
23 | #include <linux/device.h> | 24 | #include <linux/device.h> |
@@ -580,11 +581,7 @@ static int read_bus_info_block(struct fw_device *device, int generation) | |||
580 | */ | 581 | */ |
581 | key = stack[--sp]; | 582 | key = stack[--sp]; |
582 | i = key & 0xffffff; | 583 | i = key & 0xffffff; |
583 | if (i >= READ_BIB_ROM_SIZE) | 584 | if (WARN_ON(i >= READ_BIB_ROM_SIZE)) |
584 | /* | ||
585 | * The reference points outside the standard | ||
586 | * config rom area, something's fishy. | ||
587 | */ | ||
588 | goto out; | 585 | goto out; |
589 | 586 | ||
590 | /* Read header quadlet for the block to get the length. */ | 587 | /* Read header quadlet for the block to get the length. */ |
@@ -606,14 +603,29 @@ static int read_bus_info_block(struct fw_device *device, int generation) | |||
606 | * block, check the entries as we read them to see if | 603 | * block, check the entries as we read them to see if |
607 | * it references another block, and push it in that case. | 604 | * it references another block, and push it in that case. |
608 | */ | 605 | */ |
609 | while (i < end) { | 606 | for (; i < end; i++) { |
610 | if (read_rom(device, generation, i, &rom[i]) != | 607 | if (read_rom(device, generation, i, &rom[i]) != |
611 | RCODE_COMPLETE) | 608 | RCODE_COMPLETE) |
612 | goto out; | 609 | goto out; |
613 | if ((key >> 30) == 3 && (rom[i] >> 30) > 1 && | 610 | |
614 | sp < READ_BIB_STACK_SIZE) | 611 | if ((key >> 30) != 3 || (rom[i] >> 30) < 2 || |
615 | stack[sp++] = i + rom[i]; | 612 | sp >= READ_BIB_STACK_SIZE) |
616 | i++; | 613 | continue; |
614 | /* | ||
615 | * Offset points outside the ROM. May be a firmware | ||
616 | * bug or an Extended ROM entry (IEEE 1212-2001 clause | ||
617 | * 7.7.18). Simply overwrite this pointer here by a | ||
618 | * fake immediate entry so that later iterators over | ||
619 | * the ROM don't have to check offsets all the time. | ||
620 | */ | ||
621 | if (i + (rom[i] & 0xffffff) >= READ_BIB_ROM_SIZE) { | ||
622 | fw_error("skipped unsupported ROM entry %x at %llx\n", | ||
623 | rom[i], | ||
624 | i * 4 | CSR_REGISTER_BASE | CSR_CONFIG_ROM); | ||
625 | rom[i] = 0; | ||
626 | continue; | ||
627 | } | ||
628 | stack[sp++] = i + rom[i]; | ||
617 | } | 629 | } |
618 | if (length < i) | 630 | if (length < i) |
619 | length = i; | 631 | length = i; |