net/ice: get_module_eeprom() silently drops trailing bytes when read length is not a multiple of 8
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:
/* 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);Signature · 2 lines
You are receiving this mail because: You are the assignee for the bug.