mirror of
https://github.com/torvalds/linux.git
synced 2026-06-03 03:53:37 +02:00
linux-can-fixes-for-7.0-20260323
-----BEGIN PGP SIGNATURE----- iIkEABYKADEWIQSl+MghEFFAdY3pYJLMOmT6rpmt0gUCacEVXhMcbWtsQHBlbmd1 dHJvbml4LmRlAAoJEMw6ZPquma3Si58BANpBSZYYe4PcLhowSJdr7KbT3oI3qiZS lnhk+ubPUWOUAQDzugYr+fUM9VHmCh2qCqsjgn83SzggCr110tzZUtRVBw== =VPfS -----END PGP SIGNATURE----- Merge tag 'linux-can-fixes-for-7.0-20260323' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can Marc Kleine-Budde says: ==================== pull-request: can 2026-03-23 this is a pull request of 5 patches for net/main. The first patch is by me and adds missing error handling to the CAN netlink device configuration code. Wenyuan Li contributes a patch for the mcp251x drier to add missing error handling for power enabling in th open and resume functions. Oliver Hartkopp's patch adds missing atomic access in hot path for the CAN procfs statistics. A series by Ali Norouzi and Oliver Hartkopp fix a can-Out-of-Bounds Heap R/W in the can-gw protocol and a UAF in the CAN isotp protocol. linux-can-fixes-for-7.0-20260323 * tag 'linux-can-fixes-for-7.0-20260323' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can: can: isotp: fix tx.buf use-after-free in isotp_sendmsg() can: gw: fix OOB heap access in cgw_csum_crc8_rel() can: statistics: add missing atomic access in hot path can: mcp251x: add error handling for power enable in open and resume can: netlink: can_changelink(): add missing error handling to call can_ctrlmode_changelink() ==================== Link: https://patch.msgid.link/20260323103224.218099-1-mkl@pengutronix.de Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
commit
d9c2a509c9
|
|
@ -601,7 +601,9 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
|
|||
/* We need synchronization with dev->stop() */
|
||||
ASSERT_RTNL();
|
||||
|
||||
can_ctrlmode_changelink(dev, data, extack);
|
||||
err = can_ctrlmode_changelink(dev, data, extack);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (data[IFLA_CAN_BITTIMING]) {
|
||||
struct can_bittiming bt;
|
||||
|
|
|
|||
|
|
@ -1225,7 +1225,11 @@ static int mcp251x_open(struct net_device *net)
|
|||
}
|
||||
|
||||
mutex_lock(&priv->mcp_lock);
|
||||
mcp251x_power_enable(priv->transceiver, 1);
|
||||
ret = mcp251x_power_enable(priv->transceiver, 1);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "failed to enable transceiver power: %pe\n", ERR_PTR(ret));
|
||||
goto out_close_candev;
|
||||
}
|
||||
|
||||
priv->force_quit = 0;
|
||||
priv->tx_skb = NULL;
|
||||
|
|
@ -1272,6 +1276,7 @@ static int mcp251x_open(struct net_device *net)
|
|||
mcp251x_hw_sleep(spi);
|
||||
out_close:
|
||||
mcp251x_power_enable(priv->transceiver, 0);
|
||||
out_close_candev:
|
||||
close_candev(net);
|
||||
mutex_unlock(&priv->mcp_lock);
|
||||
if (release_irq)
|
||||
|
|
@ -1516,11 +1521,25 @@ static int __maybe_unused mcp251x_can_resume(struct device *dev)
|
|||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
struct mcp251x_priv *priv = spi_get_drvdata(spi);
|
||||
int ret = 0;
|
||||
|
||||
if (priv->after_suspend & AFTER_SUSPEND_POWER)
|
||||
mcp251x_power_enable(priv->power, 1);
|
||||
if (priv->after_suspend & AFTER_SUSPEND_UP)
|
||||
mcp251x_power_enable(priv->transceiver, 1);
|
||||
if (priv->after_suspend & AFTER_SUSPEND_POWER) {
|
||||
ret = mcp251x_power_enable(priv->power, 1);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to restore power: %pe\n", ERR_PTR(ret));
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->after_suspend & AFTER_SUSPEND_UP) {
|
||||
ret = mcp251x_power_enable(priv->transceiver, 1);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to restore transceiver power: %pe\n", ERR_PTR(ret));
|
||||
if (priv->after_suspend & AFTER_SUSPEND_POWER)
|
||||
mcp251x_power_enable(priv->power, 0);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->after_suspend & (AFTER_SUSPEND_POWER | AFTER_SUSPEND_UP))
|
||||
queue_work(priv->wq, &priv->restart_work);
|
||||
|
|
|
|||
|
|
@ -469,7 +469,7 @@ int can_rx_register(struct net *net, struct net_device *dev, canid_t can_id,
|
|||
|
||||
rcv->can_id = can_id;
|
||||
rcv->mask = mask;
|
||||
rcv->matches = 0;
|
||||
atomic_long_set(&rcv->matches, 0);
|
||||
rcv->func = func;
|
||||
rcv->data = data;
|
||||
rcv->ident = ident;
|
||||
|
|
@ -573,7 +573,7 @@ EXPORT_SYMBOL(can_rx_unregister);
|
|||
static inline void deliver(struct sk_buff *skb, struct receiver *rcv)
|
||||
{
|
||||
rcv->func(skb, rcv->data);
|
||||
rcv->matches++;
|
||||
atomic_long_inc(&rcv->matches);
|
||||
}
|
||||
|
||||
static int can_rcv_filter(struct can_dev_rcv_lists *dev_rcv_lists, struct sk_buff *skb)
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ struct receiver {
|
|||
struct hlist_node list;
|
||||
canid_t can_id;
|
||||
canid_t mask;
|
||||
unsigned long matches;
|
||||
atomic_long_t matches;
|
||||
void (*func)(struct sk_buff *skb, void *data);
|
||||
void *data;
|
||||
char *ident;
|
||||
|
|
|
|||
|
|
@ -375,10 +375,10 @@ static void cgw_csum_crc8_rel(struct canfd_frame *cf,
|
|||
return;
|
||||
|
||||
if (from <= to) {
|
||||
for (i = crc8->from_idx; i <= crc8->to_idx; i++)
|
||||
for (i = from; i <= to; i++)
|
||||
crc = crc8->crctab[crc ^ cf->data[i]];
|
||||
} else {
|
||||
for (i = crc8->from_idx; i >= crc8->to_idx; i--)
|
||||
for (i = from; i >= to; i--)
|
||||
crc = crc8->crctab[crc ^ cf->data[i]];
|
||||
}
|
||||
|
||||
|
|
@ -397,7 +397,7 @@ static void cgw_csum_crc8_rel(struct canfd_frame *cf,
|
|||
break;
|
||||
}
|
||||
|
||||
cf->data[crc8->result_idx] = crc ^ crc8->final_xor_val;
|
||||
cf->data[res] = crc ^ crc8->final_xor_val;
|
||||
}
|
||||
|
||||
static void cgw_csum_crc8_pos(struct canfd_frame *cf,
|
||||
|
|
|
|||
|
|
@ -1248,12 +1248,6 @@ static int isotp_release(struct socket *sock)
|
|||
so->ifindex = 0;
|
||||
so->bound = 0;
|
||||
|
||||
if (so->rx.buf != so->rx.sbuf)
|
||||
kfree(so->rx.buf);
|
||||
|
||||
if (so->tx.buf != so->tx.sbuf)
|
||||
kfree(so->tx.buf);
|
||||
|
||||
sock_orphan(sk);
|
||||
sock->sk = NULL;
|
||||
|
||||
|
|
@ -1622,6 +1616,21 @@ static int isotp_notifier(struct notifier_block *nb, unsigned long msg,
|
|||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static void isotp_sock_destruct(struct sock *sk)
|
||||
{
|
||||
struct isotp_sock *so = isotp_sk(sk);
|
||||
|
||||
/* do the standard CAN sock destruct work */
|
||||
can_sock_destruct(sk);
|
||||
|
||||
/* free potential extended PDU buffers */
|
||||
if (so->rx.buf != so->rx.sbuf)
|
||||
kfree(so->rx.buf);
|
||||
|
||||
if (so->tx.buf != so->tx.sbuf)
|
||||
kfree(so->tx.buf);
|
||||
}
|
||||
|
||||
static int isotp_init(struct sock *sk)
|
||||
{
|
||||
struct isotp_sock *so = isotp_sk(sk);
|
||||
|
|
@ -1666,6 +1675,9 @@ static int isotp_init(struct sock *sk)
|
|||
list_add_tail(&so->notifier, &isotp_notifier_list);
|
||||
spin_unlock(&isotp_notifier_lock);
|
||||
|
||||
/* re-assign default can_sock_destruct() reference */
|
||||
sk->sk_destruct = isotp_sock_destruct;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -196,7 +196,8 @@ static void can_print_rcvlist(struct seq_file *m, struct hlist_head *rx_list,
|
|||
" %-5s %03x %08x %pK %pK %8ld %s\n";
|
||||
|
||||
seq_printf(m, fmt, DNAME(dev), r->can_id, r->mask,
|
||||
r->func, r->data, r->matches, r->ident);
|
||||
r->func, r->data, atomic_long_read(&r->matches),
|
||||
r->ident);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user