Commit 6c3f999a authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

ethtool: cmis: require exact CDB reply length



Malicious SFP module could respond with rpl_len longer than
what cmis_cdb_process_reply() expected, leading to OOB writes.
Malicious HW is a bit theoretical but some modules may just
be buggy and/or the reads may occasionally get corrupted,
so let's protect the kernel.

The existing check protects from short replies. We need to
protect from long ones, too. All callers that pass a non-zero
rpl_exp_len cast the reply payload to a fixed-layout struct
and read fields at fixed offsets, with no version negotiation
or short-reply handling:

  - cmis_cdb_validate_password()
  - cmis_cdb_module_features_get()
  - cmis_fw_update_fw_mng_features_get()

so let's assume that responses longer than expected do not
have to be handled gracefully here. Add a warning message
to make the debug easier in case my understanding is wrong...

Note that page_data->length (argument of kmalloc) comes from
last arg to ethtool_cmis_page_init() which is rpl_exp_len.

Note2 that AIs also like to point out overflows in args->req.payload
itself (which is a fixed-size 120 B buffer, on the stack),
but callers should be reading structs defined by the standard,
so protecting from requests for more data than max seem like
defensive programming.

Fixes: a39c84d7 ("ethtool: cmis_cdb: Add a layer for supporting CDB commands")
Reviewed-by: default avatarDanielle Ratson <danieller@nvidia.com>
Link: https://patch.msgid.link/20260522231312.1710836-7-kuba@kernel.org


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 760d04eb
Loading
Loading
Loading
Loading
+7 −2
Original line number Diff line number Diff line
@@ -513,8 +513,13 @@ static int cmis_cdb_process_reply(struct net_device *dev,
	}

	rpl = (struct ethtool_cmis_cdb_rpl *)page_data->data;
	if ((args->rpl_exp_len > rpl->hdr.rpl_len + rpl_hdr_len) ||
	    !rpl->hdr.rpl_chk_code) {
	if (rpl->hdr.rpl_len != args->rpl_exp_len) {
		netdev_warn(dev, "CDB reply length mismatch, expected %u got %u\n",
			    args->rpl_exp_len, rpl->hdr.rpl_len);
		err = -EIO;
		goto out;
	}
	if (!rpl->hdr.rpl_chk_code) {
		err = -EIO;
		goto out;
	}