Commit 12c2496a authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

ethtool: cmis: validate start_cmd_payload_size from module



The CMIS firmware update code reads start_cmd_payload_size from
the module's FW Management Features CDB reply and uses it directly
as the byte count for memcpy. The destination buffer is 112 bytes
(ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH - 8). So a malicious
module (or corrupted response) can cause a OOB write later on in
cmis_fw_update_start_download().

Let's error out. If modules that expect longer LPL writes actually
exist we should revisit.

struct cmis_cdb_start_fw_download_pl's definition has to move,
no change there.

Fixes: c4f78134 ("ethtool: cmis_fw_update: add a layer for supporting firmware update using CDB")
Reviewed-by: default avatarMaxime Chevallier <maxime.chevallier@bootlin.com>
Reviewed-by: default avatarDanielle Ratson <danieller@nvidia.com>
Link: https://patch.msgid.link/20260522231312.1710836-9-kuba@kernel.org


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 3e8c3d46
Loading
Loading
Loading
Loading
+22 −14
Original line number Diff line number Diff line
@@ -44,6 +44,20 @@ enum cmis_cdb_fw_write_mechanism {
	CMIS_CDB_FW_WRITE_MECHANISM_BOTH	= 0x11,
};

/* See section 9.7.2 "CMD 0101h: Start Firmware Download" in CMIS standard
 * revision 5.2.
 * struct cmis_cdb_start_fw_download_pl is a structured layout of the
 * flat array, ethtool_cmis_cdb_request::payload.
 */
struct cmis_cdb_start_fw_download_pl {
	__struct_group(cmis_cdb_start_fw_download_pl_h, head, /* no attrs */,
			__be32	image_size;
			__be32	resv1;
	);
	u8 vendor_data[ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH -
		sizeof(struct cmis_cdb_start_fw_download_pl_h)];
};

static int
cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb,
				   struct net_device *dev,
@@ -86,6 +100,14 @@ cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb,
	 */
	cdb->read_write_len_ext = rpl->read_write_len_ext;
	fw_mng->start_cmd_payload_size = rpl->start_cmd_payload_size;
	if (fw_mng->start_cmd_payload_size >
	    sizeof_field(struct cmis_cdb_start_fw_download_pl, vendor_data)) {
		ethnl_module_fw_flash_ntf_err(dev, ntf_params,
					      "Start cmd payload size exceeds max LPL payload",
					      NULL);
		return -EINVAL;
	}

	fw_mng->write_mechanism =
		rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_LPL ?
		CMIS_CDB_FW_WRITE_MECHANISM_LPL :
@@ -97,20 +119,6 @@ cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb,
	return 0;
}

/* See section 9.7.2 "CMD 0101h: Start Firmware Download" in CMIS standard
 * revision 5.2.
 * struct cmis_cdb_start_fw_download_pl is a structured layout of the
 * flat array, ethtool_cmis_cdb_request::payload.
 */
struct cmis_cdb_start_fw_download_pl {
	__struct_group(cmis_cdb_start_fw_download_pl_h, head, /* no attrs */,
			__be32	image_size;
			__be32	resv1;
	);
	u8 vendor_data[ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH -
		sizeof(struct cmis_cdb_start_fw_download_pl_h)];
};

static int
cmis_fw_update_start_download(struct ethtool_cmis_cdb *cdb,
			      struct ethtool_cmis_fw_update_params *fw_update,