mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
net: ethtool: netlink: Allow NULL nlattrs when getting a phy_device
ethnl_req_get_phydev() is used to lookup a phy_device, in the case an
ethtool netlink command targets a specific phydev within a netdev's
topology.
It takes as a parameter a const struct nlattr *header that's used for
error handling :
if (!phydev) {
NL_SET_ERR_MSG_ATTR(extack, header,
"no phy matching phyindex");
return ERR_PTR(-ENODEV);
}
In the notify path after a ->set operation however, there's no request
attributes available.
The typical callsite for the above function looks like:
phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_XXX_HEADER],
info->extack);
So, when tb is NULL (such as in the ethnl notify path), we have a nice
crash.
It turns out that there's only the PLCA command that is in that case, as
the other phydev-specific commands don't have a notification.
This commit fixes the crash by passing the cmd index and the nlattr
array separately, allowing NULL-checking it directly inside the helper.
Fixes: c15e065b46
("net: ethtool: Allow passing a phy index for some commands")
Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Reviewed-by: Kory Maincent <kory.maincent@bootlin.com>
Reported-by: Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
Link: https://patch.msgid.link/20250301141114.97204-1-maxime.chevallier@bootlin.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
4c2d14c40a
commit
637399bf7e
9 changed files with 19 additions and 18 deletions
|
@ -72,8 +72,8 @@ int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info)
|
|||
dev = req_info.dev;
|
||||
|
||||
rtnl_lock();
|
||||
phydev = ethnl_req_get_phydev(&req_info,
|
||||
tb[ETHTOOL_A_CABLE_TEST_HEADER],
|
||||
phydev = ethnl_req_get_phydev(&req_info, tb,
|
||||
ETHTOOL_A_CABLE_TEST_HEADER,
|
||||
info->extack);
|
||||
if (IS_ERR_OR_NULL(phydev)) {
|
||||
ret = -EOPNOTSUPP;
|
||||
|
@ -339,8 +339,8 @@ int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info)
|
|||
goto out_dev_put;
|
||||
|
||||
rtnl_lock();
|
||||
phydev = ethnl_req_get_phydev(&req_info,
|
||||
tb[ETHTOOL_A_CABLE_TEST_TDR_HEADER],
|
||||
phydev = ethnl_req_get_phydev(&req_info, tb,
|
||||
ETHTOOL_A_CABLE_TEST_TDR_HEADER,
|
||||
info->extack);
|
||||
if (IS_ERR_OR_NULL(phydev)) {
|
||||
ret = -EOPNOTSUPP;
|
||||
|
|
|
@ -103,7 +103,7 @@ static int linkstate_prepare_data(const struct ethnl_req_info *req_base,
|
|||
struct phy_device *phydev;
|
||||
int ret;
|
||||
|
||||
phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_LINKSTATE_HEADER],
|
||||
phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_LINKSTATE_HEADER,
|
||||
info->extack);
|
||||
if (IS_ERR(phydev)) {
|
||||
ret = PTR_ERR(phydev);
|
||||
|
|
|
@ -211,7 +211,7 @@ int ethnl_parse_header_dev_get(struct ethnl_req_info *req_info,
|
|||
}
|
||||
|
||||
struct phy_device *ethnl_req_get_phydev(const struct ethnl_req_info *req_info,
|
||||
const struct nlattr *header,
|
||||
struct nlattr **tb, unsigned int header,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct phy_device *phydev;
|
||||
|
@ -225,8 +225,8 @@ struct phy_device *ethnl_req_get_phydev(const struct ethnl_req_info *req_info,
|
|||
return req_info->dev->phydev;
|
||||
|
||||
phydev = phy_link_topo_get_phy(req_info->dev, req_info->phy_index);
|
||||
if (!phydev) {
|
||||
NL_SET_ERR_MSG_ATTR(extack, header,
|
||||
if (!phydev && tb) {
|
||||
NL_SET_ERR_MSG_ATTR(extack, tb[header],
|
||||
"no phy matching phyindex");
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
|
|
@ -275,7 +275,8 @@ static inline void ethnl_parse_header_dev_put(struct ethnl_req_info *req_info)
|
|||
* ethnl_req_get_phydev() - Gets the phy_device targeted by this request,
|
||||
* if any. Must be called under rntl_lock().
|
||||
* @req_info: The ethnl request to get the phy from.
|
||||
* @header: The netlink header, used for error reporting.
|
||||
* @tb: The netlink attributes array, for error reporting.
|
||||
* @header: The netlink header index, used for error reporting.
|
||||
* @extack: The netlink extended ACK, for error reporting.
|
||||
*
|
||||
* The caller must hold RTNL, until it's done interacting with the returned
|
||||
|
@ -289,7 +290,7 @@ static inline void ethnl_parse_header_dev_put(struct ethnl_req_info *req_info)
|
|||
* is returned.
|
||||
*/
|
||||
struct phy_device *ethnl_req_get_phydev(const struct ethnl_req_info *req_info,
|
||||
const struct nlattr *header,
|
||||
struct nlattr **tb, unsigned int header,
|
||||
struct netlink_ext_ack *extack);
|
||||
|
||||
/**
|
||||
|
|
|
@ -125,7 +125,7 @@ static int ethnl_phy_parse_request(struct ethnl_req_info *req_base,
|
|||
struct phy_req_info *req_info = PHY_REQINFO(req_base);
|
||||
struct phy_device *phydev;
|
||||
|
||||
phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_PHY_HEADER],
|
||||
phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_PHY_HEADER,
|
||||
extack);
|
||||
if (!phydev)
|
||||
return 0;
|
||||
|
|
|
@ -62,7 +62,7 @@ static int plca_get_cfg_prepare_data(const struct ethnl_req_info *req_base,
|
|||
struct phy_device *phydev;
|
||||
int ret;
|
||||
|
||||
phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_PLCA_HEADER],
|
||||
phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_PLCA_HEADER,
|
||||
info->extack);
|
||||
// check that the PHY device is available and connected
|
||||
if (IS_ERR_OR_NULL(phydev)) {
|
||||
|
@ -152,7 +152,7 @@ ethnl_set_plca(struct ethnl_req_info *req_info, struct genl_info *info)
|
|||
bool mod = false;
|
||||
int ret;
|
||||
|
||||
phydev = ethnl_req_get_phydev(req_info, tb[ETHTOOL_A_PLCA_HEADER],
|
||||
phydev = ethnl_req_get_phydev(req_info, tb, ETHTOOL_A_PLCA_HEADER,
|
||||
info->extack);
|
||||
// check that the PHY device is available and connected
|
||||
if (IS_ERR_OR_NULL(phydev))
|
||||
|
@ -211,7 +211,7 @@ static int plca_get_status_prepare_data(const struct ethnl_req_info *req_base,
|
|||
struct phy_device *phydev;
|
||||
int ret;
|
||||
|
||||
phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_PLCA_HEADER],
|
||||
phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_PLCA_HEADER,
|
||||
info->extack);
|
||||
// check that the PHY device is available and connected
|
||||
if (IS_ERR_OR_NULL(phydev)) {
|
||||
|
|
|
@ -64,7 +64,7 @@ static int pse_prepare_data(const struct ethnl_req_info *req_base,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_PSE_HEADER],
|
||||
phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_PSE_HEADER,
|
||||
info->extack);
|
||||
if (IS_ERR(phydev))
|
||||
return -ENODEV;
|
||||
|
@ -261,7 +261,7 @@ ethnl_set_pse(struct ethnl_req_info *req_info, struct genl_info *info)
|
|||
struct phy_device *phydev;
|
||||
int ret;
|
||||
|
||||
phydev = ethnl_req_get_phydev(req_info, tb[ETHTOOL_A_PSE_HEADER],
|
||||
phydev = ethnl_req_get_phydev(req_info, tb, ETHTOOL_A_PSE_HEADER,
|
||||
info->extack);
|
||||
ret = ethnl_set_pse_validate(phydev, info);
|
||||
if (ret)
|
||||
|
|
|
@ -138,7 +138,7 @@ static int stats_prepare_data(const struct ethnl_req_info *req_base,
|
|||
struct phy_device *phydev;
|
||||
int ret;
|
||||
|
||||
phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_STATS_HEADER],
|
||||
phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_STATS_HEADER,
|
||||
info->extack);
|
||||
if (IS_ERR(phydev))
|
||||
return PTR_ERR(phydev);
|
||||
|
|
|
@ -309,7 +309,7 @@ static int strset_prepare_data(const struct ethnl_req_info *req_base,
|
|||
return 0;
|
||||
}
|
||||
|
||||
phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_HEADER_FLAGS],
|
||||
phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_HEADER_FLAGS,
|
||||
info->extack);
|
||||
|
||||
/* phydev can be NULL, check for errors only */
|
||||
|
|
Loading…
Add table
Reference in a new issue