* [PATCH net 1/9] ethtool: module: call ethnl_ops_complete() on module flash errors
2026-05-22 23:13 [PATCH net 0/9] ethtool: module: fix a handful of small bugs Jakub Kicinski
@ 2026-05-22 23:13 ` Jakub Kicinski
2026-05-22 23:13 ` [PATCH net 2/9] ethtool: module: avoid leaking a netdev ref " Jakub Kicinski
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Jakub Kicinski @ 2026-05-22 23:13 UTC (permalink / raw)
To: davem
Cc: netdev, edumazet, pabeni, andrew+netdev, horms, maxime.chevallier,
danieller, petrm, o.rempel, idosch, Jakub Kicinski, andrew, kees
When validate() fails we are skipping over ethnl_ops_complete()
even tho we already called ethnl_ops_begin().
Fixes: 32b4c8b53ee7 ("ethtool: Add ability to flash transceiver modules' firmware")
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
CC: andrew@lunn.ch
CC: kees@kernel.org
CC: maxime.chevallier@bootlin.com
CC: petrm@nvidia.com
CC: danieller@nvidia.com
---
net/ethtool/module.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/ethtool/module.c b/net/ethtool/module.c
index cad2eb25b5a4..741f6fb25d45 100644
--- a/net/ethtool/module.c
+++ b/net/ethtool/module.c
@@ -427,10 +427,11 @@ int ethnl_act_module_fw_flash(struct sk_buff *skb, struct genl_info *info)
ret = ethnl_module_fw_flash_validate(dev, info->extack);
if (ret < 0)
- goto out_unlock;
+ goto out_complete;
ret = module_flash_fw(dev, tb, skb, info);
+out_complete:
ethnl_ops_complete(dev);
out_unlock:
--
2.54.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH net 2/9] ethtool: module: avoid leaking a netdev ref on module flash errors
2026-05-22 23:13 [PATCH net 0/9] ethtool: module: fix a handful of small bugs Jakub Kicinski
2026-05-22 23:13 ` [PATCH net 1/9] ethtool: module: call ethnl_ops_complete() on module flash errors Jakub Kicinski
@ 2026-05-22 23:13 ` Jakub Kicinski
2026-05-22 23:13 ` [PATCH net 3/9] ethtool: module: avoid racy updates to dev->ethtool bitfield Jakub Kicinski
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Jakub Kicinski @ 2026-05-22 23:13 UTC (permalink / raw)
To: davem
Cc: netdev, edumazet, pabeni, andrew+netdev, horms, maxime.chevallier,
danieller, petrm, o.rempel, idosch, Jakub Kicinski, andrew
module_flash_fw_schedule() is missing undo for setting
the "in_progress" flag and taking the netdev reference.
Delay taking these, the device can't disappear while
we are holding rtnl_lock.
Fixes: 32b4c8b53ee7 ("ethtool: Add ability to flash transceiver modules' firmware")
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
CC: andrew@lunn.ch
CC: maxime.chevallier@bootlin.com
CC: danieller@nvidia.com
CC: petrm@nvidia.com
---
net/ethtool/module.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/net/ethtool/module.c b/net/ethtool/module.c
index 741f6fb25d45..392c03935e5e 100644
--- a/net/ethtool/module.c
+++ b/net/ethtool/module.c
@@ -319,8 +319,6 @@ module_flash_fw_schedule(struct net_device *dev, const char *file_name,
if (err < 0)
goto err_release_firmware;
- dev->ethtool->module_fw_flash_in_progress = true;
- netdev_hold(dev, &module_fw->dev_tracker, GFP_KERNEL);
fw_update->dev = dev;
fw_update->ntf_params.portid = info->snd_portid;
fw_update->ntf_params.seq = info->snd_seq;
@@ -335,6 +333,9 @@ module_flash_fw_schedule(struct net_device *dev, const char *file_name,
if (err < 0)
goto err_release_firmware;
+ dev->ethtool->module_fw_flash_in_progress = true;
+ netdev_hold(dev, &module_fw->dev_tracker, GFP_KERNEL);
+
schedule_work(&module_fw->work);
return 0;
--
2.54.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH net 3/9] ethtool: module: avoid racy updates to dev->ethtool bitfield
2026-05-22 23:13 [PATCH net 0/9] ethtool: module: fix a handful of small bugs Jakub Kicinski
2026-05-22 23:13 ` [PATCH net 1/9] ethtool: module: call ethnl_ops_complete() on module flash errors Jakub Kicinski
2026-05-22 23:13 ` [PATCH net 2/9] ethtool: module: avoid leaking a netdev ref " Jakub Kicinski
@ 2026-05-22 23:13 ` Jakub Kicinski
2026-05-22 23:13 ` [PATCH net 4/9] ethtool: module: check fw_flash_in_progress under rtnl_lock Jakub Kicinski
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Jakub Kicinski @ 2026-05-22 23:13 UTC (permalink / raw)
To: davem
Cc: netdev, edumazet, pabeni, andrew+netdev, horms, maxime.chevallier,
danieller, petrm, o.rempel, idosch, Jakub Kicinski, andrew
When reviewing other changes Gemini points out that we currently
update module_fw_flash_in_progress without holding any locks.
Since module_fw_flash_in_progress is part of a bitfield this
is not great, updates to other fields may be lost.
We could use a bool and sprinkle some READ_ONCE/WRITE_ONCE here
but seems like the issue is rather than the work is an unusual
writer. The other writers already hold the right locks. So just
very briefly take these locks when the work completes.
Note that nothing ever cancels the FW update work, so there's
no concern with deadlocks vs cancel.
Fixes: 32b4c8b53ee7 ("ethtool: Add ability to flash transceiver modules' firmware")
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
CC: andrew@lunn.ch
CC: petrm@nvidia.com
CC: danieller@nvidia.com
---
net/ethtool/module.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/net/ethtool/module.c b/net/ethtool/module.c
index 392c03935e5e..cdb85e19a23b 100644
--- a/net/ethtool/module.c
+++ b/net/ethtool/module.c
@@ -221,14 +221,22 @@ static void module_flash_fw_work_list_del(struct list_head *list)
static void module_flash_fw_work(struct work_struct *work)
{
struct ethtool_module_fw_flash *module_fw;
+ struct net_device *dev;
module_fw = container_of(work, struct ethtool_module_fw_flash, work);
+ dev = module_fw->fw_update.dev;
ethtool_cmis_fw_update(&module_fw->fw_update);
module_flash_fw_work_list_del(&module_fw->list);
- module_fw->fw_update.dev->ethtool->module_fw_flash_in_progress = false;
- netdev_put(module_fw->fw_update.dev, &module_fw->dev_tracker);
+
+ rtnl_lock();
+ netdev_lock_ops(dev);
+ dev->ethtool->module_fw_flash_in_progress = false;
+ netdev_unlock_ops(dev);
+ rtnl_unlock();
+
+ netdev_put(dev, &module_fw->dev_tracker);
release_firmware(module_fw->fw_update.fw);
kfree(module_fw);
}
--
2.54.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH net 4/9] ethtool: module: check fw_flash_in_progress under rtnl_lock
2026-05-22 23:13 [PATCH net 0/9] ethtool: module: fix a handful of small bugs Jakub Kicinski
` (2 preceding siblings ...)
2026-05-22 23:13 ` [PATCH net 3/9] ethtool: module: avoid racy updates to dev->ethtool bitfield Jakub Kicinski
@ 2026-05-22 23:13 ` Jakub Kicinski
2026-05-22 23:13 ` [PATCH net 5/9] ethtool: module: fix cleanup if socket used for flashing multiple devices Jakub Kicinski
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Jakub Kicinski @ 2026-05-22 23:13 UTC (permalink / raw)
To: davem
Cc: netdev, edumazet, pabeni, andrew+netdev, horms, maxime.chevallier,
danieller, petrm, o.rempel, idosch, Jakub Kicinski, andrew
ethnl_set_module_validate() inspects module_fw_flash_in_progress
but validate is meant for _input_ validation, not state validation.
rtnl_lock is not held, yet. Move the check into ethnl_set_module().
Fixes: 32b4c8b53ee7 ("ethtool: Add ability to flash transceiver modules' firmware")
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
CC: andrew@lunn.ch
CC: petrm@nvidia.com
CC: danieller@nvidia.com
---
net/ethtool/module.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/net/ethtool/module.c b/net/ethtool/module.c
index cdb85e19a23b..5b49004ddf60 100644
--- a/net/ethtool/module.c
+++ b/net/ethtool/module.c
@@ -120,12 +120,6 @@ ethnl_set_module_validate(struct ethnl_req_info *req_info,
if (!tb[ETHTOOL_A_MODULE_POWER_MODE_POLICY])
return 0;
- if (req_info->dev->ethtool->module_fw_flash_in_progress) {
- NL_SET_ERR_MSG(info->extack,
- "Module firmware flashing is in progress");
- return -EBUSY;
- }
-
if (!ops->get_module_power_mode || !ops->set_module_power_mode) {
NL_SET_ERR_MSG_ATTR(info->extack,
tb[ETHTOOL_A_MODULE_POWER_MODE_POLICY],
@@ -148,6 +142,12 @@ ethnl_set_module(struct ethnl_req_info *req_info, struct genl_info *info)
ops = dev->ethtool_ops;
+ if (dev->ethtool->module_fw_flash_in_progress) {
+ NL_SET_ERR_MSG(info->extack,
+ "Module firmware flashing is in progress");
+ return -EBUSY;
+ }
+
power_new.policy = nla_get_u8(tb[ETHTOOL_A_MODULE_POWER_MODE_POLICY]);
ret = ops->get_module_power_mode(dev, &power, info->extack);
if (ret < 0)
--
2.54.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH net 5/9] ethtool: module: fix cleanup if socket used for flashing multiple devices
2026-05-22 23:13 [PATCH net 0/9] ethtool: module: fix a handful of small bugs Jakub Kicinski
` (3 preceding siblings ...)
2026-05-22 23:13 ` [PATCH net 4/9] ethtool: module: check fw_flash_in_progress under rtnl_lock Jakub Kicinski
@ 2026-05-22 23:13 ` Jakub Kicinski
2026-05-22 23:13 ` [PATCH net 6/9] ethtool: cmis: require exact CDB reply length Jakub Kicinski
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Jakub Kicinski @ 2026-05-22 23:13 UTC (permalink / raw)
To: davem
Cc: netdev, edumazet, pabeni, andrew+netdev, horms, maxime.chevallier,
danieller, petrm, o.rempel, idosch, Jakub Kicinski, andrew
When a single Netlink socket issues MODULE_FW_FLASH_ACT against multiple
devices, ethnl_sock_priv_set() overwrites sk_priv->dev on each call,
retaining only the last one. The socket priv is used on socket close,
to walk the global work list and mark the uncompleted flashing work
as "orphaned". Otherwise if another socket reuses the PID it will
unexpectedly receive the flashing notifications.
Don't record the device, record net pointer instead. The purpose of
the dev is to scope the work to a netns, anyway. If we store netns
the overrides are safe/a nop since all flashed devices must be in
the same netns as the socket.
Fixes: 32b4c8b53ee7 ("ethtool: Add ability to flash transceiver modules' firmware")
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
CC: andrew@lunn.ch
CC: maxime.chevallier@bootlin.com
CC: danieller@nvidia.com
CC: petrm@nvidia.com
---
net/ethtool/netlink.h | 4 ++--
net/ethtool/module.c | 9 ++++-----
net/ethtool/netlink.c | 4 ++--
3 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h
index aaf6f2468768..fd2198e45d2b 100644
--- a/net/ethtool/netlink.h
+++ b/net/ethtool/netlink.h
@@ -318,12 +318,12 @@ enum ethnl_sock_type {
};
struct ethnl_sock_priv {
- struct net_device *dev;
+ struct net *net;
u32 portid;
enum ethnl_sock_type type;
};
-int ethnl_sock_priv_set(struct sk_buff *skb, struct net_device *dev, u32 portid,
+int ethnl_sock_priv_set(struct sk_buff *skb, struct net *net, u32 portid,
enum ethnl_sock_type type);
/**
diff --git a/net/ethtool/module.c b/net/ethtool/module.c
index 5b49004ddf60..ea4fb2a76650 100644
--- a/net/ethtool/module.c
+++ b/net/ethtool/module.c
@@ -291,11 +291,9 @@ void ethnl_module_fw_flash_sock_destroy(struct ethnl_sock_priv *sk_priv)
spin_lock(&module_fw_flash_work_list_lock);
list_for_each_entry(work, &module_fw_flash_work_list, list) {
- if (work->fw_update.dev == sk_priv->dev &&
- work->fw_update.ntf_params.portid == sk_priv->portid) {
+ if (work->fw_update.ntf_params.portid == sk_priv->portid &&
+ dev_net(work->fw_update.dev) == sk_priv->net)
work->fw_update.ntf_params.closed_sock = true;
- break;
- }
}
spin_unlock(&module_fw_flash_work_list_lock);
}
@@ -332,7 +330,8 @@ module_flash_fw_schedule(struct net_device *dev, const char *file_name,
fw_update->ntf_params.seq = info->snd_seq;
fw_update->ntf_params.closed_sock = false;
- err = ethnl_sock_priv_set(skb, dev, fw_update->ntf_params.portid,
+ err = ethnl_sock_priv_set(skb, dev_net(dev),
+ fw_update->ntf_params.portid,
ETHTOOL_SOCK_TYPE_MODULE_FW_FLASH);
if (err < 0)
goto err_release_firmware;
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index 5046023a30b1..7d45f9a884e5 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -53,7 +53,7 @@ const struct nla_policy ethnl_header_policy_phy_stats[] = {
[ETHTOOL_A_HEADER_PHY_INDEX] = NLA_POLICY_MIN(NLA_U32, 1),
};
-int ethnl_sock_priv_set(struct sk_buff *skb, struct net_device *dev, u32 portid,
+int ethnl_sock_priv_set(struct sk_buff *skb, struct net *net, u32 portid,
enum ethnl_sock_type type)
{
struct ethnl_sock_priv *sk_priv;
@@ -62,7 +62,7 @@ int ethnl_sock_priv_set(struct sk_buff *skb, struct net_device *dev, u32 portid,
if (IS_ERR(sk_priv))
return PTR_ERR(sk_priv);
- sk_priv->dev = dev;
+ sk_priv->net = net;
sk_priv->portid = portid;
sk_priv->type = type;
--
2.54.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH net 6/9] ethtool: cmis: require exact CDB reply length
2026-05-22 23:13 [PATCH net 0/9] ethtool: module: fix a handful of small bugs Jakub Kicinski
` (4 preceding siblings ...)
2026-05-22 23:13 ` [PATCH net 5/9] ethtool: module: fix cleanup if socket used for flashing multiple devices Jakub Kicinski
@ 2026-05-22 23:13 ` Jakub Kicinski
2026-05-22 23:13 ` [PATCH net 7/9] ethtool: cmis: fix u16-to-u8 truncation of msleep_pre_rpl Jakub Kicinski
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Jakub Kicinski @ 2026-05-22 23:13 UTC (permalink / raw)
To: davem
Cc: netdev, edumazet, pabeni, andrew+netdev, horms, maxime.chevallier,
danieller, petrm, o.rempel, idosch, Jakub Kicinski, andrew, kees
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: a39c84d79625 ("ethtool: cmis_cdb: Add a layer for supporting CDB commands")
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
CC: andrew@lunn.ch
CC: kees@kernel.org
CC: danieller@nvidia.com
CC: petrm@nvidia.com
---
net/ethtool/cmis_cdb.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/net/ethtool/cmis_cdb.c b/net/ethtool/cmis_cdb.c
index 3670ca42dd40..f3a53a984460 100644
--- a/net/ethtool/cmis_cdb.c
+++ b/net/ethtool/cmis_cdb.c
@@ -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;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH net 7/9] ethtool: cmis: fix u16-to-u8 truncation of msleep_pre_rpl
2026-05-22 23:13 [PATCH net 0/9] ethtool: module: fix a handful of small bugs Jakub Kicinski
` (5 preceding siblings ...)
2026-05-22 23:13 ` [PATCH net 6/9] ethtool: cmis: require exact CDB reply length Jakub Kicinski
@ 2026-05-22 23:13 ` Jakub Kicinski
2026-05-22 23:13 ` [PATCH net 8/9] ethtool: cmis: validate start_cmd_payload_size from module Jakub Kicinski
2026-05-22 23:13 ` [PATCH net 9/9] ethtool: cmis: validate fw->size against start_cmd_payload_size Jakub Kicinski
8 siblings, 0 replies; 10+ messages in thread
From: Jakub Kicinski @ 2026-05-22 23:13 UTC (permalink / raw)
To: davem
Cc: netdev, edumazet, pabeni, andrew+netdev, horms, maxime.chevallier,
danieller, petrm, o.rempel, idosch, Jakub Kicinski, andrew
ethtool_cmis_cdb_compose_args() accepts msleep_pre_rpl as u16 but stores
it into the u8 field ethtool_cmis_cdb_cmd_args::msleep_pre_rpl, silently
truncating values >= 256. Seven of the nine call sites pass 1000 ms
(it's the third argument from the end).
Fixes: a39c84d79625 ("ethtool: cmis_cdb: Add a layer for supporting CDB commands")
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
CC: andrew@lunn.ch
CC: petrm@nvidia.com
CC: danieller@nvidia.com
---
net/ethtool/cmis.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/ethtool/cmis.h b/net/ethtool/cmis.h
index 4a9a946cabf0..778783a0f23c 100644
--- a/net/ethtool/cmis.h
+++ b/net/ethtool/cmis.h
@@ -63,9 +63,9 @@ struct ethtool_cmis_cdb_request {
* struct ethtool_cmis_cdb_cmd_args - CDB commands execution arguments
* @req: CDB command fields as described in the CMIS standard.
* @max_duration: Maximum duration time for command completion in msec.
+ * @msleep_pre_rpl: Waiting time before checking reply in msec.
* @read_write_len_ext: Allowable additional number of byte octets to the LPL
* in a READ or a WRITE commands.
- * @msleep_pre_rpl: Waiting time before checking reply in msec.
* @rpl_exp_len: Expected reply length in bytes.
* @flags: Validation flags for CDB commands.
* @err_msg: Error message to be sent to user space.
@@ -73,8 +73,8 @@ struct ethtool_cmis_cdb_request {
struct ethtool_cmis_cdb_cmd_args {
struct ethtool_cmis_cdb_request req;
u16 max_duration;
+ u16 msleep_pre_rpl;
u8 read_write_len_ext;
- u8 msleep_pre_rpl;
u8 rpl_exp_len;
u8 flags;
char *err_msg;
--
2.54.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH net 8/9] ethtool: cmis: validate start_cmd_payload_size from module
2026-05-22 23:13 [PATCH net 0/9] ethtool: module: fix a handful of small bugs Jakub Kicinski
` (6 preceding siblings ...)
2026-05-22 23:13 ` [PATCH net 7/9] ethtool: cmis: fix u16-to-u8 truncation of msleep_pre_rpl Jakub Kicinski
@ 2026-05-22 23:13 ` Jakub Kicinski
2026-05-22 23:13 ` [PATCH net 9/9] ethtool: cmis: validate fw->size against start_cmd_payload_size Jakub Kicinski
8 siblings, 0 replies; 10+ messages in thread
From: Jakub Kicinski @ 2026-05-22 23:13 UTC (permalink / raw)
To: davem
Cc: netdev, edumazet, pabeni, andrew+netdev, horms, maxime.chevallier,
danieller, petrm, o.rempel, idosch, Jakub Kicinski, andrew
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")
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
CC: andrew@lunn.ch
CC: petrm@nvidia.com
CC: danieller@nvidia.com
---
net/ethtool/cmis_fw_update.c | 36 ++++++++++++++++++++++--------------
1 file changed, 22 insertions(+), 14 deletions(-)
diff --git a/net/ethtool/cmis_fw_update.c b/net/ethtool/cmis_fw_update.c
index df5f344209c4..16190c97e1f7 100644
--- a/net/ethtool/cmis_fw_update.c
+++ b/net/ethtool/cmis_fw_update.c
@@ -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,
--
2.54.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH net 9/9] ethtool: cmis: validate fw->size against start_cmd_payload_size
2026-05-22 23:13 [PATCH net 0/9] ethtool: module: fix a handful of small bugs Jakub Kicinski
` (7 preceding siblings ...)
2026-05-22 23:13 ` [PATCH net 8/9] ethtool: cmis: validate start_cmd_payload_size from module Jakub Kicinski
@ 2026-05-22 23:13 ` Jakub Kicinski
8 siblings, 0 replies; 10+ messages in thread
From: Jakub Kicinski @ 2026-05-22 23:13 UTC (permalink / raw)
To: davem
Cc: netdev, edumazet, pabeni, andrew+netdev, horms, maxime.chevallier,
danieller, petrm, o.rempel, idosch, Jakub Kicinski, andrew
cmis_fw_update_start_download() copies start_cmd_payload_size bytes
from the firmware blob into the CDB LPL vendor_data[] payload without
validating that the FW has enough data.
Since the start_cmd_payload_size can only be ~120B an image too short
is most likely corrupted, so reject it.
Fixes: c4f78134d45c ("ethtool: cmis_fw_update: add a layer for supporting firmware update using CDB")
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
CC: andrew@lunn.ch
CC: danieller@nvidia.com
CC: petrm@nvidia.com
---
net/ethtool/cmis_fw_update.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/net/ethtool/cmis_fw_update.c b/net/ethtool/cmis_fw_update.c
index 16190c97e1f7..291d04d2776a 100644
--- a/net/ethtool/cmis_fw_update.c
+++ b/net/ethtool/cmis_fw_update.c
@@ -130,6 +130,14 @@ cmis_fw_update_start_download(struct ethtool_cmis_cdb *cdb,
u8 lpl_len;
int err;
+ if (fw_update->fw->size < vendor_data_size) {
+ ethnl_module_fw_flash_ntf_err(fw_update->dev,
+ &fw_update->ntf_params,
+ "Firmware image too small for module's start payload",
+ NULL);
+ return -EINVAL;
+ }
+
pl.image_size = cpu_to_be32(fw_update->fw->size);
memcpy(pl.vendor_data, fw_update->fw->data, vendor_data_size);
--
2.54.0
^ permalink raw reply related [flat|nested] 10+ messages in thread