linux-can-fixes-for-5.10-20201115

-----BEGIN PGP SIGNATURE-----
 
 iQFHBAABCgAxFiEEK3kIWJt9yTYMP3ehqclaivrt76kFAl+xZoMTHG1rbEBwZW5n
 dXRyb25peC5kZQAKCRCpyVqK+u3vqX8lB/4gQq9MTczYjSxVGgqaEyToftX7rokl
 EiP6RcpXKvAY8p0IJHEWHeCGOqsD5am4xo6M/Z5nMAinBdywweSvQRdU8ZDdCb84
 AxJEbrkU7JTNqHbQnLp3wzl5sHPAwvRavf9plFwnPosMM2nS0HcPnjaj9kgO3cLI
 E/fMa+WmPwDjMEIBM2TJCgFh9pH5Fs8I3SRHC/TUYwigXKVtgIuIm1o6t4evBk9w
 zBW+5HX++r2FSt0164vVZyBCOCK/z2tEMCEO8l3mrUKdjBy3jAFqXfWxcQbaFy8f
 Oy8Nx1vgNZYVH7RqYJ6JuQO6/wQIPAWb6KOgDrDWaM6jl3ZdA7/gBdiR
 =Ed6S
 -----END PGP SIGNATURE-----

Merge tag 'linux-can-fixes-for-5.10-20201115' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can

Marc Kleine-Budde says:

====================
pull-request: can 2020-11-15

Anant Thazhemadam contributed two patches for the AF_CAN that prevent potential
access of uninitialized member in can_rcv() and canfd_rcv().

The next patch is by Alejandro Concepcion Rodriguez and changes can_restart()
to use the correct function to push a skb into the networking stack from
process context.

Zhang Qilong's patch fixes a memory leak in the error path of the ti_hecc's
probe function.

A patch by me fixes mcba_usb_start_xmit() function in the mcba_usb driver, to
first fill the skb and then pass it to can_put_echo_skb().

Colin Ian King's patch fixes a potential integer overflow on shift in the
peak_usb driver.

The next two patches target the flexcan driver, a patch by me adds the missing
"req_bit" to the stop mode property comment (which was broken during net-next
for v5.10). Zhang Qilong's patch fixes the failure handling of
pm_runtime_get_sync().

The next seven patches target the m_can driver including the tcan4x5x spi
driver glue code. Enric Balletbo i Serra's patch for the tcan4x5x Kconfig fix
the REGMAP_SPI dependency handling. A patch by me for the tcan4x5x driver's
probe() function adds missing error handling to for devm_regmap_init(), and in
tcan4x5x_can_remove() the order of deregistration is fixed. Wu Bo's patch for
the m_can driver fixes the state change handling in
m_can_handle_state_change(). Two patches by Dan Murphy first introduce
m_can_class_free_dev() and then make use of it to fix the freeing of the can
device. A patch by Faiz Abbas add a missing shutdown of the CAN controller in
the m_can_stop() function.

* tag 'linux-can-fixes-for-5.10-20201115' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can:
  can: m_can: m_can_stop(): set device to software init mode before closing
  can: m_can: Fix freeing of can device from peripherials
  can: m_can: m_can_class_free_dev(): introduce new function
  can: m_can: m_can_handle_state_change(): fix state change
  can: tcan4x5x: tcan4x5x_can_remove(): fix order of deregistration
  can: tcan4x5x: tcan4x5x_can_probe(): add missing error checking for devm_regmap_init()
  can: tcan4x5x: replace depends on REGMAP_SPI with depends on SPI
  can: flexcan: fix failure handling of pm_runtime_get_sync()
  can: flexcan: flexcan_setup_stop_mode(): add missing "req_bit" to stop mode property comment
  can: peak_usb: fix potential integer overflow on shift of a int
  can: mcba_usb: mcba_usb_start_xmit(): first fill skb, then pass to can_put_echo_skb()
  can: ti_hecc: Fix memleak in ti_hecc_probe
  can: dev: can_restart(): post buffer from the right context
  can: af_can: prevent potential access of uninitialized member in canfd_rcv()
  can: af_can: prevent potential access of uninitialized member in can_rcv()
====================

Link: https://lore.kernel.org/r/20201115174131.2089251-1-mkl@pengutronix.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2020-11-16 07:34:30 -08:00
commit e2142ef266
11 changed files with 100 additions and 46 deletions

View File

@ -592,7 +592,7 @@ static void can_restart(struct net_device *dev)
cf->can_id |= CAN_ERR_RESTARTED;
netif_rx(skb);
netif_rx_ni(skb);
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;

View File

