The SFF decoders assume the buffer is large enough for the module type: SFF-8079 and SFF-8472 do not receive the length at all, and SFF-8636 only uses it to detect the optional page 03h. If a driver reports a length shorter than the type requires, the decoders read past the end of the buffer.
Move the type dispatch into a common internal function which checks the minimal length for each type before decoding: - SFF-8079 and SFF-8436/8636 require at least 256 bytes, - SFF-8472 requires 256 bytes for the base information, and the diagnostics (page A2h) are decoded only if 512 bytes are available. This is a preparation for exposing the decoders to applications, which may pass buffers of arbitrary length. Signed-off-by: Roman Khromenok <[email protected]> --- lib/ethdev/sff_telemetry.c | 37 +++++++++++++++++++++++++++++-------- lib/ethdev/sff_telemetry.h | 8 ++++++++ 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/lib/ethdev/sff_telemetry.c b/lib/ethdev/sff_telemetry.c index 8c8e95affe..72d55322b6 100644 --- a/lib/ethdev/sff_telemetry.c +++ b/lib/ethdev/sff_telemetry.c @@ -99,25 +99,46 @@ sff_port_module_eeprom_parse(uint16_t port_id, struct rte_tel_data *d) return; } - switch (minfo.type) { + ret = sff_decode_module_eeprom(minfo.type, einfo.data, einfo.length, &out); + if (ret == -ENOTSUP) + RTE_ETHDEV_LOG_LINE(NOTICE, "Unsupported module type: %u", minfo.type); + else if (ret != 0) + RTE_ETHDEV_LOG_LINE(ERR, "Port %u module EEPROM is too short: %u bytes", + port_id, einfo.length); + + free(einfo.data); +} + +int +sff_decode_module_eeprom(uint32_t type, const uint8_t *data, uint32_t length, + struct sff_output *d) +{ + switch (type) { /* parsing module EEPROM data base on different module type */ case RTE_ETH_MODULE_SFF_8079: - sff_8079_show_all(einfo.data, &out); + if (length < RTE_ETH_MODULE_SFF_8079_LEN) + return -EINVAL; + sff_8079_show_all(data, d); break; case RTE_ETH_MODULE_SFF_8472: - sff_8079_show_all(einfo.data, &out); - sff_8472_show_all(einfo.data, &out); + if (length < RTE_ETH_MODULE_SFF_8079_LEN) + return -EINVAL; + sff_8079_show_all(data, d); + /* diagnostics are in the second page (A2h) */ + if (length >= RTE_ETH_MODULE_SFF_8472_LEN) + sff_8472_show_all(data, d); break; case RTE_ETH_MODULE_SFF_8436: case RTE_ETH_MODULE_SFF_8636: - sff_8636_show_all(einfo.data, einfo.length, &out); + if (length < RTE_ETH_MODULE_SFF_8636_LEN) + return -EINVAL; + sff_8636_show_all(data, length, d); break; default: - RTE_ETHDEV_LOG_LINE(NOTICE, "Unsupported module type: %u", minfo.type); - break; + return -ENOTSUP; } - free(einfo.data); + return 0; } void diff --git a/lib/ethdev/sff_telemetry.h b/lib/ethdev/sff_telemetry.h index 2a6d79a9c1..1d2c8fd444 100644 --- a/lib/ethdev/sff_telemetry.h +++ b/lib/ethdev/sff_telemetry.h @@ -25,6 +25,14 @@ void sff_8472_show_all(const uint8_t *data, struct sff_output *d); /* SFF-8636 Optics diagnostics */ void sff_8636_show_all(const uint8_t *data, uint32_t eeprom_len, struct sff_output *d); +/* + * Decode module EEPROM of the given type (RTE_ETH_MODULE_SFF_*). + * Returns 0 on success, -EINVAL if the data is too short for the type, + * -ENOTSUP if the type is unknown. + */ +int sff_decode_module_eeprom(uint32_t type, const uint8_t *data, uint32_t length, + struct sff_output *d); + int eth_dev_handle_port_module_eeprom(const char *cmd __rte_unused, const char *params, struct rte_tel_data *d); -- 2.47.3

