* [PATCH net] net/smc: free stashed qentry before overwrite in REQ_ADD_LINK to ADD_LINK transition
@ 2026-08-18 7:31 Mahanta Jambigi
2026-08-19 7:31 ` sashiko-bot
2026-08-20 21:20 ` patchwork-bot+netdevbpf
0 siblings, 2 replies; 3+ messages in thread
From: Mahanta Jambigi @ 2026-08-18 7:31 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni, alibuda, dust.li,
sidraya
Cc: pasic, horms, tonylu, guwen, netdev, linux-s390, Mahanta Jambigi,
Hidayath Khan
When smc_llc_event_handler() transitions the local LLC flow from
SMC_LLC_FLOW_REQ_ADD_LINK to SMC_LLC_FLOW_ADD_LINK on arrival of an ADD_LINK
request, it calls smc_llc_flow_qentry_set() unconditionally:
if (lgr->llc_flow_lcl.type == SMC_LLC_FLOW_REQ_ADD_LINK) {
lgr->llc_flow_lcl.type = SMC_LLC_FLOW_ADD_LINK;
smc_llc_flow_qentry_set(&lgr->llc_flow_lcl, qentry);
...
}
A CONFIRM_LINK or ADD_LINK_CONT arriving while flow->type is
SMC_LLC_FLOW_REQ_ADD_LINK is stashed into flow->qentry via the
SMC_LLC_CONFIRM_LINK / SMC_LLC_ADD_LINK_CONT handler (which stores into
flow->qentry for any non-NONE flow type). When the subsequent ADD_LINK
arrives, the REQ_ADD_LINK branch overwrites flow->qentry with the new pointer
without first freeing the stashed allocation, leaking one kmalloc object.
The stashed entry has no consumer: smc_llc_wait() is only called from
llc_add_link_work, which is not yet scheduled while the flow type remains
REQ_ADD_LINK. No waiter is sleeping on llc_msg_waiter at this point.
It is safe to unconditionally free any stashed qentry before
the overwrite.
Call smc_llc_flow_qentry_del() before smc_llc_flow_qentry_set() in the
REQ_ADD_LINK branch. smc_llc_flow_qentry_del() already checks flow->qentry
before freeing, so the normal path where no entry is stashed is a no-op.
Fixes: b4ba4652b3f8 ("net/smc: extend LLC layer for SMC-Rv2")
Reviewed-by: Hidayath Khan <hidayath@linux.ibm.com>
Signed-off-by: Mahanta Jambigi <mjambigi@linux.ibm.com>
---
net/smc/smc_llc.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/smc/smc_llc.c b/net/smc/smc_llc.c
index 07e2d7fef7b2..9cc4b3e97699 100644
--- a/net/smc/smc_llc.c
+++ b/net/smc/smc_llc.c
@@ -1911,6 +1911,8 @@ static void smc_llc_event_handler(struct smc_llc_qentry *qentry)
if (lgr->llc_flow_lcl.type ==
SMC_LLC_FLOW_REQ_ADD_LINK) {
/* server started add_link processing */
+ /* free any qentry stashed in REQ_ADD_LINK state */
+ smc_llc_flow_qentry_del(&lgr->llc_flow_lcl);
lgr->llc_flow_lcl.type = SMC_LLC_FLOW_ADD_LINK;
smc_llc_flow_qentry_set(&lgr->llc_flow_lcl,
qentry);
--
2.50.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH net] net/smc: free stashed qentry before overwrite in REQ_ADD_LINK to ADD_LINK transition
2026-08-18 7:31 [PATCH net] net/smc: free stashed qentry before overwrite in REQ_ADD_LINK to ADD_LINK transition Mahanta Jambigi
@ 2026-08-19 7:31 ` sashiko-bot
2026-08-20 21:20 ` patchwork-bot+netdevbpf
1 sibling, 0 replies; 3+ messages in thread
From: sashiko-bot @ 2026-08-19 7:31 UTC (permalink / raw)
To: Mahanta Jambigi
Cc: Heiko Carstens, linux-s390, Alexander Gordeev, Vasily Gorbik,
Christian Borntraeger
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
Pre-existing issues:
- [Critical] Use-After-Free and Out-of-Bounds Read in `smc_llc_srv_add_link()` when accessing the `add_llc` payload.
- [High] `smc_llc_flow_stop()` overwrites `flow->qentry` with `memset`, unconditionally leaking any stashed LLC message.
- [High] Unsynchronized access to `lgr->llc_flow_lcl` across workqueue and tasklet contexts causes data races, leading to memory leaks and NULL pointer dereferences.
--
--- Patch [1]: [PATCH net] net/smc: free stashed qentry before overwrite in REQ_ADD_LINK to ADD_LINK transition ---
commit 5dc4ee5e350906dce47b3e2165e175388d750d51
Author: Mahanta Jambigi <mjambigi@linux.ibm.com>
Subject: net/smc: free stashed qentry before overwrite in REQ_ADD_LINK to ADD_LINK transition
When an ADD_LINK request arrives while the flow is in REQ_ADD_LINK state,
the event handler overwrites flow->qentry without freeing any stashed entry.
This leak is fixed by unconditionally calling smc_llc_flow_qentry_del()
before overwriting the qentry pointer.
> diff --git a/net/smc/smc_llc.c b/net/smc/smc_llc.c
> index aa6d83af55eda..c7f0222aff8d0 100644
> --- a/net/smc/smc_llc.c
> +++ b/net/smc/smc_llc.c
[ ... ]
> @@ -1911,6 +1911,8 @@ static void smc_llc_event_handler(struct smc_llc_qentry *qentry)
> if (lgr->llc_flow_lcl.type ==
> SMC_LLC_FLOW_REQ_ADD_LINK) {
> /* server started add_link processing */
> + /* free any qentry stashed in REQ_ADD_LINK state */
> + smc_llc_flow_qentry_del(&lgr->llc_flow_lcl);
[Severity: High]
This isn't a bug introduced by this patch, but doesn't this unsynchronized
access to lgr->llc_flow_lcl create a data race between workqueue and tasklet
contexts?
In smc_llc_event_handler() (workqueue context), we modify the flow type and
qentry without holding lgr->llc_flow_lock:
smc_llc_flow_qentry_del(&lgr->llc_flow_lcl);
lgr->llc_flow_lcl.type = SMC_LLC_FLOW_ADD_LINK;
smc_llc_flow_qentry_set(&lgr->llc_flow_lcl, qentry);
If a softirq preempts this immediately after we zero qentry and set the type,
smc_llc_rx_response() could locklessly read the type and assign a new response
to the flow:
smc_llc_rx_response() {
...
/* assign responses to the local flow, we requested them */
smc_llc_flow_qentry_set(&link->lgr->llc_flow_lcl, qentry);
...
}
When the workqueue resumes, it would unconditionally overwrite qentry with its
own message, leaking the softirq's qentry. Also, if the type is changed
concurrently, smc_llc_add_link_work() might falsely trigger
smc_llc_flow_stop() mid-flow, zeroing the state and leading to a subsequent
NULL pointer dereference. Could this be prevented by holding the appropriate
locks?
> lgr->llc_flow_lcl.type = SMC_LLC_FLOW_ADD_LINK;
> smc_llc_flow_qentry_set(&lgr->llc_flow_lcl,
> qentry);
[Severity: High]
This is a pre-existing issue, but while we are looking at memory leaks
related to flow->qentry, does smc_llc_flow_stop() also unconditionally leak
any stashed message?
If an incoming message is stashed into lgr->llc_flow_lcl.qentry while the link
group is in the SMC_LLC_FLOW_REQ_ADD_LINK state, and then the remote peer
sends an SMC_LLC_REQ_ADD_LINK response, smc_llc_event_handler() handles it by
calling smc_llc_flow_stop():
smc_llc_event_handler() {
...
case SMC_LLC_REQ_ADD_LINK:
if (lgr->role == SMC_CLNT &&
lgr->llc_flow_lcl.type == SMC_LLC_FLOW_REQ_ADD_LINK &&
(llc->raw.hdr.flags & SMC_LLC_FLAG_RESP)) {
smc_llc_flow_stop(link->lgr, &lgr->llc_flow_lcl);
...
}
smc_llc_flow_stop() then uses memset to clear the flow state:
smc_llc_flow_stop() {
...
memset(flow, 0, sizeof(*flow));
flow->type = SMC_LLC_FLOW_NONE;
...
}
This zero-initializes the struct, silently wiping the flow->qentry pointer
without freeing its dynamically allocated memory. Could this allow a remote
peer to cause memory exhaustion by sending a CONFIRM_LINK message followed
immediately by a REQ_ADD_LINK response?
[Severity: Critical]
This is another pre-existing issue, but does smc_llc_srv_add_link() have a
use-after-free and out-of-bounds read when accessing the add_llc payload?
In smc_llc_srv_add_link(), qentry is retrieved and explicitly freed via
smc_llc_flow_qentry_del():
smc_llc_srv_add_link() {
...
smc_llc_flow_qentry_del(&lgr->llc_flow_lcl);
...
}
Later in the same function, if the connection uses SMC_V2 and the rxbuf is
not shared, add_llc is used as the llc_msg argument:
smc_llc_srv_add_link() {
...
u8 *llc_msg = smc_link_shared_v2_rxbuf(link) ?
(u8 *)lgr->wr_rx_buf_v2 : (u8 *)add_llc;
smc_llc_save_add_link_rkeys(link, link_new, llc_msg);
...
}
Since add_llc is a pointer inside the previously freed qentry, doesn't this
result in reading from a freed memory allocation? Also, because qentry is
allocated with a fixed size of sizeof(*qentry) and does not hold the extended
V2 rkeys, wouldn't this also cause a heap out-of-bounds read past the slab
chunk boundary?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260818073107.466506-1-mjambigi@linux.ibm.com?part=1
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH net] net/smc: free stashed qentry before overwrite in REQ_ADD_LINK to ADD_LINK transition
2026-08-18 7:31 [PATCH net] net/smc: free stashed qentry before overwrite in REQ_ADD_LINK to ADD_LINK transition Mahanta Jambigi
2026-08-19 7:31 ` sashiko-bot
@ 2026-08-20 21:20 ` patchwork-bot+netdevbpf
1 sibling, 0 replies; 3+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-08-20 21:20 UTC (permalink / raw)
To: Mahanta Jambigi
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, alibuda, dust.li,
sidraya, pasic, horms, tonylu, guwen, netdev, linux-s390,
hidayath
Hello:
This patch was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Tue, 18 Aug 2026 09:31:07 +0200 you wrote:
> When smc_llc_event_handler() transitions the local LLC flow from
> SMC_LLC_FLOW_REQ_ADD_LINK to SMC_LLC_FLOW_ADD_LINK on arrival of an ADD_LINK
> request, it calls smc_llc_flow_qentry_set() unconditionally:
>
> if (lgr->llc_flow_lcl.type == SMC_LLC_FLOW_REQ_ADD_LINK) {
> lgr->llc_flow_lcl.type = SMC_LLC_FLOW_ADD_LINK;
> smc_llc_flow_qentry_set(&lgr->llc_flow_lcl, qentry);
> ...
> }
>
> [...]
Here is the summary with links:
- [net] net/smc: free stashed qentry before overwrite in REQ_ADD_LINK to ADD_LINK transition
https://git.kernel.org/netdev/net/c/036322025d6e
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-08-20 21:21 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-18 7:31 [PATCH net] net/smc: free stashed qentry before overwrite in REQ_ADD_LINK to ADD_LINK transition Mahanta Jambigi
2026-08-19 7:31 ` sashiko-bot
2026-08-20 21:20 ` patchwork-bot+netdevbpf
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.