mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: netdev-bot+sashiko@kernel.org
To: liuc63@xiaopeng.com
Cc: m.chetan.kumar@intel.com, loic.poulain@oss.qualcomm.com,
	ryazanov.s.a@gmail.com, johannes@sipsolutions.net,
	zhugl3@xiaopeng.com, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, stable@vger.kernel.org,
	kuba@kernel.org
Subject: Re: [PATCH] net: wwan: iosm: fix NULL skb deref in ul_td_process
Date: Thu, 22 Oct 2026 04:14:45 +0000	[thread overview]
Message-ID: <179264248532.3135.6948322337342491907@kernel.org> (raw)
In-Reply-To: <20261020101150.16967-1-liuc63@xiaopeng.com>

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

Critical: 0 · High: 1 (1) · Medium: 0 · Low: 0

If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).

- [High] The fix does not handle the 'already consumed' case that its
  commit message says it covers.

Pre-existing issues:
- [High] This problem wasn't introduced by this patch, but UL completion
  processing in the IRQ tasklet is not synchronized with pipe teardown.

--

net: wwan: iosm: fix NULL skb deref in ul_td_process

This commit adds a NULL check on the skb taken from the UL ring slot in
ipc_protocol_ul_td_process() before IPC_CB(skb) is dereferenced. The
goal is to avoid a NULL pointer dereference when the slot was never
populated or has already been consumed.

> diff --git a/drivers/net/wwan/iosm/iosm_ipc_protocol_ops.c b/drivers/net/wwan/iosm/iosm_ipc_protocol_ops.c
> index f2f86f41fd10..dee2e6607f77 100644
> --- a/drivers/net/wwan/iosm/iosm_ipc_protocol_ops.c
> +++ b/drivers/net/wwan/iosm/iosm_ipc_protocol_ops.c
> @@ -302,6 +302,11 @@ struct sk_buff *ipc_protocol_ul_td_process(struct iosm_protocol *ipc_protocol,
>  	if (pipe->old_tail >= pipe->nr_of_entries)
>  		pipe->old_tail = 0;
>  
> +	if (!skb) {
> +		dev_err(ipc_protocol->dev, "skb is null");
> +		return NULL;
> +	}
> +

[Severity: High]
Does this check catch the "already consumed" case that the commit message
mentions?

The UL path never resets the ring slot after taking the skb:

drivers/net/wwan/iosm/iosm_ipc_protocol_ops.c:ipc_protocol_ul_td_process() {
	struct ipc_protocol_td *p_td = &pipe->tdr_start[pipe->old_tail];
	struct sk_buff *skb = pipe->skbr_start[pipe->old_tail];

	pipe->nr_of_queued_entries--;
	pipe->old_tail++;
    ...
}

The DL sibling does reset it, so a NULL there really does mean "already
consumed":

drivers/net/wwan/iosm/iosm_ipc_protocol_ops.c:ipc_protocol_dl_td_process() {
    ...
	/* Reset the ring elements. */
	pipe->skbr_start[pipe->old_tail] = NULL;
    ...
}

The only place that writes a UL slot is ipc_protocol_ul_td_send(). It
also sets td->buffer.address = IPC_CB(skb)->mapping, and nothing clears
that field on completion. The caller, ipc_imem_ul_pipe_process(), then
frees each returned skb with ipc_pcie_kfree_skb() or passes it to
ipc_mux_ul_encoded_process().

So a consumed UL slot keeps a stale, non-NULL skb pointer and a non-zero
TD address. If the slot is processed again, the new !skb check passes.
IPC_CB(skb)->mapping is then read from freed memory. If the stale mapping
still matches the stale TD address, the freed skb is returned and freed a
second time.

Slots can be processed again because the loop count in
ipc_imem_ul_pipe_process() comes straight from the device-written tail:

	if (pipe->old_tail != tail) {
		if (pipe->old_tail < tail)
			cnt = tail - pipe->old_tail;
		else
			cnt = pipe->nr_of_entries - pipe->old_tail + tail;
	}

cnt is never checked against nr_of_queued_entries. A misbehaving
endpoint, which is the case this patch is meant to guard against, can
reach this path.

Would it be better to clear pipe->skbr_start[pipe->old_tail] after
reading it, the way the DL path does, and/or to cap cnt by
pipe->nr_of_queued_entries?

[Severity: High]
This is a pre-existing issue and was not introduced by this patch, but
the new check does not protect against it. Is UL completion processing in
the IRQ tasklet synchronized with pipe teardown?

ipc_imem_handle_irq() checks is_open without holding a lock:

	if (ul_pipe->is_open)
		ipc_imem_ul_pipe_process(ipc_imem, ul_pipe);

It then goes on into ipc_protocol_ul_td_process(), which reads
pipe->tdr_start[] and pipe->skbr_start[].

ipc_imem_sys_devlink_close() runs in process context. It waits on
ul_pend_sem with a timeout but never sets app_notify_ul_pend, so the wait
just times out. It then frees the pipes directly:

	ipc_imem_pipe_cleanup(ipc_imem, &channel->ul_pipe);
	ipc_imem_pipe_cleanup(ipc_imem, &channel->dl_pipe);

ipc_protocol_pipe_cleanup() frees the in-flight skbs, kfree()s
skbr_start and dma_free_coherent()s tdr_start. No lock or tasklet
quiescing waits for a tasklet that has already passed the is_open check.

ipc_imem_cleanup() has the same ordering:

	ipc_imem_channel_reset(ipc_imem);

	ipc_protocol_deinit(ipc_imem->ipc_protocol);
	ipc_task_deinit(ipc_imem->ipc_task);

Here the channels are freed before tasklet_kill() in ipc_task_deinit(),
and the IRQ is still live until ipc_pcie_cleanup() runs afterwards.

Can a running tasklet then dereference freed or NULL tdr_start and
skbr_start, or free the same skb that the cleanup loop frees? The local
skb pointer it holds would be non-NULL, so the new !skb check would not
catch it.

>  	if (!p_td->buffer.address) {
>  		dev_err(ipc_protocol->dev, "Td buffer address is NULL");
>  		return NULL;

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261020101150.16967-1-liuc63%40xiaopeng.com

      parent reply	other threads:[~2026-10-22  4:14 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-20 10:11 liuc63
2026-10-20 10:14 ` netdev-bot+sinfo
2026-10-20 10:21 ` Loic Poulain
2026-10-22  4:14 ` netdev-bot+sashiko [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=179264248532.3135.6948322337342491907@kernel.org \
    --to=netdev-bot+sashiko@kernel.org \
    --cc=johannes@sipsolutions.net \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=liuc63@xiaopeng.com \
    --cc=loic.poulain@oss.qualcomm.com \
    --cc=m.chetan.kumar@intel.com \
    --cc=netdev@vger.kernel.org \
    --cc=ryazanov.s.a@gmail.com \
    --cc=stable@vger.kernel.org \
    --cc=zhugl3@xiaopeng.com \
    /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

all inboxes | Powered by JetHome®