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 eecd52dc8e98..e02bf2dff845 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; |
