Re: [RFC net-next v2 4/6] ptp: ocp: Validate EEPROM board IDs

Vadim Fedorenko <[email protected]> Tue, 4 Aug 2026 14:55:17 +0100
Newsgroups org.kernel.vger.linux-leds,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-hardening,org.kernel.vger.linux-i2c,org.kernel.vger.linux-kernel,org.kernel.vger.netdev,org.kernel.vger.stable
Message-ID <[email protected]>
On 03/08/2026 21:50, Ahmad Byagowi wrote:
> The EEPROM board ID is a fixed 13-byte field. It is stored without room
> for a terminator and passed to devlink as a C string. An erased EEPROM
> therefore exposes 0xff bytes and can make devlink read beyond the field
> while formatting board.id.
> 
> Reserve a trailing byte, classify erased and malformed contents, and
> publish board.id only when the field contains printable text with valid
> padding. Continue reporting the serial number when the board ID is
> absent.
> 
> Fixes: 0cfcdd1ebcfe1a9b262f6ad8419580720dc843c4 ("ptp: ocp: add nvmem interface for accessing eeprom")

use short format of hash to provide commit to fix:

Fixes: 0cfcdd1ebcfe ("ptp: ocp: add nvmem interface for accessing eeprom")

And as this is a fix, it has to go to net rather than net-next

> Cc: [email protected]
> Signed-off-by: Ahmad Byagowi <[email protected]>
> ---
>   drivers/ptp/ptp_ocp.c | 69 +++++++++++++++++++++++++++++++++++++++++--
>   1 file changed, 66 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
> index 35e911f1a..cec936bd1 100644
> --- a/drivers/ptp/ptp_ocp.c
> +++ b/drivers/ptp/ptp_ocp.c
> @@ -347,6 +347,13 @@ struct ptp_ocp_serial_port {
>   #define OCP_SIGNAL_NUM			4
>   #define OCP_FREQ_NUM			4
>   
> +enum ptp_ocp_board_id_state {
> +	OCP_BOARD_ID_UNREAD,
> +	OCP_BOARD_ID_VALID,
> +	OCP_BOARD_ID_ERASED,
> +	OCP_BOARD_ID_INVALID,
> +};
> +
>   enum {
>   	PORT_GNSS,
>   	PORT_GNSS2,
> @@ -401,8 +408,9 @@ struct ptp_ocp {
>   	bool			fw_loader;
>   	u8			fw_tag;
>   	u16			fw_version;
> -	u8			board_id[OCP_BOARD_ID_LEN];
> +	char			board_id[OCP_BOARD_ID_LEN + 1];
>   	u8			serial[OCP_SERIAL_LEN];
> +	enum ptp_ocp_board_id_state board_id_state;
>   	bool			has_eeprom_data;
>   	u32			pps_req_map;
>   	int			flash_start;
> @@ -472,18 +480,23 @@ struct ptp_ocp_eeprom_map {
>   	.len = sizeof_field(struct ptp_ocp, member),		\
>   	.bp_offset = offsetof(struct ptp_ocp, member)
>   
> +#define EEPROM_ENTRY_LEN(addr, member, entry_len)		\
> +	.off = addr,						\
> +	.len = entry_len,					\
> +	.bp_offset = offsetof(struct ptp_ocp, member)
> +
>   #define BP_MAP_ENTRY_ADDR(bp, map) ({				\
>   	(void *)((uintptr_t)(bp) + (map)->bp_offset);		\
>   })
>   
>   static struct ptp_ocp_eeprom_map fb_eeprom_map[] = {
> -	{ EEPROM_ENTRY(0x43, board_id) },
> +	{ EEPROM_ENTRY_LEN(0x43, board_id, OCP_BOARD_ID_LEN) },
>   	{ EEPROM_ENTRY(0x00, serial), .tag = "mac" },
>   	{ }
>   };
>   
>   static struct ptp_ocp_eeprom_map art_eeprom_map[] = {
> -	{ EEPROM_ENTRY(0x200 + 0x43, board_id) },
> +	{ EEPROM_ENTRY_LEN(0x200 + 0x43, board_id, OCP_BOARD_ID_LEN) },
>   	{ EEPROM_ENTRY(0x200 + 0x63, serial) },
>   	{ }
>   };
> @@ -1969,6 +1982,52 @@ ptp_ocp_nvmem_device_put(struct nvmem_device **nvmemp)
>   	*nvmemp = NULL;
>   }
>   
> +static enum ptp_ocp_board_id_state
> +ptp_ocp_classify_board_id(char *board_id)
> +{
> +	bool all_zero = true;
> +	bool all_ones = true;
> +	bool terminated = false;
> +	unsigned int i;
> +
> +	board_id[OCP_BOARD_ID_LEN] = '\0';
> +	for (i = 0; i < OCP_BOARD_ID_LEN; i++) {
> +		u8 value = board_id[i];
> +
> +		all_zero &= value == 0;
> +		all_ones &= value == 0xff;
> +	}
> +
> +	if (all_zero || all_ones) {
> +		board_id[0] = '\0';
> +		return OCP_BOARD_ID_ERASED;
> +	}
> +
> +	for (i = 0; i < OCP_BOARD_ID_LEN; i++) {
> +		u8 value = board_id[i];
> +
> +		if (terminated) {
> +			if (value)
> +				goto invalid;
> +			continue;
> +		}
> +
> +		if (!value) {
> +			terminated = true;
> +			continue;
> +		}
> +		if (value < 0x20 || value > 0x7e)
> +			goto invalid;
> +	}
> +
> +	if (board_id[0])
> +		return OCP_BOARD_ID_VALID;
> +
> +invalid:
> +	board_id[0] = '\0';
> +	return OCP_BOARD_ID_INVALID;
> +}
> +
>   static void
>   ptp_ocp_read_eeprom(struct ptp_ocp *bp)
>   {
> @@ -2001,6 +2060,7 @@ ptp_ocp_read_eeprom(struct ptp_ocp *bp)
>   			goto fail;
>   	}
>   
> +	bp->board_id_state = ptp_ocp_classify_board_id(bp->board_id);
>   	bp->has_eeprom_data = true;
>   
>   out:
> @@ -2177,6 +2237,9 @@ ptp_ocp_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
>   	if (err)
>   		return err;
>   
> +	if (bp->board_id_state != OCP_BOARD_ID_VALID)
> +		return 0;
> +

why don't simply
snprintf(buf, OCP_BOARD_ID_LEN + 1, "%s", bp->board_id); ?

buf is already used in the function, let's reuse it

>   	err = devlink_info_version_fixed_put(req,
>   			DEVLINK_INFO_VERSION_GENERIC_BOARD_ID,
>   			bp->board_id);