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.