From: Paul Greenwalt <[email protected]>

Prevent out-of-bounds MMIO accesses triggered through user-controlled
register offsets.  IXGBE_HFDR (0x15FE8) is the highest valid MMIO
register in the ixgbe register map; any offset beyond it would address
unmapped memory.

Add a defense-in-depth check at two levels:

1. ixgbe_read_reg() -- the noinline register read accessor.  A
   WARN_ON_ONCE() guard here catches any future code path (including
   ioctl extensions) that might inadvertently pass an out-of-range
   offset without relying on higher layers to catch it first.
   ixgbe_write_reg() is a static inline called from the TX/RX hot path;
   adding WARN_ON_ONCE there would inline the check at every call site,
   so only the read path gets this guard.

2. ixgbe_dbg_reg_ops_write() -- the debugfs 'reg_ops' interface is the
   only current path where a raw, user-supplied offset enters the driver.
   Gating it before invoking the register accessors provides a clean,
   user-visible failure (silent ignore with no kernel splat) for
   deliberately malformed debugfs writes.

Add a reg <= IXGBE_HFDR guard to both the read and write paths in
ixgbe_dbg_reg_ops_write(), and a WARN_ON_ONCE + early-return guard to
ixgbe_read_reg().

Signed-off-by: Paul Greenwalt <[email protected]>
Signed-off-by: Aleksandr Loktionov <[email protected]>
---
 drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c | 6 ++++--
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c    | 2 ++
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c 
b/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c
index 5b1cf49d..a6a19c0 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c
@@ -86,7 +86,8 @@ static ssize_t ixgbe_dbg_reg_ops_write(struct file *filp,
                u32 reg, value;
                int cnt;
                cnt = sscanf(&ixgbe_dbg_reg_ops_buf[5], "%x %x", &reg, &value);
-               if (cnt == 2) {
+               /* check format and bounds check register access */
+               if (cnt == 2 && reg <= IXGBE_HFDR) {
                        IXGBE_WRITE_REG(&adapter->hw, reg, value);
                        value = IXGBE_READ_REG(&adapter->hw, reg);
                        e_dev_info("write: 0x%08x = 0x%08x\n", reg, value);
@@ -97,7 +98,8 @@ static ssize_t ixgbe_dbg_reg_ops_write(struct file *filp,
                u32 reg, value;
                int cnt;
                cnt = sscanf(&ixgbe_dbg_reg_ops_buf[4], "%x", &reg);
-               if (cnt == 1) {
+               /* check format and bounds check register access */
+               if (cnt == 1 && reg <= IXGBE_HFDR) {
                        value = IXGBE_READ_REG(&adapter->hw, reg);
                        e_dev_info("read 0x%08x = 0x%08x\n", reg, value);
                } else {

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c 
b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 210c7b9..4a1f3c2 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -354,4 +354,6 @@ u32 ixgbe_read_reg(struct ixgbe_hw *hw, u32 reg)
        if (ixgbe_removed(reg_addr))
                return IXGBE_FAILED_READ_REG;
+       if (WARN_ON_ONCE(reg > IXGBE_HFDR))
+               return IXGBE_FAILED_READ_REG;
        if (unlikely(hw->phy.nw_mng_if_sel &
                     IXGBE_NW_MNG_IF_SEL_SGMII_ENABLE)) {
-- 
2.52.0

Reply via email to