From 47de87eb23c48315be208dad9995382208fad25f Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Fri, 2 May 2025 13:44:29 -0400 Subject: [PATCH] realtek: harden MDIO driver At least since 2022 there is a major bug in the MDIO driver that produces out-of-bound reads and erratic behaviour during initialization. - mdiobus_scan_bus_c22() scans the bus for 64 devices (PHY_MAX_ADDR) - private bus structure only supports 57 entry arrays (MAX_PORTS) All the bus/reader writer functions accept calls with addr>=57 and will silently read beyond their limits. This can lead to ghost SERDES like https://github.com/openwrt/openwrt/issues/18665#issuecomment-2846053813 Add proper boundary checks and end the functions with -ENODEV that is the only accepted error code from the bus scan function. Fixes: 0536c582e673aa292 ("realtek: Fix RTL931X Ethernet driver") etc ... Signed-off-by: Markus Stockhausen Link: https://github.com/openwrt/openwrt/pull/18402 Signed-off-by: Stijn Tintel --- .../drivers/net/ethernet/rtl838x_eth.c | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/target/linux/realtek/files-6.6/drivers/net/ethernet/rtl838x_eth.c b/target/linux/realtek/files-6.6/drivers/net/ethernet/rtl838x_eth.c index 269d8bed569..fe4e8670658 100644 --- a/target/linux/realtek/files-6.6/drivers/net/ethernet/rtl838x_eth.c +++ b/target/linux/realtek/files-6.6/drivers/net/ethernet/rtl838x_eth.c @@ -1819,6 +1819,9 @@ static int rtmdio_read_c45(struct mii_bus *bus, int addr, int devnum, int regnum if (bus_priv->extaddr >= 0) addr = bus_priv->extaddr; + + if (addr >= RTMDIO_MAX_PORT) + return -ENODEV; err = (*bus_priv->read_mmd_phy)(addr, devnum, regnum, &val); pr_debug("rd_MMD(adr=%d, dev=%d, reg=%d) = %d, err = %d\n", @@ -1834,6 +1837,9 @@ static int rtmdio_83xx_read(struct mii_bus *bus, int addr, int regnum) if (bus_priv->extaddr >= 0) addr = bus_priv->extaddr; + + if (addr >= RTMDIO_MAX_PORT) + return -ENODEV; if (addr >= 24 && addr <= 27 && eth_priv->id == 0x8380) return rtl838x_read_sds_phy(addr, regnum); @@ -1860,6 +1866,9 @@ static int rtmdio_93xx_read(struct mii_bus *bus, int addr, int regnum) if (bus_priv->extaddr >= 0) addr = bus_priv->extaddr; + if (addr >= RTMDIO_MAX_PORT) + return -ENODEV; + if (regnum == RTMDIO_PAGE_SELECT && bus_priv->page[addr] != bus_priv->rawpage) return bus_priv->page[addr]; @@ -1887,6 +1896,9 @@ static int rtmdio_write_c45(struct mii_bus *bus, int addr, int devnum, int regnu if (bus_priv->extaddr >= 0) addr = bus_priv->extaddr; + if (addr >= RTMDIO_MAX_PORT) + return -ENODEV; + err = (*bus_priv->write_mmd_phy)(addr, devnum, regnum, val); pr_debug("wr_MMD(adr=%d, dev=%d, reg=%d, val=%d) err = %d\n", addr, devnum, regnum, val, err); @@ -1906,6 +1918,10 @@ static int rtmdio_83xx_write(struct mii_bus *bus, int addr, int regnum, u16 val) if (bus_priv->extaddr >= 0) addr = bus_priv->extaddr; + + if (addr >= RTMDIO_MAX_PORT) + return -ENODEV; + page = bus_priv->page[addr]; if (addr >= 24 && addr <= 27 && eth_priv->id == 0x8380) { @@ -1946,6 +1962,10 @@ static int rtmdio_93xx_write(struct mii_bus *bus, int addr, int regnum, u16 val) if (bus_priv->extaddr >= 0) addr = bus_priv->extaddr; + + if (addr >= RTMDIO_MAX_PORT) + return -ENODEV; + page = bus_priv->page[addr]; if (regnum == RTMDIO_PAGE_SELECT)