diff options
author | Yuval Mintz <yuvalmin@broadcom.com> | 2013-10-20 10:51:27 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-10-21 18:31:35 -0400 |
commit | 1a6974b2c78755ae55d7be738866eb8d57c3ed45 (patch) | |
tree | 5835074f923433306647acbca03f0a7087d288e4 | |
parent | b1239723f0564778d993d51d18afdfda01bdaca3 (diff) |
bnx2x: Prevent an illegal pointer dereference during panic
During a panic, the driver tries to print the Management FW buffer of recent
commands. To do so, the driver reads the address of that buffer from a known
address. If the buffer is unavailable (e.g., PCI reads don't work, MCP is
failing, etc.), the driver will try to access the address it has read, possibly
causing a kernel panic.
This check 'sanitizes' the access, validating the read value is indeed a valid
address inside the management FW's buffers.
The patch also removes a read outside the scope of the buffer, which resulted
in some unrelated chraracters appearing in the log.
Signed-off-by: Yuval Mintz <yuvalmin@broadcom.com>
Signed-off-by: Dmitry Kravkov <dmitry@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 32 |
2 files changed, 29 insertions, 7 deletions
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index 97b3d32a98bd..d21742ca2fd2 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | |||
@@ -2498,4 +2498,8 @@ enum bnx2x_pci_bus_speed { | |||
2498 | }; | 2498 | }; |
2499 | 2499 | ||
2500 | void bnx2x_set_local_cmng(struct bnx2x *bp); | 2500 | void bnx2x_set_local_cmng(struct bnx2x *bp); |
2501 | |||
2502 | #define MCPR_SCRATCH_BASE(bp) \ | ||
2503 | (CHIP_IS_E1x(bp) ? MCP_REG_MCPR_SCRATCH : MCP_A_REG_MCPR_SCRATCH) | ||
2504 | |||
2501 | #endif /* bnx2x.h */ | 2505 | #endif /* bnx2x.h */ |
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 60f9e68ea46c..c2609c41340e 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | |||
@@ -751,6 +751,10 @@ static int bnx2x_mc_assert(struct bnx2x *bp) | |||
751 | return rc; | 751 | return rc; |
752 | } | 752 | } |
753 | 753 | ||
754 | #define MCPR_TRACE_BUFFER_SIZE (0x800) | ||
755 | #define SCRATCH_BUFFER_SIZE(bp) \ | ||
756 | (CHIP_IS_E1(bp) ? 0x10000 : (CHIP_IS_E1H(bp) ? 0x20000 : 0x28000)) | ||
757 | |||
754 | void bnx2x_fw_dump_lvl(struct bnx2x *bp, const char *lvl) | 758 | void bnx2x_fw_dump_lvl(struct bnx2x *bp, const char *lvl) |
755 | { | 759 | { |
756 | u32 addr, val; | 760 | u32 addr, val; |
@@ -775,7 +779,17 @@ void bnx2x_fw_dump_lvl(struct bnx2x *bp, const char *lvl) | |||
775 | trace_shmem_base = bp->common.shmem_base; | 779 | trace_shmem_base = bp->common.shmem_base; |
776 | else | 780 | else |
777 | trace_shmem_base = SHMEM2_RD(bp, other_shmem_base_addr); | 781 | trace_shmem_base = SHMEM2_RD(bp, other_shmem_base_addr); |
778 | addr = trace_shmem_base - 0x800; | 782 | |
783 | /* sanity */ | ||
784 | if (trace_shmem_base < MCPR_SCRATCH_BASE(bp) + MCPR_TRACE_BUFFER_SIZE || | ||
785 | trace_shmem_base >= MCPR_SCRATCH_BASE(bp) + | ||
786 | SCRATCH_BUFFER_SIZE(bp)) { | ||
787 | BNX2X_ERR("Unable to dump trace buffer (mark %x)\n", | ||
788 | trace_shmem_base); | ||
789 | return; | ||
790 | } | ||
791 | |||
792 | addr = trace_shmem_base - MCPR_TRACE_BUFFER_SIZE; | ||
779 | 793 | ||
780 | /* validate TRCB signature */ | 794 | /* validate TRCB signature */ |
781 | mark = REG_RD(bp, addr); | 795 | mark = REG_RD(bp, addr); |
@@ -787,14 +801,17 @@ void bnx2x_fw_dump_lvl(struct bnx2x *bp, const char *lvl) | |||
787 | /* read cyclic buffer pointer */ | 801 | /* read cyclic buffer pointer */ |
788 | addr += 4; | 802 | addr += 4; |
789 | mark = REG_RD(bp, addr); | 803 | mark = REG_RD(bp, addr); |
790 | mark = (CHIP_IS_E1x(bp) ? MCP_REG_MCPR_SCRATCH : MCP_A_REG_MCPR_SCRATCH) | 804 | mark = MCPR_SCRATCH_BASE(bp) + ((mark + 0x3) & ~0x3) - 0x08000000; |
791 | + ((mark + 0x3) & ~0x3) - 0x08000000; | 805 | if (mark >= trace_shmem_base || mark < addr + 4) { |
806 | BNX2X_ERR("Mark doesn't fall inside Trace Buffer\n"); | ||
807 | return; | ||
808 | } | ||
792 | printk("%s" "begin fw dump (mark 0x%x)\n", lvl, mark); | 809 | printk("%s" "begin fw dump (mark 0x%x)\n", lvl, mark); |
793 | 810 | ||
794 | printk("%s", lvl); | 811 | printk("%s", lvl); |
795 | 812 | ||
796 | /* dump buffer after the mark */ | 813 | /* dump buffer after the mark */ |
797 | for (offset = mark; offset <= trace_shmem_base; offset += 0x8*4) { | 814 | for (offset = mark; offset < trace_shmem_base; offset += 0x8*4) { |
798 | for (word = 0; word < 8; word++) | 815 | for (word = 0; word < 8; word++) |
799 | data[word] = htonl(REG_RD(bp, offset + 4*word)); | 816 | data[word] = htonl(REG_RD(bp, offset + 4*word)); |
800 | data[8] = 0x0; | 817 | data[8] = 0x0; |
@@ -11685,9 +11702,6 @@ static int bnx2x_init_bp(struct bnx2x *bp) | |||
11685 | static int bnx2x_open(struct net_device *dev) | 11702 | static int bnx2x_open(struct net_device *dev) |
11686 | { | 11703 | { |
11687 | struct bnx2x *bp = netdev_priv(dev); | 11704 | struct bnx2x *bp = netdev_priv(dev); |
11688 | bool global = false; | ||
11689 | int other_engine = BP_PATH(bp) ? 0 : 1; | ||
11690 | bool other_load_status, load_status; | ||
11691 | int rc; | 11705 | int rc; |
11692 | 11706 | ||
11693 | bp->stats_init = true; | 11707 | bp->stats_init = true; |
@@ -11703,6 +11717,10 @@ static int bnx2x_open(struct net_device *dev) | |||
11703 | * Parity recovery is only relevant for PF driver. | 11717 | * Parity recovery is only relevant for PF driver. |
11704 | */ | 11718 | */ |
11705 | if (IS_PF(bp)) { | 11719 | if (IS_PF(bp)) { |
11720 | int other_engine = BP_PATH(bp) ? 0 : 1; | ||
11721 | bool other_load_status, load_status; | ||
11722 | bool global = false; | ||
11723 | |||
11706 | other_load_status = bnx2x_get_load_status(bp, other_engine); | 11724 | other_load_status = bnx2x_get_load_status(bp, other_engine); |
11707 | load_status = bnx2x_get_load_status(bp, BP_PATH(bp)); | 11725 | load_status = bnx2x_get_load_status(bp, BP_PATH(bp)); |
11708 | if (!bnx2x_reset_is_done(bp, BP_PATH(bp)) || | 11726 | if (!bnx2x_reset_is_done(bp, BP_PATH(bp)) || |