From: netdev-bot+sashiko@kernel.org
To: v3rdant.xiang@gmail.com
Cc: mitch@sfgoth.com, 3chas3@gmail.com, netdev@vger.kernel.org,
davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
pabeni@redhat.com, horms@kernel.org,
linux-atm-general@lists.sourceforge.net,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH net] atm: pppoatm: reject duplicate backend assignment
Date: Sat, 05 Sep 2026 19:46:23 +0000 [thread overview]
Message-ID: <178863758341.219967.1263005070837622760@kernel.org> (raw)
In-Reply-To: <20260902040320.4007552-1-v3rdant.xiang@gmail.com>
Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider:
Critical: 0 · High: 1 · Medium: 0 (1) · Low: 0
- [High] Incomplete fix: the new `if (atmvcc->user_back) return -EBUSY;`
guard in pppoatm_assign_vcc() (net/atm/pppoatm.c:399) only rejects a…
Pre-existing issues:
- [Medium] pppoatm_assign_vcc() publishes the backend with two plain,
unordered stores: `atmvcc->user_back = pvcc;` immediately followed by…
--
atm: pppoatm: reject duplicate backend assignment
This adds a check in pppoatm_assign_vcc() that returns -EBUSY when
atmvcc->user_back is already populated, so a second ATM_SETBACKEND with
ATM_BACKEND_PPP cannot stack a second pppoatm_vcc on the same VCC. The
commit message describes the resulting NULL user_back dereference during
VCC teardown as the bug being fixed.
> diff --git a/net/atm/pppoatm.c b/net/atm/pppoatm.c
> index 6da52d12df68e..93ba22f437bc9 100644
> --- a/net/atm/pppoatm.c
> +++ b/net/atm/pppoatm.c
> @@ -396,6 +396,8 @@ static int pppoatm_assign_vcc(struct atm_vcc *atmvcc, void __user *arg)
> if (be.encaps != PPPOATM_ENCAPS_AUTODETECT &&
> be.encaps != PPPOATM_ENCAPS_VC && be.encaps != PPPOATM_ENCAPS_LLC)
> return -EINVAL;
> + if (atmvcc->user_back)
> + return -EBUSY;
[Severity: High]
Does this guard close the described crash, or only the pppoatm-over-pppoatm
ordering of it? pppoatm is not the only writer of atmvcc->user_back.
br2684_regvcc() in net/atm/br2684.c writes the same field, and its only
ownership checks are:
net/atm/br2684.c:br2684_regvcc() {
...
if (atmvcc->push == NULL) {
err = -EBADFD;
goto error;
}
if (!list_empty(&brdev->brvccs)) {
/* Only 1 VCC/dev right now */
err = -EEXIST;
goto error;
}
...
}
After pppoatm_assign_vcc() has installed pppoatm_push, atmvcc->push is
non-NULL, and a freshly created nas device from ATM_NEWBACKENDIF has an
empty brvccs list, so neither check fires. br2684_regvcc() then does:
net/atm/br2684.c:br2684_regvcc() {
...
atmvcc->user_back = brvcc;
brvcc->encaps = (enum br2684_encaps)be.encaps;
brvcc->old_push = atmvcc->push;
...
}
which overwrites the pppoatm private pointer and chains pppoatm_push as
old_push.
On close, vcc_destroy_socket() calls vcc->push(vcc, NULL) -> br2684_push()
-> br2684_close_vcc():
net/atm/br2684.c:br2684_close_vcc() {
...
brvcc->atmvcc->user_back = NULL; /* what about vcc->recvq ??? */
brvcc->atmvcc->release_cb = brvcc->old_release_cb;
brvcc->old_push(brvcc->atmvcc, NULL); /* pass on the bad news */
...
}
so pppoatm_push() runs with user_back already NULL and dereferences it:
net/atm/pppoatm.c:pppoatm_push() {
...
module = pvcc->old_owner;
pppoatm_unassign_vcc(atmvcc);
...
}
Is that not the same NULL dereference the commit message says is removed,
just with the two ATM_SETBACKEND calls in the opposite order?
While both backends are stacked, can this also corrupt memory? br2684_pop()
calls brvcc->old_pop, which is pppoatm_pop():
net/atm/pppoatm.c:pppoatm_pop() {
struct pppoatm_vcc *pvcc = atmvcc_to_pvcc(atmvcc);
pvcc->old_pop(atmvcc, skb);
atomic_dec(&pvcc->inflight);
...
}
Here user_back points at a struct br2684_vcc, so pvcc->old_pop is an
indirect call through br2684_vcc::old_push and atomic_dec(&pvcc->inflight)
writes into br2684_vcc::old_owner. The same type confusion applies to
br2684_release_cb() -> pppoatm_release_cb(). The first pvcc also stays
registered via ppp_register_channel() with a live tasklet, and its
__module_get(THIS_MODULE) is never balanced, since teardown now runs through
br2684_push().
Regarding this part of the commit message:
do_vcc_ioctl() holds ioctl_mutex while invoking backend handlers, so
concurrent backend assignments cannot race past this check.
Is serialization the relevant property here? do_vcc_ioctl() offers
ATM_SETBACKEND to every registered backend handler with no core-level
"backend already assigned" rejection:
net/atm/ioctl.c:do_vcc_ioctl() {
...
list_for_each(pos, &ioctl_list) {
struct atm_ioctl *ic = list_entry(pos, struct atm_ioctl, list);
if (try_module_get(ic->owner)) {
error = ic->ioctl(sock, cmd, arg);
...
}
so the other writer of user_back runs under the same mutex without any such
guard. Would it make sense to add the same rejection to br2684_regvcc(), or
to do the check once in the shared ATM_SETBACKEND dispatch instead?
> pvcc = kzalloc_obj(*pvcc);
> if (pvcc == NULL)
> return -ENOMEM;
[Severity: Medium]
This isn't a bug introduced by this patch, but since the same field is
involved: is the publication of user_back ordered against the publication of
the push callback? Further down in pppoatm_assign_vcc() the two stores are
plain and adjacent:
net/atm/pppoatm.c:pppoatm_assign_vcc() {
...
atmvcc->user_back = pvcc;
atmvcc->push = pppoatm_push;
atmvcc->pop = pppoatm_pop;
...
}
ATM_SETBACKEND requires sock->state == SS_CONNECTED, and the driver receive
path calls vcc->push(vcc, skb) from softirq context without any lock shared
with do_vcc_ioctl(), which holds only ioctl_mutex. If the store to
atmvcc->push becomes visible first, pppoatm_push() reads user_back as NULL
and dereferences it with no NULL check:
net/atm/pppoatm.c:pppoatm_push() {
struct pppoatm_vcc *pvcc = atmvcc_to_pvcc(atmvcc);
pr_debug("\n");
if (skb == NULL) {
...
module = pvcc->old_owner;
...
switch (pvcc->encaps) {
...
}
The sibling backend orders the same sequence explicitly:
net/atm/br2684.c:br2684_regvcc() {
...
brvcc->old_owner = atmvcc->owner;
barrier();
atmvcc->push = br2684_push;
...
}
Would smp_store_release(&atmvcc->push, pppoatm_push) after user_back is set
be appropriate here?
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260902040320.4007552-1-v3rdant.xiang%40gmail.com
prev parent reply other threads:[~2026-09-05 19:46 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-02 4:03 XingWang Xiang
2026-09-05 19:46 ` 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=178863758341.219967.1263005070837622760@kernel.org \
--to=netdev-bot+sashiko@kernel.org \
--cc=3chas3@gmail.com \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-atm-general@lists.sourceforge.net \
--cc=linux-kernel@vger.kernel.org \
--cc=mitch@sfgoth.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=v3rdant.xiang@gmail.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®