Linux CAN drivers development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Binbin Zhou" <zhoubinbin@loongson.cn>
Cc: "Vincent Mailhol" <mailhol@kernel.org>,
	"Marc Kleine-Budde" <mkl@pengutronix.de>,
	"Oliver Hartkopp" <socketcan@hartkopp.net>,
	"Oleksij Rempel" <o.rempel@pengutronix.de>,
	linux-can@vger.kernel.org
Subject: Re: [PATCH v3 2/2] can: loongson_canfd: Add RXDMA support
Date: Tue, 30 Jun 2026 03:11:19 +0000	[thread overview]
Message-ID: <20260630031120.3D4DB1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <ef3b5ae775bbdb739e70da51d6189b7f2eeef654.1782787997.git.zhoubinbin@loongson.cn>

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

New issues:
- [High] NAPI polling loop reads incomplete CAN frames ahead of the DMA engine, corrupting the ring buffer read pointer.
- [High] DMA initialization failure breaks PIO fallback (hanging RX) and causes double-free on driver removal.

Pre-existing issues:
- [High] Missing bounds check on CAN frame data length allows a heap buffer overflow.
- [High] SKB allocation failure causes permanent NAPI deadlock and RX stream desynchronization.
--

commit 60c5f9dce521c51839cd00b85f3676b903c1d307
Author: Binbin Zhou <zhoubinbin@loongson.cn>

    can: loongson_canfd: Add RXDMA support

    Add optional DMA support for RX path using the Loongson APB CMC DMA
    engine. When a DMA channel is successfully requested, the driver:
    - Uses DMA cyclic transfers to write incoming CAN frames directly to
      a coherent DMA buffer

> diff --git a/drivers/net/can/loongson_canfd.c b/drivers/net/can/loongson_canfd.c
> index 1c7381129c2b6..a4b5d9e506765 100644
> --- a/drivers/net/can/loongson_canfd.c
> +++ b/drivers/net/can/loongson_canfd.c
[ ... ]
> +static void loongson_canfd_rxdma_remove(struct loongson_canfd_priv *priv, struct device *dev)
> +{
> +	if (!priv->rx_ch)
> +		return;
> +
> +	dmaengine_terminate_sync(priv->rx_ch);
> +	loongson_canfd_rxdma_free(priv, dev);
> +	dma_release_channel(priv->rx_ch);
> +}
[ ... ]
> +static bool loongson_canfd_get_rxbuf_empty_in_dma(struct loongson_canfd_priv *priv)
> +{
> +	struct dma_tx_state state;
> +	enum dma_status status;
> +
> +	status = dmaengine_tx_status(priv->rx_ch, priv->rx_ch->cookie, &state);
> +	if (status != DMA_IN_PROGRESS)
> +		return true;
> +
> +	return priv->last_res == (state.residue / DMA_SLAVE_BUSWIDTH_4_BYTES);
> +}

[Severity: High]
Could this implementation cause the CPU to read incomplete frames ahead of the 
DMA engine?

The cyclic DMA engine writes to memory word-by-word. As soon as the DMA 
transfers a single word (like meta0), the residue changes and this function 
returns false.

Because the NAPI loop executing on the CPU is faster than the DMA engine, it 
appears loongson_canfd_rx() will unconditionally read the entire frame 
(including meta1 and data words) before the DMA engine has actually transferred 
them. 

Does this structurally guarantee stream desynchronization and data corruption 
under load?

[ ... ]
> @@ -999,10 +1143,10 @@ static void loongson_canfd_read_rx_frame(struct loongson_canfd_priv *priv, struc
>  
>  	/* Data */
>  	for (i = 0; i < len; i += LOONGSON_CANFD_DW_BYTE)
> -		regmap_read(priv->regmap, LOONGSON_CANFD_RX_DATA, (u32 *)(cf->data + i));
> +		*(u32 *)(cf->data + i) = priv->get_rx_data(priv);
>  
>  	while (unlikely(i < wc * LOONGSON_CANFD_DW_BYTE)) {
> -		regmap_read(priv->regmap, LOONGSON_CANFD_RX_DATA, &data);
> +		priv->get_rx_data(priv);
>  		i += LOONGSON_CANFD_DW_BYTE;
>  	}
>  }

[Severity: High]
This is a pre-existing issue, but is it possible for `len` to exceed the size 
of `cf->data` and cause a heap buffer overflow?

The `cf->data` buffer is a fixed 64-byte array. `len` is calculated based on 
the RWCNT field from meta1, but there appears to be no bounds check verifying 
that `len <= CANFD_MAX_DLEN`. 