@ -728,8 +728,10 @@ static int flexcan_get_berr_counter(const struct net_device *dev,
int err;
err = pm_runtime_get_sync(priv->dev);
if (err < 0)
if (err < 0) {
pm_runtime_put_noidle(priv->dev);
return err;
}
err = __flexcan_get_berr_counter(dev, bec);
@ -1654,8 +1656,10 @@ static int flexcan_open(struct net_device *dev)
}
err = pm_runtime_get_sync(priv->dev);
if (err < 0)
if (err < 0) {
pm_runtime_put_noidle(priv->dev);
return err;
}
err = open_candev(dev);
if (err)
@ -1852,7 +1856,7 @@ static int flexcan_setup_stop_mode(struct platform_device *pdev)
return -EINVAL;
/* stop mode property format is:
* <&gpr req_gpr>.
* <&gpr req_gpr req_bit>.
*/
ret = of_property_read_u32_array(np, "fsl,stop-mode", out_val,
ARRAY_SIZE(out_val));

View File

@ -16,7 +16,8 @@ config CAN_M_CAN_PLATFORM
config CAN_M_CAN_TCAN4X5X
depends on CAN_M_CAN
depends on REGMAP_SPI
depends on SPI
select REGMAP_SPI
tristate "TCAN4X5X M_CAN device"
help
Say Y here if you want support for Texas Instruments TCAN4x5x

View File

@ -665,7 +665,7 @@ static int m_can_handle_state_change(struct net_device *dev,
unsigned int ecr;
switch (new_state) {
case CAN_STATE_ERROR_ACTIVE:
case CAN_STATE_ERROR_WARNING:
/* error warning state */
cdev->can.can_stats.error_warning++;
cdev->can.state = CAN_STATE_ERROR_WARNING;
@ -694,7 +694,7 @@ static int m_can_handle_state_change(struct net_device *dev,
__m_can_get_berr_counter(dev, &bec);
switch (new_state) {
case CAN_STATE_ERROR_ACTIVE:
case CAN_STATE_ERROR_WARNING:
/* error warning state */
cf->can_id |= CAN_ERR_CRTL;
cf->data[1] = (bec.txerr > bec.rxerr) ?
@ -1414,6 +1414,9 @@ static void m_can_stop(struct net_device *dev)
/* disable all interrupts */
m_can_disable_all_interrupts(cdev);
/* Set init mode to disengage from the network */
m_can_config_endisable(cdev, true);
/* set the state as STOPPED */
cdev->can.state = CAN_STATE_STOPPED;
}
@ -1812,6 +1815,12 @@ struct m_can_classdev *m_can_class_allocate_dev(struct device *dev)
}
EXPORT_SYMBOL_GPL(m_can_class_allocate_dev);
void m_can_class_free_dev(struct net_device *net)
{
free_candev(net);
}
EXPORT_SYMBOL_GPL(m_can_class_free_dev);
int m_can_class_register(struct m_can_classdev *m_can_dev)
{
int ret;
@ -1850,7 +1859,6 @@ int m_can_class_register(struct m_can_classdev *m_can_dev)
if (ret) {
if (m_can_dev->pm_clock_support)
pm_runtime_disable(m_can_dev->dev);
free_candev(m_can_dev->net);
}
return ret;
@ -1908,8 +1916,6 @@ void m_can_class_unregister(struct m_can_classdev *m_can_dev)
unregister_candev(m_can_dev->net);
m_can_clk_stop(m_can_dev);
free_candev(m_can_dev->net);
}
EXPORT_SYMBOL_GPL(m_can_class_unregister);

View File

@ -99,6 +99,7 @@ struct m_can_classdev {
};
struct m_can_classdev *m_can_class_allocate_dev(struct device *dev);
void m_can_class_free_dev(struct net_device *net);
int m_can_class_register(struct m_can_classdev *cdev);
void m_can_class_unregister(struct m_can_classdev *cdev);
int m_can_class_get_clocks(struct m_can_classdev *cdev);

View File

@ -67,32 +67,36 @@ static int m_can_plat_probe(struct platform_device *pdev)
return -ENOMEM;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
if (!priv) {
ret = -ENOMEM;
goto probe_fail;
}
mcan_class->device_data = priv;
m_can_class_get_clocks(mcan_class);
ret = m_can_class_get_clocks(mcan_class);
if (ret)
goto probe_fail;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "m_can");
addr = devm_ioremap_resource(&pdev->dev, res);
irq = platform_get_irq_byname(pdev, "int0");
if (IS_ERR(addr) || irq < 0) {
ret = -EINVAL;
goto failed_ret;
goto probe_fail;
}
/* message ram could be shared */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "message_ram");
if (!res) {
ret = -ENODEV;
goto failed_ret;
goto probe_fail;
}
mram_addr = devm_ioremap(&pdev->dev, res->start, resource_size(res));
if (!mram_addr) {
ret = -ENOMEM;
goto failed_ret;
goto probe_fail;
}
priv->base = addr;
@ -111,9 +115,10 @@ static int m_can_plat_probe(struct platform_device *pdev)
m_can_init_ram(mcan_class);
ret = m_can_class_register(mcan_class);
return m_can_class_register(mcan_class);
failed_ret:
probe_fail:
m_can_class_free_dev(mcan_class->net);
return ret;
}
@ -134,6 +139,8 @@ static int m_can_plat_remove(struct platform_device *pdev)
m_can_class_unregister(mcan_class);
m_can_class_free_dev(mcan_class->net);
platform_set_drvdata(pdev, NULL);
return 0;

