In nfcmrvl_probe(), the driver calls nfcmrvl_nci_register_dev(), which
creates and registers the NCI device via nci_register_device(). Once
registered, the device is immediately exposed to userspace, which can bring
the interface up via netlink. When the interface is opened,
nfcmrvl_usb_nci_open() submits bulk RX URBs. However, nfcmrvl_probe()
assigns drv_data->priv = priv only after nfcmrvl_nci_register_dev()
returns. If an URB completes before drv_data->priv is assigned, the
completion handler nfcmrvl_bulk_complete() dereferences drv_data->priv
(which is still NULL) when allocating an skb, triggering a general
protection fault.
Additionally, nfcmrvl_bulk_complete() and nfcmrvl_resume() checked
test_bit(NFCMRVL_NCI_RUNNING, &drv_data->flags) instead of &priv->flags.
Since NFCMRVL_NCI_RUNNING and NFCMRVL_USB_BULK_RUNNING both share the value
1, this inadvertently tested drv_data->flags for NFCMRVL_USB_BULK_RUNNING,
masking the issue on the first URB completion while failing on subsequent
completions.
KASAN report:
Oops: general protection fault, probably for non-canonical address
0xdffffc0000000004: 0000 [#1] SMP KASAN NOPTI
KASAN: null-ptr-deref in range [0x0000000000000020-0x0000000000000027]
RIP: 0010:nfcmrvl_bulk_complete+0x107/0x600 drivers/nfc/nfcmrvl/usb.c:71
Call Trace:
__usb_hcd_giveback_urb+0x374/0x530 drivers/usb/core/hcd.c:1657
dummy_timer+0xa91/0x4cf0 drivers/usb/gadget/udc/dummy_hcd.c:2019
__run_hrtimer kernel/time/hrtimer.c:2032 [inline]
__hrtimer_run_queues+0x3bc/0xa10 kernel/time/hrtimer.c:2096
hrtimer_run_softirq+0x17a/0x240 kernel/time/hrtimer.c:2113
handle_softirqs+0x225/0x840 kernel/softirq.c:622
Fix this by passing priv as the URB context in nfcmrvl_submit_bulk_urb()
and retrieving priv directly from urb->context in nfcmrvl_bulk_complete().
Because priv is already initialized and valid when nfcmrvl_usb_nci_open()
is called, this removes the reliance on drv_data->priv. Also, update
nfcmrvl_bulk_complete() and nfcmrvl_resume() to test NFCMRVL_NCI_RUNNING
against priv->flags.
Fixes: f26e30cc6b50 ("NFC: nfcmrvl: Initial commit for Marvell NFC driver")
Assisted-by: Gemini:gemini-3.7-flash Gemini:gemini-3.1-pro-preview syzbot
Reported-by: syzbot+59d5e6a8ed04e6a000c8@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=59d5e6a8ed04e6a000c8
Link: https://syzkaller.appspot.com/ai_job?id=cf4896f2-e0ed-48cf-888c-6677fdcd9ee8
To: "David Heidelberg"
To:
To: "Amitkumar Karwar"
Cc: "Bartosz Golaszewski"
Cc: "Johan Hovold"
Cc: "Jakub Kicinski"
Cc: "Linus Walleij"
Cc:
Cc: "Jialu Xu"
---
diff --git a/drivers/nfc/nfcmrvl/usb.c b/drivers/nfc/nfcmrvl/usb.c
index 4babde8e4..ca20030bd 100644
--- a/drivers/nfc/nfcmrvl/usb.c
+++ b/drivers/nfc/nfcmrvl/usb.c
@@ -56,26 +56,27 @@ static int nfcmrvl_inc_tx(struct nfcmrvl_usb_drv_data *drv_data)
static void nfcmrvl_bulk_complete(struct urb *urb)
{
- struct nfcmrvl_usb_drv_data *drv_data = urb->context;
+ struct nfcmrvl_private *priv = urb->context;
+ struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data;
int err;
dev_dbg(&drv_data->udev->dev, "urb %p status %d count %d\n",
urb, urb->status, urb->actual_length);
- if (!test_bit(NFCMRVL_NCI_RUNNING, &drv_data->flags))
+ if (!test_bit(NFCMRVL_NCI_RUNNING, &priv->flags))
return;
if (!urb->status) {
struct sk_buff *skb;
- skb = nci_skb_alloc(drv_data->priv->ndev, urb->actual_length,
+ skb = nci_skb_alloc(priv->ndev, urb->actual_length,
GFP_ATOMIC);
if (!skb) {
nfc_err(&drv_data->udev->dev, "failed to alloc mem\n");
} else {
skb_put_data(skb, urb->transfer_buffer,
urb->actual_length);
- if (nfcmrvl_nci_recv_frame(drv_data->priv, skb) < 0)
+ if (nfcmrvl_nci_recv_frame(priv, skb) < 0)
nfc_err(&drv_data->udev->dev,
"corrupted Rx packet\n");
}
@@ -100,8 +101,9 @@ static void nfcmrvl_bulk_complete(struct urb *urb)
}
static int
-nfcmrvl_submit_bulk_urb(struct nfcmrvl_usb_drv_data *drv_data, gfp_t mem_flags)
+nfcmrvl_submit_bulk_urb(struct nfcmrvl_private *priv, gfp_t mem_flags)
{
+ struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data;
struct urb *urb;
unsigned char *buf;
unsigned int pipe;
@@ -124,7 +126,7 @@ nfcmrvl_submit_bulk_urb(struct nfcmrvl_usb_drv_data *drv_data, gfp_t mem_flags)
drv_data->bulk_rx_ep->bEndpointAddress);
usb_fill_bulk_urb(urb, drv_data->udev, pipe, buf, size,
- nfcmrvl_bulk_complete, drv_data);
+ nfcmrvl_bulk_complete, priv);
urb->transfer_flags |= URB_FREE_BUFFER;
@@ -174,12 +176,12 @@ static int nfcmrvl_usb_nci_open(struct nfcmrvl_private *priv)
drv_data->intf->needs_remote_wakeup = 1;
- err = nfcmrvl_submit_bulk_urb(drv_data, GFP_KERNEL);
+ err = nfcmrvl_submit_bulk_urb(priv, GFP_KERNEL);
if (err)
goto failed;
set_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags);
- nfcmrvl_submit_bulk_urb(drv_data, GFP_KERNEL);
+ nfcmrvl_submit_bulk_urb(priv, GFP_KERNEL);
usb_autopm_put_interface(drv_data->intf);
return 0;
@@ -400,6 +402,7 @@ static void nfcmrvl_play_deferred(struct nfcmrvl_usb_drv_data *drv_data)
static int nfcmrvl_resume(struct usb_interface *intf)
{
struct nfcmrvl_usb_drv_data *drv_data = usb_get_intfdata(intf);
+ struct nfcmrvl_private *priv = drv_data->priv;
int err = 0;
nfc_info(&drv_data->udev->dev, "intf %p\n", intf);
@@ -407,17 +410,17 @@ static int nfcmrvl_resume(struct usb_interface *intf)
if (--drv_data->suspend_count)
return 0;
- if (!test_bit(NFCMRVL_NCI_RUNNING, &drv_data->flags))
+ if (!test_bit(NFCMRVL_NCI_RUNNING, &priv->flags))
goto done;
if (test_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags)) {
- err = nfcmrvl_submit_bulk_urb(drv_data, GFP_NOIO);
+ err = nfcmrvl_submit_bulk_urb(priv, GFP_NOIO);
if (err) {
clear_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags);
goto failed;
}
- nfcmrvl_submit_bulk_urb(drv_data, GFP_NOIO);
+ nfcmrvl_submit_bulk_urb(priv, GFP_NOIO);
}
spin_lock_irq(&drv_data->txlock);
base-commit: 8d3ae59288f1e7d58d76558a6ee96d533bc5019f
--
This is an AI-generated patch subject to moderation.
Reply with '#syz upstream' to Sign-off the patch as a human author
and send it to the upstream kernel mailing lists.
Reply with '#syz reject' to reject it ('#syz unreject' to undo).
See https://goo.gle/syzbot-ai-patches for information about AI-generated patches.
You can comment on the patch as usual, syzbot will try to address
the comments and send a new version of the patch if necessary.
syzbot engineers can be reached at syzkaller@googlegroups.com.