]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ethtool: cmis: validate start_cmd_payload_size from module
authorJakub Kicinski <kuba@kernel.org>
Fri, 22 May 2026 23:13:11 +0000 (16:13 -0700)
committerJakub Kicinski <kuba@kernel.org>
Tue, 26 May 2026 15:19:33 +0000 (08:19 -0700)
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: c4f78134d45c ("ethtool: cmis_fw_update: add a layer for supporting firmware update using CDB")
Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Reviewed-by: Danielle Ratson <danieller@nvidia.com>
Link: https://patch.msgid.link/20260522231312.1710836-9-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/ethtool/cmis_fw_update.c

index df5f344209c47bee0795a9c506e99f6c66c323da..16190c97e1f78c66844a243b4f95c98d71b36fb3 100644 (file)
@@ -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,