View File

@ -440,14 +440,18 @@ static int tcan4x5x_can_probe(struct spi_device *spi)
return -ENOMEM;
priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
if (!priv) {
ret = -ENOMEM;
goto out_m_can_class_free_dev;
}
priv->power = devm_regulator_get_optional(&spi->dev, "vsup");
if (PTR_ERR(priv->power) == -EPROBE_DEFER)
return -EPROBE_DEFER;
else
if (PTR_ERR(priv->power) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
goto out_m_can_class_free_dev;
} else {
priv->power = NULL;
}
mcan_class->device_data = priv;
@ -460,8 +464,10 @@ static int tcan4x5x_can_probe(struct spi_device *spi)
}
/* Sanity check */
if (freq < 20000000 || freq > TCAN4X5X_EXT_CLK_DEF)
return -ERANGE;
if (freq < 20000000 || freq > TCAN4X5X_EXT_CLK_DEF) {
ret = -ERANGE;
goto out_m_can_class_free_dev;
}
priv->reg_offset = TCAN4X5X_MCAN_OFFSET;
priv->mram_start = TCAN4X5X_MRAM_START;
@ -487,6 +493,10 @@ static int tcan4x5x_can_probe(struct spi_device *spi)
priv->regmap = devm_regmap_init(&spi->dev, &tcan4x5x_bus,
&spi->dev, &tcan4x5x_regmap);
if (IS_ERR(priv->regmap)) {
ret = PTR_ERR(priv->regmap);
goto out_clk;
}
ret = tcan4x5x_power_enable(priv->power, 1);
if (ret)
@ -514,8 +524,10 @@ static int tcan4x5x_can_probe(struct spi_device *spi)
clk_disable_unprepare(mcan_class->cclk);
clk_disable_unprepare(mcan_class->hclk);
}
out_m_can_class_free_dev:
m_can_class_free_dev(mcan_class->net);
dev_err(&spi->dev, "Probe failed, err=%d\n", ret);
return ret;
}
@ -523,9 +535,11 @@ static int tcan4x5x_can_remove(struct spi_device *spi)
{
struct tcan4x5x_priv *priv = spi_get_drvdata(spi);
m_can_class_unregister(priv->mcan_dev);
tcan4x5x_power_enable(priv->power, 0);
m_can_class_unregister(priv->mcan_dev);
m_can_class_free_dev(priv->mcan_dev->net);
return 0;
}

View File

@ -881,7 +881,8 @@ static int ti_hecc_probe(struct platform_device *pdev)
priv->base = devm_platform_ioremap_resource_byname(pdev, "hecc");
if (IS_ERR(priv->base)) {
dev_err(&pdev->dev, "hecc ioremap failed\n");
return PTR_ERR(priv->base);
err = PTR_ERR(priv->base);
goto probe_exit_candev;
}
/* handle hecc-ram memory */
@ -889,20 +890,22 @@ static int ti_hecc_probe(struct platform_device *pdev)
"hecc-ram");
if (IS_ERR(priv->hecc_ram)) {
dev_err(&pdev->dev, "hecc-ram ioremap failed\n");
return PTR_ERR(priv->hecc_ram);
err = PTR_ERR(priv->hecc_ram);
goto probe_exit_candev;
}
/* handle mbx memory */
priv->mbx = devm_platform_ioremap_resource_byname(pdev, "mbx");
if (IS_ERR(priv->mbx)) {
dev_err(&pdev->dev, "mbx ioremap failed\n");
return PTR_ERR(priv->mbx);
err = PTR_ERR(priv->mbx);
goto probe_exit_candev;
}
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!irq) {
dev_err(&pdev->dev, "No irq resource\n");
goto probe_exit;
goto probe_exit_candev;
}
priv->ndev = ndev;
@ -966,7 +969,7 @@ static int ti_hecc_probe(struct platform_device *pdev)
clk_put(priv->clk);
probe_exit_candev:
free_candev(ndev);
probe_exit:
return err;
}

