https://bugs.dpdk.org/show_bug.cgi?id=2091

            Bug ID: 2091
           Summary: net/ice: get_module_eeprom() silently drops trailing
                    bytes when read length is not a multiple of 8
           Product: DPDK
           Version: 25.11
          Hardware: x86
                OS: All
            Status: UNCONFIRMED
          Severity: normal
          Priority: Normal
         Component: ethdev
          Assignee: [email protected]
          Reporter: [email protected]
  Target Milestone: ---

ice_get_module_eeprom() reads the transceiver EEPROM in fixed 8-byte blocks via
ice_aq_sff_eeprom(). The hardware read happens unconditionally for every block,
including a trailing partial one, but the copy into the caller's buffer is
gated by an all-or-nothing check:

https://github.com/DPDK/dpdk/blob/a13c1053360ee26bbacca9f883d3f3cb83a0f366/drivers/net/intel/ice/ice_ethdev.c#L6765-L6767

    /* Make sure we have enough room for the new block */
    if ((i + SFF_READ_BLOCK_SIZE) <= info->length)
        memcpy(data + i, value, SFF_READ_BLOCK_SIZE);

When info->length is not an exact multiple of SFF_READ_BLOCK_SIZE (8), the
final loop iteration reads the correct 8 bytes from the module into value[],
but the guard evaluates false (e.g. i=88, length=90: 88+8=96 > 90), so the
memcpy is skipped entirely. Since the destination buffer is memset to 0 at
function entry, the trailing length % 8 bytes are silently returned as zero
instead of the real EEPROM content, with no error indication to the caller.

This is a different (and still-open) case of the same bug class fixed in
31f15787 ("net/ice: fix module EEPROM read", Oct 2022), which only addressed
the complementary edge case where length is an exact multiple of 8 (changing
the guard from < to <=). That fix did not address non-multiple lengths at all.

The equivalent Linux kernel driver (ice_get_module_eeprom() in ice_ethtool.c)
had the same underlying bug and fixed it completely as CVE-2023-53142, by
replacing the all-or-nothing guard with a clamped partial copy:

https://github.com/torvalds/linux/commit/84cba1840e68430325ac133a11be06bfb2f7acd8

    /* Make sure we have enough room for the new block */
    copy_len = min_t(u32, SFF_READ_BLOCK_SIZE, ee->len - i);
    memcpy(data + i, value, copy_len);

The DPDK ice PMD never picked up this more complete fix.

Steps to Reproduce:
1. On a port using the ice PMD with an SFF-8472 transceiver attached, call
rte_eth_dev_get_module_eeprom() with offset=3, length=90 (deliberately not a
multiple of 8, e.g. the common "read compliance codes + vendor fields + DDM
type byte in one request, skip the padding gap before A2h" pattern).
2. Compare the returned buffer's last 2 bytes against an independent read of
the same EEPROM region (e.g. via the kernel ice driver + ethtool -m on the same
port, after temporarily unbinding from vfio-pci).

Expected: all 90 requested bytes match the module's actual EEPROM content.

Actual: the last 2 bytes (length % 8) come back as 0x00, regardless of their
real value. Confirmed concretely: byte 92 (SFF-8472 "Diagnostic Monitoring
Type," containing the DDM-implemented bit) returned 0x00 via this 90-byte read,
but 0x68 (DDM bit correctly set) via an independent ethtool -m read of the same
module. Re-running the same rte_eth_dev_get_module_eeprom() call with length=96
(a clean multiple of 8 that fully covers byte 92 within a complete block)
correctly returns 0x68, directly confirming the root cause.

Suggested fix: replace the all-or-nothing guard with a clamped partial copy,
matching the Linux kernel's fix:

    uint32_t copy_len = RTE_MIN((uint32_t)SFF_READ_BLOCK_SIZE, info->length -
i);
    memcpy(data + i, value, copy_len);

-- 
You are receiving this mail because:
You are the assignee for the bug.

Reply via email to