Skip to content

Commit c1f3f97

Browse files
can: netlink: can_changelink(): fix NULL pointer deref of struct can_priv::do_set_mode
Andrei Lalaev reported a NULL pointer deref when a CAN device is restarted from Bus Off and the driver does not implement the struct can_priv::do_set_mode callback. There are 2 code path that call struct can_priv::do_set_mode: - directly by a manual restart from the user space, via can_changelink() - delayed automatic restart after bus off (deactivated by default) To prevent the NULL pointer deference, refuse a manual restart or configure the automatic restart delay in can_changelink() and report the error via extack to user space. As an additional safety measure let can_restart() return an error if can_priv::do_set_mode is not set instead of dereferencing it unchecked. Reported-by: Andrei Lalaev <[email protected]> Closes: https://lore.kernel.org/all/[email protected] Fixes: 39549ee ("can: CAN Network device driver and Netlink interface") Link: https://patch.msgid.link/20250718-fix-nullptr-deref-do_set_mode-v1-1-0b520097bb96@pengutronix.de Signed-off-by: Marc Kleine-Budde <[email protected]>
1 parent b03f15c commit c1f3f97

File tree

2 files changed

+21
-3
lines changed

2 files changed

+21
-3
lines changed

drivers/net/can/dev/dev.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,13 +145,16 @@ void can_change_state(struct net_device *dev, struct can_frame *cf,
145145
EXPORT_SYMBOL_GPL(can_change_state);
146146

147147
/* CAN device restart for bus-off recovery */
148-
static void can_restart(struct net_device *dev)
148+
static int can_restart(struct net_device *dev)
149149
{
150150
struct can_priv *priv = netdev_priv(dev);
151151
struct sk_buff *skb;
152152
struct can_frame *cf;
153153
int err;
154154

155+
if (!priv->do_set_mode)
156+
return -EOPNOTSUPP;
157+
155158
if (netif_carrier_ok(dev))
156159
netdev_err(dev, "Attempt to restart for bus-off recovery, but carrier is OK?\n");
157160

@@ -173,10 +176,14 @@ static void can_restart(struct net_device *dev)
173176
if (err) {
174177
netdev_err(dev, "Restart failed, error %pe\n", ERR_PTR(err));
175178
netif_carrier_off(dev);
179+
180+
return err;
176181
} else {
177182
netdev_dbg(dev, "Restarted\n");
178183
priv->can_stats.restarts++;
179184
}
185+
186+
return 0;
180187
}
181188

182189
static void can_restart_work(struct work_struct *work)
@@ -201,9 +208,8 @@ int can_restart_now(struct net_device *dev)
201208
return -EBUSY;
202209

203210
cancel_delayed_work_sync(&priv->restart_work);
204-
can_restart(dev);
205211

206-
return 0;
212+
return can_restart(dev);
207213
}
208214

209215
/* CAN bus-off

drivers/net/can/dev/netlink.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,13 +285,25 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
285285
}
286286

287287
if (data[IFLA_CAN_RESTART_MS]) {
288+
if (!priv->do_set_mode) {
289+
NL_SET_ERR_MSG(extack,
290+
"Device doesn't support restart from Bus Off");
291+
return -EOPNOTSUPP;
292+
}
293+
288294
/* Do not allow changing restart delay while running */
289295
if (dev->flags & IFF_UP)
290296
return -EBUSY;
291297
priv->restart_ms = nla_get_u32(data[IFLA_CAN_RESTART_MS]);
292298
}
293299

294300
if (data[IFLA_CAN_RESTART]) {
301+
if (!priv->do_set_mode) {
302+
NL_SET_ERR_MSG(extack,
303+
"Device doesn't support restart from Bus Off");
304+
return -EOPNOTSUPP;
305+
}
306+
295307
/* Do not allow a restart while not running */
296308
if (!(dev->flags & IFF_UP))
297309
return -EINVAL;

0 commit comments

Comments
 (0)