If the hardware provides a malformed RWCNT, or if the CPU reads garbage data 
as meta1 (due to the DMA race mentioned above), won't this write past the end 
of the allocated SKB and corrupt the `skb_shared_info` and adjacent heap memory?

[ ... ]
> @@ -1291,12 +1436,11 @@ static int loongson_canfd_rx_napi(struct napi_struct *napi, int quota)
>  	if (rxbuf_is_empty && ret != 0) {
>  		if (napi_complete_done(napi, work_done)) {

[Severity: High]
This isn't a bug introduced by this patch, but what happens if SKB allocation 
fails inside loongson_canfd_rx()?

Looking at loongson_canfd_rx(), if alloc_can_skb() or alloc_canfd_skb() fails 
due to memory exhaustion, it returns 0 immediately without consuming the rest 
of the frame's words:

	if (unlikely(!skb))
		return 0;

This seems to cause two separate issues:
1. It desynchronizes the data stream, as subsequent polls will misinterpret 
   remaining payload words as the headers of the next frame.
2. It breaks the NAPI loop because `ret == 0` causes this completion condition 
   (`rxbuf_is_empty && ret != 0`) to evaluate to false. 

By skipping napi_complete_done() and returning a value less than the quota, the 
NAPI state bit NAPIF_STATE_SCHED remains permanently set but removed from the 
poll list. Doesn't this permanently deadlock the receiver until a module reload?

[ ... ]
> @@ -1646,6 +1791,24 @@ static int loongson_canfd_probe(struct platform_device *pdev)
>  	ndev->ethtool_ops = &loongson_canfd_ethtool_ops;
>  	SET_NETDEV_DEV(ndev, dev);
>  
> +	priv->get_rx_data = loongson_canfd_get_rxdata_in_poll;
> +	priv->get_rxbuf_empty = loongson_canfd_get_rxbuf_empty_in_poll;
> +
> +	priv->rx_ch = dma_request_chan(dev, "rx");
> +	if (PTR_ERR(priv->rx_ch) == -EPROBE_DEFER)
> +		return -EPROBE_DEFER;
> +
> +	if (IS_ERR(priv->rx_ch)) {
> +		dev_warn(dev, "Fall back in poll mode for any non-deferral error.\n");
> +		priv->rx_ch = NULL;
> +	}
> +
> +	ret = loongson_canfd_rxdma_init(ndev);
> +	if (!ret) {
> +		priv->get_rx_data = loongson_canfd_get_rxdata_in_dma;
> +		priv->get_rxbuf_empty = loongson_canfd_get_rxbuf_empty_in_dma;
> +		priv->last_res = LOONGSON_CANFD_RXDMA_NUM;
> +	}
>  	netif_napi_add(ndev, &priv->napi, loongson_canfd_rx_napi);

[Severity: High]
What happens if loongson_canfd_rxdma_init() fails?

If loongson_canfd_rxdma_init() returns an error (e.g., dma_alloc_coherent fails), 
it frees the buffer but does not clear priv->rx_ch or release the channel. The 
probe function ignores the error and proceeds with the intent to fall back to PIO.

However, since priv->rx_ch remains non-NULL, loongson_canfd_chip_start() will 
incorrectly configure the controller to use the DMADI interrupt instead of the 
RBNEI PIO interrupt, permanently breaking reception.

Additionally, upon module removal, loongson_canfd_rxdma_remove() checks 
priv->rx_ch and calls loongson_canfd_rxdma_free() again. Since the buffer was 
already freed during the failed init, won't this trigger a double-free?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1782787997.git.zhoubinbin@loongson.cn?part=2

      reply	other threads:[~2026-06-30  3:11 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-30  3:01 [PATCH v3 0/2] Add Loongson CAN-FD controller driver Binbin Zhou
2026-06-30  3:01 ` [PATCH v3 1/2] can: " Binbin Zhou
2026-06-30  3:16   ` sashiko-bot
2026-06-30  6:51     ` Vincent Mailhol
2026-06-30  3:01 ` [PATCH v3 2/2] can: loongson_canfd: Add RXDMA support Binbin Zhou
2026-06-30  3:11   ` sashiko-bot [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260630031120.3D4DB1F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-can@vger.kernel.org \
    --cc=mailhol@kernel.org \
    --cc=mkl@pengutronix.de \
    --cc=o.rempel@pengutronix.de \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=socketcan@hartkopp.net \
    --cc=zhoubinbin@loongson.cn \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox