From: netdev-bot+sashiko@kernel.org
To: syzbot@kernel.org
Cc: syzkaller-bugs@googlegroups.com, jie.wang@intel.com,
3chas3@gmail.com, accessrunner-general@lists.sourceforge.net,
gregkh@linuxfoundation.org,
linux-atm-general@lists.sourceforge.net,
linux-usb@vger.kernel.org, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org, syzbot@lists.linux.dev,
kuba@kernel.org
Subject: Re: usb: atm: cxacru: fix NULL pointer dereference on uninitialized atm_dev
Date: Wed, 02 Sep 2026 08:42:51 +0000 [thread overview]
Message-ID: <178833857175.3394541.4513055242648047225@kernel.org> (raw)
In-Reply-To: <f3ef0a67-79d7-47da-be6e-7e82d92e68fe@mail.kernel.org>
Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider:
Critical: 0 · High: 1 · Medium: 0 · Low: 0
- [High] Incomplete fix: the new `instance->usbatm->atm_dev == NULL`
guards in adsl_state_store() (drivers/usb/atm/cxacru.c:350) and…
--
usb: atm: cxacru: fix NULL pointer dereference on uninitialized atm_dev
The commit adds a NULL test on instance->usbatm->atm_dev at the entry of
adsl_state_store() and adsl_config_store() in drivers/usb/atm/cxacru.c, so
that a sysfs write arriving before usbatm_do_heavy_init() has registered the
ATM device returns -ENODEV instead of dereferencing atm_dev through
atm_err().
Closes: https://syzkaller.appspot.com/bug?extid=9b195c4f412ea5c4e56a
Link: https://syzkaller.appspot.com/ai_job?id=b6352d63-d03a-4e87-92a4-b334c3ebcf97
> diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
> index 429ac20a8999f..dee15f7b70bf6 100644
> --- a/drivers/usb/atm/cxacru.c
> +++ b/drivers/usb/atm/cxacru.c
> @@ -347,7 +347,7 @@ static ssize_t adsl_state_store(struct device *dev,
> return -EINVAL;
> ret = 0;
>
> - if (instance == NULL)
> + if (instance == NULL || instance->usbatm->atm_dev == NULL)
> return -ENODEV;
>
> if (mutex_lock_interruptible(&instance->adsl_state_serialize))
[Severity: High]
Is this check taken early enough to still be valid at the point where
atm_dev is actually dereferenced?
The test reads instance->usbatm->atm_dev once at handler entry, but the
dereference happens later in atm_err(), which expands through atm_printk()
in drivers/usb/atm/usbatm.h:
#define atm_printk(level, instance, format, arg...) \
printk(level "ATM dev %d: " format , \
(instance)->atm_dev->number , ## arg)
Between the check and that dereference the handler sleeps in
mutex_lock_interruptible(&instance->adsl_state_serialize), then in
cxacru_cm() (which takes cm_serialize and performs a USB control transfer),
and on the "restart" path also in msleep(1500).
Meanwhile usbatm_atm_init() in drivers/usb/atm/usbatm.c publishes atm_dev
before calling atm_start, and clears plus frees it if atm_start fails:
instance->atm_dev = atm_dev;
...
if (instance->driver->atm_start && ((ret = instance->driver->atm_start(instance, atm_dev)) < 0)) {
atm_err(instance, "%s: atm_start failed: %d!\n", __func__, ret);
goto fail;
}
...
fail:
instance->atm_dev = NULL;
atm_dev_deregister(atm_dev); /* usbatm_atm_dev_close will eventually be called */
So a non-NULL atm_dev does not mean initialization completed, and the only
failing leg of cxacru_atm_start() runs before it takes the mutex that
adsl_state_store() uses:
ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_MAC_ADDRESS, NULL, 0,
atm_dev->esi, sizeof(atm_dev->esi));
if (ret < 0) {
atm_err(usbatm_instance, "cxacru_atm_start: CARD_GET_MAC_ADDRESS returned %d\n", ret);
return ret;
}
/* start ADSL */
mutex_lock(&instance->adsl_state_serialize);
With that ordering, can the exact oops quoted in the commit message still
happen? A writer passes the new check while atm_dev is published but
atm_start has not finished, sleeps in cxacru_cm(), the heavy-init kthread
takes the fail path above, and the writer then evaluates:
atm_err(instance->usbatm, "change adsl state:"
" CHIP_ADSL_LINE_STOP returned %d\n", ret);
which is the reported crash site. The CHIP_ADSL_LINE_START error leg is
identical. If the compiler had already loaded the old pointer, is this a
use-after-free instead, given atm_dev_deregister() drops the last reference?
There is a second window of the same shape in usbatm_usb_disconnect():
if (instance->atm_dev) {
atm_dev_deregister(instance->atm_dev);
instance->atm_dev = NULL;
}
Would it be more robust to drop the atm_dev dereference from these paths
altogether, for example by using usb_err()/dev_err() on
instance->usb_intf->dev, which stays valid for the duration of the sysfs
write? Alternatively, re-validating and latching atm_dev under a lock that
usbatm_atm_init()'s failure path also takes, holding a reference on the
atm_dev, or publishing instance->atm_dev only after initialization has fully
succeeded would close the window rather than narrow it.
Related to the same window: adsl_state_store() calls cxacru_poll_status()
after dropping adsl_state_serialize, and that function caches the pointer
with no check of its own:
struct usbatm_data *usbatm = instance->usbatm;
struct atm_dev *atm_dev = usbatm->atm_dev;
and then uses it via atm_warn(), atm_dev->link_rate and
atm_dev_signal_change(). Can that path fault too once atm_dev has been
cleared behind the writer's back?
> @@ -444,7 +444,7 @@ static ssize_t adsl_config_store(struct device *dev,
> if (!capable(CAP_NET_ADMIN))
> return -EACCES;
>
> - if (instance == NULL)
> + if (instance == NULL || instance->usbatm->atm_dev == NULL)
> return -ENODEV;
>
> pos = 0;
[Severity: High]
The same check-then-use concern applies here, and this handler holds no
mutex at all before the sleeping cxacru_cm() transfers inside the
while (pos < len) loop. Both the failure and the success legs dereference
atm_dev after that sleep:
ret = cxacru_cm(instance, CM_REQUEST_CARD_DATA_SET,
(u8 *) data, 4 + num * 8, NULL, 0);
if (ret < 0) {
atm_err(instance->usbatm,
"set card data returned %d\n", ret);
return -EIO;
}
...
atm_info(instance->usbatm, "config%s\n", log);
Since atm_info() expands to the same (instance)->atm_dev->number, does this
mean no command failure is even required to hit the dereference here once
usbatm_atm_init() or usbatm_usb_disconnect() has cleared atm_dev?
Would it make sense to also drop the atm_err()/atm_info() uses in this
function in favour of usb_err()/usb_info() on the USB interface?
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/f3ef0a67-79d7-47da-be6e-7e82d92e68fe%40mail.kernel.org
next prev parent reply other threads:[~2026-09-02 8:42 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-31 14:40 [PATCH] usb: atm: cxacru: fix NULL pointer dereference on uninitialized atm_dev syzbot
2026-09-02 8:42 ` netdev-bot+sashiko [this message]
2026-09-08 15:02 ` [PATCH v2] usb: atm: cxacru: fix NULL deref of atm_dev on sysfs writes Jie Wang
2026-09-10 12:47 ` Greg Kroah-Hartman
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=178833857175.3394541.4513055242648047225@kernel.org \
--to=netdev-bot+sashiko@kernel.org \
--cc=3chas3@gmail.com \
--cc=accessrunner-general@lists.sourceforge.net \
--cc=gregkh@linuxfoundation.org \
--cc=jie.wang@intel.com \
--cc=kuba@kernel.org \
--cc=linux-atm-general@lists.sourceforge.net \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=syzbot@kernel.org \
--cc=syzbot@lists.linux.dev \
--cc=syzkaller-bugs@googlegroups.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 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.