mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
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

      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®