|
Kmods SIG |
ad5487 |
From 51032e6f17ce990d06123ad7307f258c50d25aa7 Mon Sep 17 00:00:00 2001
|
|
Kmods SIG |
ad5487 |
From: Jacob Keller <jacob.e.keller@intel.com>
|
|
Kmods SIG |
ad5487 |
Date: Wed, 8 Sep 2021 10:52:37 -0700
|
|
Kmods SIG |
ad5487 |
Subject: [Backport 51032e6f17ce] e100: fix buffer overrun in e100_get_regs
|
|
Kmods SIG |
ad5487 |
|
|
Kmods SIG |
ad5487 |
The e100_get_regs function is used to implement a simple register dump
|
|
Kmods SIG |
ad5487 |
for the e100 device. The data is broken into a couple of MAC control
|
|
Kmods SIG |
ad5487 |
registers, and then a series of PHY registers, followed by a memory dump
|
|
Kmods SIG |
ad5487 |
buffer.
|
|
Kmods SIG |
ad5487 |
|
|
Kmods SIG |
ad5487 |
The total length of the register dump is defined as (1 + E100_PHY_REGS)
|
|
Kmods SIG |
ad5487 |
* sizeof(u32) + sizeof(nic->mem->dump_buf).
|
|
Kmods SIG |
ad5487 |
|
|
Kmods SIG |
ad5487 |
The logic for filling in the PHY registers uses a convoluted inverted
|
|
Kmods SIG |
ad5487 |
count for loop which counts from E100_PHY_REGS (0x1C) down to 0, and
|
|
Kmods SIG |
ad5487 |
assigns the slots 1 + E100_PHY_REGS - i. The first loop iteration will
|
|
Kmods SIG |
ad5487 |
fill in [1] and the final loop iteration will fill in [1 + 0x1C]. This
|
|
Kmods SIG |
ad5487 |
is actually one more than the supposed number of PHY registers.
|
|
Kmods SIG |
ad5487 |
|
|
Kmods SIG |
ad5487 |
The memory dump buffer is then filled into the space at
|
|
Kmods SIG |
ad5487 |
[2 + E100_PHY_REGS] which will cause that memcpy to assign 4 bytes past
|
|
Kmods SIG |
ad5487 |
the total size.
|
|
Kmods SIG |
ad5487 |
|
|
Kmods SIG |
ad5487 |
The end result is that we overrun the total buffer size allocated by the
|
|
Kmods SIG |
ad5487 |
kernel, which could lead to a panic or other issues due to memory
|
|
Kmods SIG |
ad5487 |
corruption.
|
|
Kmods SIG |
ad5487 |
|
|
Kmods SIG |
ad5487 |
It is difficult to determine the actual total number of registers
|
|
Kmods SIG |
ad5487 |
here. The only 8255x datasheet I could find indicates there are 28 total
|
|
Kmods SIG |
ad5487 |
MDI registers. However, we're reading 29 here, and reading them in
|
|
Kmods SIG |
ad5487 |
reverse!
|
|
Kmods SIG |
ad5487 |
|
|
Kmods SIG |
ad5487 |
In addition, the ethtool e100 register dump interface appears to read
|
|
Kmods SIG |
ad5487 |
the first PHY register to determine if the device is in MDI or MDIx
|
|
Kmods SIG |
ad5487 |
mode. This doesn't appear to be documented anywhere within the 8255x
|
|
Kmods SIG |
ad5487 |
datasheet. I can only assume it must be in register 28 (the extra
|
|
Kmods SIG |
ad5487 |
register we're reading here).
|
|
Kmods SIG |
ad5487 |
|
|
Kmods SIG |
ad5487 |
Lets not change any of the intended meaning of what we copy here. Just
|
|
Kmods SIG |
ad5487 |
extend the space by 4 bytes to account for the extra register and
|
|
Kmods SIG |
ad5487 |
continue copying the data out in the same order.
|
|
Kmods SIG |
ad5487 |
|
|
Kmods SIG |
ad5487 |
Change the E100_PHY_REGS value to be the correct total (29) so that the
|
|
Kmods SIG |
ad5487 |
total register dump size is calculated properly. Fix the offset for
|
|
Kmods SIG |
ad5487 |
where we copy the dump buffer so that it doesn't overrun the total size.
|
|
Kmods SIG |
ad5487 |
|
|
Kmods SIG |
ad5487 |
Re-write the for loop to use counting up instead of the convoluted
|
|
Kmods SIG |
ad5487 |
down-counting. Correct the mdio_read offset to use the 0-based register
|
|
Kmods SIG |
ad5487 |
offsets, but maintain the bizarre reverse ordering so that we have the
|
|
Kmods SIG |
ad5487 |
ABI expected by applications like ethtool. This requires and additional
|
|
Kmods SIG |
ad5487 |
subtraction of 1. It seems a bit odd but it makes the flow of assignment
|
|
Kmods SIG |
ad5487 |
into the register buffer easier to follow.
|
|
Kmods SIG |
ad5487 |
|
|
Kmods SIG |
ad5487 |
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
|
|
Kmods SIG |
ad5487 |
Reported-by: Felicitas Hetzelt <felicitashetzelt@gmail.com>
|
|
Kmods SIG |
ad5487 |
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
|
|
Kmods SIG |
ad5487 |
Tested-by: Jacob Keller <jacob.e.keller@intel.com>
|
|
Kmods SIG |
ad5487 |
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
|
|
Kmods SIG |
ad5487 |
---
|
|
Kmods SIG |
ad5487 |
src/e100.c | 16 ++++++++++------
|
|
Kmods SIG |
ad5487 |
1 file changed, 10 insertions(+), 6 deletions(-)
|
|
Kmods SIG |
ad5487 |
|
|
Kmods SIG |
ad5487 |
diff --git a/src/e100.c b/src/e100.c
|
|
Kmods SIG |
ad5487 |
index 588a59546d1237e7afb1e6b9bfcce37ecdf03a1c..09ae1939e6db4c7cc32e89708aa871763a543d91 100644
|
|
Kmods SIG |
ad5487 |
--- a/src/e100.c
|
|
Kmods SIG |
ad5487 |
+++ b/src/e100.c
|
|
Kmods SIG |
ad5487 |
@@ -2437,7 +2437,7 @@ static void e100_get_drvinfo(struct net_device *netdev,
|
|
Kmods SIG |
ad5487 |
sizeof(info->bus_info));
|
|
Kmods SIG |
ad5487 |
}
|
|
Kmods SIG |
ad5487 |
|
|
Kmods SIG |
ad5487 |
-#define E100_PHY_REGS 0x1C
|
|
Kmods SIG |
ad5487 |
+#define E100_PHY_REGS 0x1D
|
|
Kmods SIG |
ad5487 |
static int e100_get_regs_len(struct net_device *netdev)
|
|
Kmods SIG |
ad5487 |
{
|
|
Kmods SIG |
ad5487 |
struct nic *nic = netdev_priv(netdev);
|
|
Kmods SIG |
ad5487 |
@@ -2459,14 +2459,18 @@ static void e100_get_regs(struct net_device *netdev,
|
|
Kmods SIG |
ad5487 |
buff[0] = ioread8(&nic->csr->scb.cmd_hi) << 24 |
|
|
Kmods SIG |
ad5487 |
ioread8(&nic->csr->scb.cmd_lo) << 16 |
|
|
Kmods SIG |
ad5487 |
ioread16(&nic->csr->scb.status);
|
|
Kmods SIG |
ad5487 |
- for (i = E100_PHY_REGS; i >= 0; i--)
|
|
Kmods SIG |
ad5487 |
- buff[1 + E100_PHY_REGS - i] =
|
|
Kmods SIG |
ad5487 |
- mdio_read(netdev, nic->mii.phy_id, i);
|
|
Kmods SIG |
ad5487 |
+ for (i = 0; i < E100_PHY_REGS; i++)
|
|
Kmods SIG |
ad5487 |
+ /* Note that we read the registers in reverse order. This
|
|
Kmods SIG |
ad5487 |
+ * ordering is the ABI apparently used by ethtool and other
|
|
Kmods SIG |
ad5487 |
+ * applications.
|
|
Kmods SIG |
ad5487 |
+ */
|
|
Kmods SIG |
ad5487 |
+ buff[1 + i] = mdio_read(netdev, nic->mii.phy_id,
|
|
Kmods SIG |
ad5487 |
+ E100_PHY_REGS - 1 - i);
|
|
Kmods SIG |
ad5487 |
memset(nic->mem->dump_buf, 0, sizeof(nic->mem->dump_buf));
|
|
Kmods SIG |
ad5487 |
e100_exec_cb(nic, NULL, e100_dump);
|
|
Kmods SIG |
ad5487 |
msleep(10);
|
|
Kmods SIG |
ad5487 |
- memcpy(&buff[2 + E100_PHY_REGS], nic->mem->dump_buf,
|
|
Kmods SIG |
ad5487 |
- sizeof(nic->mem->dump_buf));
|
|
Kmods SIG |
ad5487 |
+ memcpy(&buff[1 + E100_PHY_REGS], nic->mem->dump_buf,
|
|
Kmods SIG |
ad5487 |
+ sizeof(nic->mem->dump_buf));
|
|
Kmods SIG |
ad5487 |
}
|
|
Kmods SIG |
ad5487 |
|
|
Kmods SIG |
ad5487 |
static void e100_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
|
|
Kmods SIG |
ad5487 |
--
|
|
Kmods SIG |
ad5487 |
2.31.1
|
|
Kmods SIG |
ad5487 |
|