Skip to content

Commit 637399b

Browse files
minimaxwellkuba-moo
authored andcommitted
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: c15e065 ("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>
1 parent 4c2d14c commit 637399b

File tree

9 files changed

+19
-18
lines changed

9 files changed

+19
-18
lines changed

net/ethtool/cabletest.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info)
7272
dev = req_info.dev;
7373

7474
rtnl_lock();
75-
phydev = ethnl_req_get_phydev(&req_info,
76-
tb[ETHTOOL_A_CABLE_TEST_HEADER],
75+
phydev = ethnl_req_get_phydev(&req_info, tb,
76+
ETHTOOL_A_CABLE_TEST_HEADER,
7777
info->extack);
7878
if (IS_ERR_OR_NULL(phydev)) {
7979
ret = -EOPNOTSUPP;
@@ -339,8 +339,8 @@ int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info)
339339
goto out_dev_put;
340340

341341
rtnl_lock();
342-
phydev = ethnl_req_get_phydev(&req_info,
343-
tb[ETHTOOL_A_CABLE_TEST_TDR_HEADER],
342+
phydev = ethnl_req_get_phydev(&req_info, tb,
343+
ETHTOOL_A_CABLE_TEST_TDR_HEADER,
344344
info->extack);
345345
if (IS_ERR_OR_NULL(phydev)) {
346346
ret = -EOPNOTSUPP;

net/ethtool/linkstate.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ static int linkstate_prepare_data(const struct ethnl_req_info *req_base,
103103
struct phy_device *phydev;
104104
int ret;
105105

106-
phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_LINKSTATE_HEADER],
106+
phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_LINKSTATE_HEADER,
107107
info->extack);
108108
if (IS_ERR(phydev)) {
109109
ret = PTR_ERR(phydev);

net/ethtool/netlink.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ int ethnl_parse_header_dev_get(struct ethnl_req_info *req_info,
211211
}
212212

213213
struct phy_device *ethnl_req_get_phydev(const struct ethnl_req_info *req_info,
214-
const struct nlattr *header,
214+
struct nlattr **tb, unsigned int header,
215215
struct netlink_ext_ack *extack)
216216
{
217217
struct phy_device *phydev;
@@ -225,8 +225,8 @@ struct phy_device *ethnl_req_get_phydev(const struct ethnl_req_info *req_info,
225225
return req_info->dev->phydev;
226226

227227
phydev = phy_link_topo_get_phy(req_info->dev, req_info->phy_index);
228-
if (!phydev) {
229-
NL_SET_ERR_MSG_ATTR(extack, header,
228+
if (!phydev && tb) {
229+
NL_SET_ERR_MSG_ATTR(extack, tb[header],
230230
"no phy matching phyindex");
231231
return ERR_PTR(-ENODEV);
232232
}

net/ethtool/netlink.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,8 @@ static inline void ethnl_parse_header_dev_put(struct ethnl_req_info *req_info)
275275
* ethnl_req_get_phydev() - Gets the phy_device targeted by this request,
276276
* if any. Must be called under rntl_lock().
277277
* @req_info: The ethnl request to get the phy from.
278-
* @header: The netlink header, used for error reporting.
278+
* @tb: The netlink attributes array, for error reporting.
279+
* @header: The netlink header index, used for error reporting.
279280
* @extack: The netlink extended ACK, for error reporting.
280281
*
281282
* 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)
289290
* is returned.
290291
*/
291292
struct phy_device *ethnl_req_get_phydev(const struct ethnl_req_info *req_info,
292-
const struct nlattr *header,
293+
struct nlattr **tb, unsigned int header,
293294
struct netlink_ext_ack *extack);
294295

295296
/**

net/ethtool/phy.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ static int ethnl_phy_parse_request(struct ethnl_req_info *req_base,
125125
struct phy_req_info *req_info = PHY_REQINFO(req_base);
126126
struct phy_device *phydev;
127127

128-
phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_PHY_HEADER],
128+
phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_PHY_HEADER,
129129
extack);
130130
if (!phydev)
131131
return 0;

net/ethtool/plca.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ static int plca_get_cfg_prepare_data(const struct ethnl_req_info *req_base,
6262
struct phy_device *phydev;
6363
int ret;
6464

65-
phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_PLCA_HEADER],
65+
phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_PLCA_HEADER,
6666
info->extack);
6767
// check that the PHY device is available and connected
6868
if (IS_ERR_OR_NULL(phydev)) {
@@ -152,7 +152,7 @@ ethnl_set_plca(struct ethnl_req_info *req_info, struct genl_info *info)
152152
bool mod = false;
153153
int ret;
154154

155-
phydev = ethnl_req_get_phydev(req_info, tb[ETHTOOL_A_PLCA_HEADER],
155+
phydev = ethnl_req_get_phydev(req_info, tb, ETHTOOL_A_PLCA_HEADER,
156156
info->extack);
157157
// check that the PHY device is available and connected
158158
if (IS_ERR_OR_NULL(phydev))
@@ -211,7 +211,7 @@ static int plca_get_status_prepare_data(const struct ethnl_req_info *req_base,
211211
struct phy_device *phydev;
212212
int ret;
213213

214-
phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_PLCA_HEADER],
214+
phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_PLCA_HEADER,
215215
info->extack);
216216
// check that the PHY device is available and connected
217217
if (IS_ERR_OR_NULL(phydev)) {

net/ethtool/pse-pd.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ static int pse_prepare_data(const struct ethnl_req_info *req_base,
6464
if (ret < 0)
6565
return ret;
6666

67-
phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_PSE_HEADER],
67+
phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_PSE_HEADER,
6868
info->extack);
6969
if (IS_ERR(phydev))
7070
return -ENODEV;
@@ -261,7 +261,7 @@ ethnl_set_pse(struct ethnl_req_info *req_info, struct genl_info *info)
261261
struct phy_device *phydev;
262262
int ret;
263263

264-
phydev = ethnl_req_get_phydev(req_info, tb[ETHTOOL_A_PSE_HEADER],
264+
phydev = ethnl_req_get_phydev(req_info, tb, ETHTOOL_A_PSE_HEADER,
265265
info->extack);
266266
ret = ethnl_set_pse_validate(phydev, info);
267267
if (ret)

net/ethtool/stats.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ static int stats_prepare_data(const struct ethnl_req_info *req_base,
138138
struct phy_device *phydev;
139139
int ret;
140140

141-
phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_STATS_HEADER],
141+
phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_STATS_HEADER,
142142
info->extack);
143143
if (IS_ERR(phydev))
144144
return PTR_ERR(phydev);

net/ethtool/strset.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ static int strset_prepare_data(const struct ethnl_req_info *req_base,
309309
return 0;
310310
}
311311

312-
phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_HEADER_FLAGS],
312+
phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_HEADER_FLAGS,
313313
info->extack);
314314

315315
/* phydev can be NULL, check for errors only */

0 commit comments

Comments
 (0)