From nobody Mon Jun 8 05:24:56 2026 Received: from mail-qv1-f46.google.com (mail-qv1-f46.google.com [209.85.219.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AE47B3D9DDC for ; Mon, 1 Jun 2026 15:43:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780328600; cv=none; b=Y88syXNdTHoVxHpmkOa6h/GID9iVERojQBkxNMbNTWa62fMr24aNQ45s0waD3cFEEtYLAmKanRRh5EloJFCp+YrrWYFTPUn8SPnHN2bzkeOFXJfN3mZY3HH+LBEUtqcOuti8WOr82Y0dnsXpfs5NWa8KU9dfcHlOaBCil5ulr+U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780328600; c=relaxed/simple; bh=gjRGSuHTFaMpWrg/aj9gtDO3Px00ekN2KTlN3bmjMC8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=QUQbhZmn4CaNyec8wpvpR95Kh1ZdKooqmLf6xsSFIV3WxIzM+1V3FZrmW9P0sVx1AecVkuveJsz7WEf+yhhSBqo0RL+KipVYERnyXZnNgS7HiSLAfXVqkPHL1SGTA8kjup+FrfxJHRoxxamqKg0ogH4Ed+30SgiHdO3Mr3Om/Mw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=pbsZmkK3; arc=none smtp.client-ip=209.85.219.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="pbsZmkK3" Received: by mail-qv1-f46.google.com with SMTP id 6a1803df08f44-8ccf7b7d188so23643866d6.1 for ; Mon, 01 Jun 2026 08:43:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1780328598; x=1780933398; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=yNnTDOSD25WnJEqdpyi7uEMknZ0Iy/maLAUEpuwj10s=; b=pbsZmkK3t2XXA4yTICxdttI0BzTWTftw4vaO1qQXEkIOcBo7yJPscFqbL0E9Citovc nTNAQZzKAeN7piNja4rDcyPHC/A8Lbs0usX9zzbbeg+JQXbNkwdUsXPjxbdVzme0f7L0 d8YjEf6rbjKr8Uw5c+KshUQvbxNzZCNnRoPkCE5ZyUv+Nhu7tpoYSMxud+L9j2yWOeQH MXuqQlkkGEFB2xtaz8l3+Wbmf4Rq7MjY+bG2gjeC316ZdszczlQ+2aKZbgXw+Jrkl5Ch 93z4+W6ThDSX/AZ3N0QozY0zf9E810mnDCTGkem14M5rss7WykSWT+ncYRFxq2R8MaBU R/XQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780328598; x=1780933398; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=yNnTDOSD25WnJEqdpyi7uEMknZ0Iy/maLAUEpuwj10s=; b=bq/SUbuXw0Pxpp9EQ3O4GWRO6GAvOwF4aNL85S1xSh0pO3t5sjw6cLY3OnMQEtD3jO sZyASMY1qPxvV7GqOyWKjnxjTK8WAS8eG++OVwTN0O+nkTiyRSYyCKz33OJl1WIRFo+O dY86Um3QiLJve6Un4QZeLey/R2FCEcCNH31cFdqptdmF2hzjb7ZOMXb9XujtMfvEo9eO kvPgaew1GjlmW4UWxdlSJWJvSoX903+hiIDuW+HjhWQg9eDPY0WprTLWMNFq3x+Ctc0Z +dTZLdU8c1m6EY/fOLrc/cG4fAc7P4MNpOgxoSq/ryMWivYwpKnH09YyKKVGO+LuPu34 f24w== X-Forwarded-Encrypted: i=1; AFNElJ+LusffqV+IHQc3F/RC994+ZLzvS2RVztpDHA3FLuzmmEsiUjGBRGtfNOfpJRyQ8JVTxEj+rTYSHPYIMbE=@vger.kernel.org X-Gm-Message-State: AOJu0Yx+8MSVz/ad6pVzx8egp3WVAO0J5WhOIBsqs00UfkvFri7KWC+W kRpqik2V85wtQSpeLe/3/RPDnlhe5eGmSjKofwNKM4JdekvrWvbZlDJk X-Gm-Gg: Acq92OG6WUIgdi6u1k8NUCvMtf/eUnkcLPKAfpqWJYjzj5Y34SGpbVIZUwSWtLSe9En LsnsrGU3DAq2NsiFZfryz0JC71l0QPXl8A3twMzbTEtLAEXzQSYWLENdulrYISh6zqMjgwxsixo uF33TLnUEyrws/FAsvbTYE8wZWOjXvT1FSclL1NZNzzJxyFh22Q1Yqs17eIJTBQdh0a7s0jMIyW d6/OEYKgiS35+t2iR0WOcB2eJzyd3pevBpCqpjXB5AXEAX2s3tf/Pz0R/GtMBEdT+b36TxU4Fjt 3xxQOmoUv2bTrnStpcVTjC3MwIj8Q39yncpCBnKyLxi97h8AN5MgOxwi8WZcCALT2vt2jStkt2H A8R4kKT99jnZXLgcn/8/kEqjB4UhOfObcyj1LiH8PHmy2zIw+lM+9Xn02NgUlvaWY7vJfH0MiGE VTw/VR/yAXhkYLNyQRvC6nzPv00P9I0TAvgixM1DsxgMMZkztY/L6JylDJLwWhUmyr2bNOEaTHa rVW X-Received: by 2002:ad4:5cc9:0:b0:89c:e4c3:dc1a with SMTP id 6a1803df08f44-8ccefb1e7femr207925136d6.1.1780328597571; Mon, 01 Jun 2026 08:43:17 -0700 (PDT) Received: from localhost.localdomain ([2600:4041:42f2:d000:5598:1322:a565:857b]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-8ccea1c384esm95315146d6.28.2026.06.01.08.43.16 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Mon, 01 Jun 2026 08:43:17 -0700 (PDT) From: Rohith Matam To: mchehab@kernel.org Cc: duoming@zju.edu.cn, hverkuil@kernel.org, linux-media@vger.kernel.org, linux-kernel@vger.kernel.org, Rohith Matam , syzbot+0d6ef2b7ceb6014d756c@syzkaller.appspotmail.com Subject: [PATCH v4] media: siano: fix URB work teardown Date: Mon, 1 Jun 2026 11:43:14 -0400 Message-ID: <20260601154314.56784-1-rohithmatham@gmail.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260601152642.55313-1-rohithmatham@gmail.com> References: <20260601152642.55313-1-rohithmatham@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" smsusb_onresponse() reinitializes the URB work item immediately before scheduling it. If teardown races with a queued work item, cancel_work_sync() can observe workqueue state with WORK_STRUCT_PWQ still set and trip the workqueue warning reported by syzbot. The teardown path also has related lifetime bugs. URB_FREE_BUFFER makes USB core free a smscore-owned buffer, and a work item can submit an URB after usb_kill_urb() has already returned. If that submission fails, the worker keeps ownership of the smscore buffer and the streaming pipeline loses an URB. Initialize each work item before any error path can tear down the device, remove URB_FREE_BUFFER, stop resubmission before killing URBs, and kill URBs again after canceling work so any URB submitted by an already-running worker is completed before buffers and the device are freed. Return the smscore buffer if URB submission fails. During teardown, kill all URBs first and return all held buffers before canceling work so a worker blocked in smscore_getbuffer() can make progress and exit. smscore_getbuffer() waits in TASK_UNINTERRUPTIBLE, so return buffers to the pool before waking waiters and use wake_up() instead of wake_up_interruptible(). Fixes: ebad8e731c1c ("media: usb: siano: Fix use after free bugs caused by = do_submit_urb") Reported-by: syzbot+0d6ef2b7ceb6014d756c@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=3D0d6ef2b7ceb6014d756c Signed-off-by: Rohith Matam --- Changes in v4: - During teardown, kill all URBs and return held buffers before canceling workers so smscore_getbuffer() waiters can wake and exit. Changes in v3: - Initialize work items before early probe error paths can call teardown. - Return the smscore buffer when URB submission fails. - Wake buffer waiters after returning the buffer, and use wake_up(). Changes in v2: - Initialize all work items before allocating URBs. - Remove URB_FREE_BUFFER from smscore-owned buffers. - Stop resubmission before teardown and kill URBs again after canceling wor= k. drivers/media/common/siano/smscoreapi.c | 2 +- drivers/media/usb/siano/smsusb.c | 44 ++++++++++++++++++++----- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common= /siano/smscoreapi.c index 017629e3c..e256344eb 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -1654,8 +1654,8 @@ EXPORT_SYMBOL_GPL(smscore_getbuffer); */ void smscore_putbuffer(struct smscore_device_t *coredev, struct smscore_buffer_t *cb) { - wake_up_interruptible(&coredev->buffer_mng_waitq); list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock); + wake_up(&coredev->buffer_mng_waitq); } EXPORT_SYMBOL_GPL(smscore_putbuffer); =20 diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/sms= usb.c index 0fdc2e095..c941a05a4 100644 --- a/drivers/media/usb/siano/smsusb.c +++ b/drivers/media/usb/siano/smsusb.c @@ -58,6 +58,7 @@ struct smsusb_device_t { unsigned char in_ep; unsigned char out_ep; enum smsusb_state state; + bool streaming; }; =20 static int smsusb_submit_urb(struct smsusb_device_t *dev, @@ -71,8 +72,14 @@ static void do_submit_urb(struct work_struct *work) { struct smsusb_urb_t *surb =3D container_of(work, struct smsusb_urb_t, wq); struct smsusb_device_t *dev =3D surb->dev; + int rc; =20 - smsusb_submit_urb(dev, surb); + if (!READ_ONCE(dev->streaming)) + return; + + rc =3D smsusb_submit_urb(dev, surb); + if (rc < 0 && READ_ONCE(dev->streaming)) + pr_err("smsusb_submit_urb(...) failed\n"); } =20 /* @@ -143,13 +150,15 @@ static void smsusb_onresponse(struct urb *urb) =20 =20 exit_and_resubmit: - INIT_WORK(&surb->wq, do_submit_urb); - schedule_work(&surb->wq); + if (READ_ONCE(dev->streaming)) + schedule_work(&surb->wq); } =20 static int smsusb_submit_urb(struct smsusb_device_t *dev, struct smsusb_urb_t *surb) { + int rc; + if (!surb->cb) { /* This function can sleep */ surb->cb =3D smscore_getbuffer(dev->coredev); @@ -168,31 +177,44 @@ static int smsusb_submit_urb(struct smsusb_device_t *= dev, smsusb_onresponse, surb ); - surb->urb->transfer_flags |=3D URB_FREE_BUFFER; + rc =3D usb_submit_urb(surb->urb, GFP_ATOMIC); + if (rc) { + smscore_putbuffer(dev->coredev, surb->cb); + surb->cb =3D NULL; + } =20 - return usb_submit_urb(surb->urb, GFP_ATOMIC); + return rc; } =20 static void smsusb_stop_streaming(struct smsusb_device_t *dev) { int i; =20 - for (i =3D 0; i < MAX_URBS; i++) { + WRITE_ONCE(dev->streaming, false); + + for (i =3D 0; i < MAX_URBS; i++) usb_kill_urb(dev->surbs[i].urb); - if (dev->surbs[i].wq.func) - cancel_work_sync(&dev->surbs[i].wq); =20 + for (i =3D 0; i < MAX_URBS; i++) { if (dev->surbs[i].cb) { smscore_putbuffer(dev->coredev, dev->surbs[i].cb); dev->surbs[i].cb =3D NULL; } } + + for (i =3D 0; i < MAX_URBS; i++) + cancel_work_sync(&dev->surbs[i].wq); + + for (i =3D 0; i < MAX_URBS; i++) + usb_kill_urb(dev->surbs[i].urb); } =20 static int smsusb_start_streaming(struct smsusb_device_t *dev) { int i, rc; =20 + WRITE_ONCE(dev->streaming, true); + for (i =3D 0; i < MAX_URBS; i++) { rc =3D smsusb_submit_urb(dev, &dev->surbs[i]); if (rc < 0) { @@ -401,6 +423,11 @@ static int smsusb_init_device(struct usb_interface *in= tf, int board_id) if (!dev) return -ENOMEM; =20 + for (i =3D 0; i < MAX_URBS; i++) { + dev->surbs[i].dev =3D dev; + INIT_WORK(&dev->surbs[i].wq, do_submit_urb); + } + memset(¶ms, 0, sizeof(params)); usb_set_intfdata(intf, dev); dev->udev =3D interface_to_usbdev(intf); @@ -467,7 +494,6 @@ static int smsusb_init_device(struct usb_interface *int= f, int board_id) =20 /* initialize urbs */ for (i =3D 0; i < MAX_URBS; i++) { - dev->surbs[i].dev =3D dev; dev->surbs[i].urb =3D usb_alloc_urb(0, GFP_KERNEL); if (!dev->surbs[i].urb) goto err_unregister_device; --=20 2.54.0