View File

@ -326,8 +326,6 @@ static netdev_tx_t mcba_usb_start_xmit(struct sk_buff *skb,
if (!ctx)
return NETDEV_TX_BUSY;
can_put_echo_skb(skb, priv->netdev, ctx->ndx);
if (cf->can_id & CAN_EFF_FLAG) {
/* SIDH | SIDL | EIDH | EIDL
* 28 - 21 | 20 19 18 x x x 17 16 | 15 - 8 | 7 - 0
@ -357,6 +355,8 @@ static netdev_tx_t mcba_usb_start_xmit(struct sk_buff *skb,
if (cf->can_id & CAN_RTR_FLAG)
usb_msg.dlc |= MCBA_DLC_RTR_MASK;
can_put_echo_skb(skb, priv->netdev, ctx->ndx);
err = mcba_usb_xmit(priv, (struct mcba_usb_msg *)&usb_msg, ctx);
if (err)
goto xmit_failed;

View File

@ -156,7 +156,7 @@ void peak_usb_get_ts_time(struct peak_time_ref *time_ref, u32 ts, ktime_t *time)
if (time_ref->ts_dev_1 < time_ref->ts_dev_2) {
/* case when event time (tsw) wraps */
if (ts < time_ref->ts_dev_1)
delta_ts = 1 << time_ref->adapter->ts_used_bits;
delta_ts = BIT_ULL(time_ref->adapter->ts_used_bits);
/* Otherwise, sync time counter (ts_dev_2) has wrapped:
* handle case when event time (tsn) hasn't.
@ -168,7 +168,7 @@ void peak_usb_get_ts_time(struct peak_time_ref *time_ref, u32 ts, ktime_t *time)
* tsn ts
*/
} else if (time_ref->ts_dev_1 < ts) {
delta_ts = -(1 << time_ref->adapter->ts_used_bits);
delta_ts = -BIT_ULL(time_ref->adapter->ts_used_bits);
}
/* add delay between last sync and event timestamps */

View File

@ -677,16 +677,25 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev,
{
struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
if (unlikely(dev->type != ARPHRD_CAN || skb->len != CAN_MTU ||
cfd->len > CAN_MAX_DLEN)) {
pr_warn_once("PF_CAN: dropped non conform CAN skbuf: dev type %d, len %d, datalen %d\n",
if (unlikely(dev->type != ARPHRD_CAN || skb->len != CAN_MTU)) {
pr_warn_once("PF_CAN: dropped non conform CAN skbuff: dev type %d, len %d\n",
dev->type, skb->len);
goto free_skb;
}
/* This check is made separately since cfd->len would be uninitialized if skb->len = 0. */
if (unlikely(cfd->len > CAN_MAX_DLEN)) {
pr_warn_once("PF_CAN: dropped non conform CAN skbuff: dev type %d, len %d, datalen %d\n",
dev->type, skb->len, cfd->len);
kfree_skb(skb);
return NET_RX_DROP;
goto free_skb;
}
can_receive(skb, dev);
return NET_RX_SUCCESS;
free_skb:
kfree_skb(skb);
return NET_RX_DROP;
}
static int canfd_rcv(struct sk_buff *skb, struct net_device *dev,
@ -694,16 +703,25 @@ static int canfd_rcv(struct sk_buff *skb, struct net_device *dev,
{
struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
if (unlikely(dev->type != ARPHRD_CAN || skb->len != CANFD_MTU ||
cfd->len > CANFD_MAX_DLEN)) {
pr_warn_once("PF_CAN: dropped non conform CAN FD skbuf: dev type %d, len %d, datalen %d\n",
if (unlikely(dev->type != ARPHRD_CAN || skb->len != CANFD_MTU)) {
pr_warn_once("PF_CAN: dropped non conform CAN FD skbuff: dev type %d, len %d\n",
dev->type, skb->len);
goto free_skb;
}
/* This check is made separately since cfd->len would be uninitialized if skb->len = 0. */
if (unlikely(cfd->len > CANFD_MAX_DLEN)) {
pr_warn_once("PF_CAN: dropped non conform CAN FD skbuff: dev type %d, len %d, datalen %d\n",
dev->type, skb->len, cfd->len);
kfree_skb(skb);
return NET_RX_DROP;
goto free_skb;
}
can_receive(skb, dev);
return NET_RX_SUCCESS;
free_skb:
kfree_skb(skb);
return NET_RX_DROP;
}
/* af_can protocol functions */