From nobody Sat Sep 26 07:15:22 2026 Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.223.131]) (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 B65B94BD115; Thu, 3 Sep 2026 14:57:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=195.135.223.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788447430; cv=none; b=IozB91HA4Qq5GEie16UG3g0tipAWpa8mGXSv3ud0N/NJyBznQms71Gb+4/D7m45BMXkGaBsrFNjjKuUKt7YabXi/nuoa5In1QSA4u6U1zXhnlpDPBOGIe+yc0I6qXmuI3t8c1/sNkaOBfXY1ym2mCFmYr9z1doGzRWS38dmL9hk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788447430; c=relaxed/simple; bh=17RZR2ZTMt59sbwE6Mx8M/WpENZsr6g+2QL+Zhn3GOM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=mek6AjzwMbwMjER5ZpVJf/3vjhaUdZrOt8QXeAkzBCK03siOAwqlOacOXBmFrx68D7MSFTlAbR2FG2r1E9VLZ/EZ08HNDv1tUqvXSHiLJn73RRAaQzQd0DaZ0yPub8j6nyF9dGyePEn6qEbEUHgW9xtJXCj3cVhVGTr88xd8eHg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=suse.de; spf=pass smtp.mailfrom=suse.de; dkim=pass (1024-bit key) header.d=suse.de header.i=@suse.de header.b=AWc+4ITF; dkim=permerror (0-bit key) header.d=suse.de header.i=@suse.de header.b=I9drJdpc; dkim=pass (1024-bit key) header.d=suse.de header.i=@suse.de header.b=vDOJZMwN; dkim=permerror (0-bit key) header.d=suse.de header.i=@suse.de header.b=JmBvoe7Y; arc=none smtp.client-ip=195.135.223.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=suse.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=suse.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=suse.de header.i=@suse.de header.b="AWc+4ITF"; dkim=permerror (0-bit key) header.d=suse.de header.i=@suse.de header.b="I9drJdpc"; dkim=pass (1024-bit key) header.d=suse.de header.i=@suse.de header.b="vDOJZMwN"; dkim=permerror (0-bit key) header.d=suse.de header.i=@suse.de header.b="JmBvoe7Y" Received: from imap1.dmz-prg2.suse.org (unknown [10.150.64.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 5D56A1FE2B; Thu, 3 Sep 2026 14:56:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1788447422; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=DpFSt+M0gpbm3frk/kVuPHJG1gAoCphQnHc2kyplzUU=; b=AWc+4ITF7cpc7pIZF3F6zOvXYZd9EsQqxV0o5DWWMO8xXqEv78b18Gxpb++qktnQ4u8ZW7 iTOJr9lTghAw1qdTG7EFZH+UvRWJGb5DUwnMNLX4t9TJOxaJsnnfq077RXBjrYrYjpU3NC hFv6E+h6ovShBbK2vyrl58kgbFr4XWU= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1788447422; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=DpFSt+M0gpbm3frk/kVuPHJG1gAoCphQnHc2kyplzUU=; b=I9drJdpcBTWUvXz/U/GbeNHF7mFxP4QBvNMav9O0w6dJyubeQdI9jCtIYl3VGxFml/if30 yIBYqD9AmWHgdUAg== Authentication-Results: smtp-out2.suse.de; none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1788447418; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=DpFSt+M0gpbm3frk/kVuPHJG1gAoCphQnHc2kyplzUU=; b=vDOJZMwNm5sHJXosIMKSMttTLTJDY12zqczSl0BICF/1hG6zEU3Q1GDml99XtD84H85FHm odBE/bDwaAv+L6CkV51WtkPvKxDJmugCe9tstZOBJINL1NRim6Hpf8hb/mTkrV+SMVppdH khBtunLVjHFJvie44X1GQxezE8EMacI= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1788447418; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=DpFSt+M0gpbm3frk/kVuPHJG1gAoCphQnHc2kyplzUU=; b=JmBvoe7YcRcK+zRHl43IGiGdHbq7EWHW2KKTvq+YmBKVrRRcY9DFdech0YMmJSQ8KCG+mO +KKf0/bD0DivgpAg== Received: from imap1.dmz-prg2.suse.org (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by imap1.dmz-prg2.suse.org (Postfix) with ESMTPS id 25EEC136E6; Thu, 3 Sep 2026 14:56:58 +0000 (UTC) Received: from dovecot-director2.suse.de ([2a07:de40:b281:106:10:150:64:167]) by imap1.dmz-prg2.suse.org with ESMTPSA id +D4gCLqKmWo6MQAAD6G6ig (envelope-from ); Thu, 03 Sep 2026 14:56:58 +0000 From: Takashi Iwai To: linux-sound@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Michal Pecio Subject: [PATCH 1/3] ALSA: usb: ua101: Avoid embedded URBs Date: Thu, 3 Sep 2026 16:56:43 +0200 Message-ID: <20260903145648.1914352-2-tiwai@suse.de> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260903145648.1914352-1-tiwai@suse.de> References: <20260903145648.1914352-1-tiwai@suse.de> 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 X-Spam-Level: X-Spam-Score: -2.80 X-Spam-Flag: NO X-Spamd-Result: default: False [-2.80 / 50.00]; BAYES_HAM(-3.00)[100.00%]; MID_CONTAINS_FROM(1.00)[]; NEURAL_HAM_LONG(-1.00)[-1.000]; R_MISSING_CHARSET(0.50)[]; NEURAL_HAM_SHORT(-0.20)[-0.999]; MIME_GOOD(-0.10)[text/plain]; TO_MATCH_ENVRCPT_ALL(0.00)[]; ARC_NA(0.00)[]; RCVD_VIA_SMTP_AUTH(0.00)[]; FREEMAIL_CC(0.00)[vger.kernel.org,gmail.com]; TO_DN_SOME(0.00)[]; MIME_TRACE(0.00)[0:+]; DBL_BLOCKED_OPENRESOLVER(0.00)[suse.de:email,suse.de:mid,imap1.dmz-prg2.suse.org:helo]; TAGGED_RCPT(0.00)[]; FROM_HAS_DN(0.00)[]; RCVD_COUNT_TWO(0.00)[2]; RCVD_TLS_ALL(0.00)[]; FROM_EQ_ENVFROM(0.00)[]; RCPT_COUNT_THREE(0.00)[3]; DKIM_SIGNED(0.00)[suse.de:s=susede2_rsa,suse.de:s=susede2_ed25519]; FREEMAIL_ENVRCPT(0.00)[gmail.com] Content-Type: text/plain; charset="utf-8" UA101 driver uses URBs embedded in struct ua101, and this is basically a buggy implementation nowadays; since a URB is managed with a refcount, this may lead to a UAF when the URB is released asynchronously. For addressing the problem, this patch converts the embedded URBs to ones that are properly allocated via usb_alloc_urb(). The iso_frame_desc[] is gone, as it's allocated together by usb_alloc_urb(). Along with the dynamic allocation of each URB, the ua101.urbs[] becomes a static array of struct ua101_urb, and struct ua101_urb contains the pointer to struct ua101. Those are needed to handle the ready_list linked list in the complete callback. No functional changes, only compile-tested. Link: https://lore.kernel.org/20260903130757.0668310a.michal.pecio@gmail.com Signed-off-by: Takashi Iwai --- sound/usb/misc/ua101.c | 102 ++++++++++++++++++++++------------------- 1 file changed, 54 insertions(+), 48 deletions(-) diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c index b9a62e94e06c..860a62a3d74b 100644 --- a/sound/usb/misc/ua101.c +++ b/sound/usb/misc/ua101.c @@ -109,10 +109,10 @@ struct ua101 { unsigned int buffer_pos; unsigned int queue_length; struct ua101_urb { - struct urb urb; - struct usb_iso_packet_descriptor iso_frame_desc[1]; + struct urb *urb; struct list_head ready_list; - } *urbs[MAX_QUEUE_LENGTH]; + struct ua101 *ua; + } urbs[MAX_QUEUE_LENGTH]; struct { unsigned int size; void *addr; @@ -167,15 +167,15 @@ static void abort_usb_playback(struct ua101 *ua) wake_up(&ua->alsa_playback_wait); } =20 -static void playback_urb_complete(struct urb *usb_urb) +static void playback_urb_complete(struct urb *urb) { - struct ua101_urb *urb =3D (struct ua101_urb *)usb_urb; - struct ua101 *ua =3D urb->urb.context; + struct ua101_urb *ua_urb =3D urb->context; + struct ua101 *ua =3D ua_urb->ua; =20 - if (unlikely(urb->urb.status =3D=3D -ENOENT || /* unlinked */ - urb->urb.status =3D=3D -ENODEV || /* device removed */ - urb->urb.status =3D=3D -ECONNRESET || /* unlinked */ - urb->urb.status =3D=3D -ESHUTDOWN)) { /* device disabled */ + if (unlikely(urb->status =3D=3D -ENOENT || /* unlinked */ + urb->status =3D=3D -ENODEV || /* device removed */ + urb->status =3D=3D -ECONNRESET || /* unlinked */ + urb->status =3D=3D -ESHUTDOWN)) { /* device disabled */ abort_usb_playback(ua); abort_alsa_playback(ua); return; @@ -184,18 +184,19 @@ static void playback_urb_complete(struct urb *usb_urb) if (test_bit(USB_PLAYBACK_RUNNING, &ua->states)) { /* append URB to FIFO */ guard(spinlock_irqsave)(&ua->lock); - list_add_tail(&urb->ready_list, &ua->ready_playback_urbs); + list_add_tail(&ua_urb->ready_list, &ua->ready_playback_urbs); if (ua->rate_feedback_count > 0) queue_work(system_highpri_wq, &ua->playback_work); ua->playback.substream->runtime->delay -=3D - urb->urb.iso_frame_desc[0].length / + urb->iso_frame_desc[0].length / ua->playback.frame_bytes; } } =20 static void first_playback_urb_complete(struct urb *urb) { - struct ua101 *ua =3D urb->context; + struct ua101_urb *ua_urb =3D urb->context; + struct ua101 *ua =3D ua_urb->ua; =20 urb->complete =3D playback_urb_complete; playback_urb_complete(urb); @@ -248,7 +249,8 @@ static void playback_work(struct work_struct *work) { struct ua101 *ua =3D container_of(work, struct ua101, playback_work); unsigned int frames; - struct ua101_urb *urb; + struct ua101_urb *ua_urb; + struct urb *urb; bool do_period_elapsed =3D false; int err; =20 @@ -275,23 +277,24 @@ static void playback_work(struct work_struct *work) ua->rate_feedback_count--; =20 /* take URB out of FIFO */ - urb =3D list_first_entry(&ua->ready_playback_urbs, - struct ua101_urb, ready_list); - list_del(&urb->ready_list); + ua_urb =3D list_first_entry(&ua->ready_playback_urbs, + struct ua101_urb, ready_list); + list_del(&ua_urb->ready_list); + urb =3D ua_urb->urb; =20 /* fill packet with data or silence */ - urb->urb.iso_frame_desc[0].length =3D + urb->iso_frame_desc[0].length =3D frames * ua->playback.frame_bytes; if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states)) do_period_elapsed |=3D copy_playback_data(&ua->playback, - &urb->urb, + urb, frames); else - memset(urb->urb.transfer_buffer, 0, - urb->urb.iso_frame_desc[0].length); + memset(urb->transfer_buffer, 0, + urb->iso_frame_desc[0].length); =20 /* and off you go ... */ - err =3D usb_submit_urb(&urb->urb, GFP_ATOMIC); + err =3D usb_submit_urb(urb, GFP_ATOMIC); if (unlikely(err < 0)) { abort_usb_playback(ua); abort_alsa_playback(ua); @@ -342,7 +345,8 @@ static bool copy_capture_data(struct ua101_stream *stre= am, struct urb *urb, =20 static void capture_urb_complete(struct urb *urb) { - struct ua101 *ua =3D urb->context; + struct ua101_urb *ua_urb =3D urb->context; + struct ua101 *ua =3D ua_urb->ua; struct ua101_stream *stream =3D &ua->capture; unsigned int frames, write_ptr; bool do_period_elapsed; @@ -413,7 +417,8 @@ static void capture_urb_complete(struct urb *urb) =20 static void first_capture_urb_complete(struct urb *urb) { - struct ua101 *ua =3D urb->context; + struct ua101_urb *ua_urb =3D urb->context; + struct ua101 *ua =3D ua_urb->ua; =20 urb->complete =3D capture_urb_complete; capture_urb_complete(urb); @@ -427,7 +432,7 @@ static int submit_stream_urbs(struct ua101 *ua, struct = ua101_stream *stream) unsigned int i; =20 for (i =3D 0; i < stream->queue_length; ++i) { - int err =3D usb_submit_urb(&stream->urbs[i]->urb, GFP_KERNEL); + int err =3D usb_submit_urb(stream->urbs[i].urb, GFP_KERNEL); if (err < 0) { dev_err(&ua->dev->dev, "USB request error %d: %s\n", err, usb_error_string(err)); @@ -442,8 +447,8 @@ static void kill_stream_urbs(struct ua101_stream *strea= m) unsigned int i; =20 for (i =3D 0; i < stream->queue_length; ++i) - if (stream->urbs[i]) - usb_kill_urb(&stream->urbs[i]->urb); + if (stream->urbs[i].urb) + usb_kill_urb(stream->urbs[i].urb); } =20 static int enable_iso_interface(struct ua101 *ua, unsigned int intf_index) @@ -508,7 +513,7 @@ static int start_usb_capture(struct ua101 *ua) return err; =20 clear_bit(CAPTURE_URB_COMPLETED, &ua->states); - ua->capture.urbs[0]->urb.complete =3D first_capture_urb_complete; + ua->capture.urbs[0].urb->complete =3D first_capture_urb_complete; ua->rate_feedback_start =3D 0; ua->rate_feedback_count =3D 0; =20 @@ -550,7 +555,7 @@ static int start_usb_playback(struct ua101 *ua) return err; =20 clear_bit(PLAYBACK_URB_COMPLETED, &ua->states); - ua->playback.urbs[0]->urb.complete =3D + ua->playback.urbs[0].urb->complete =3D first_playback_urb_complete; scoped_guard(spinlock_irq, &ua->lock) { INIT_LIST_HEAD(&ua->ready_playback_urbs); @@ -580,7 +585,7 @@ static int start_usb_playback(struct ua101 *ua) add_with_wraparound(ua, &ua->rate_feedback_start, 1); ua->rate_feedback_count--; } - urb =3D &ua->playback.urbs[i]->urb; + urb =3D ua->playback.urbs[i].urb; urb->iso_frame_desc[0].length =3D frames * ua->playback.frame_bytes; memset(urb->transfer_buffer, 0, @@ -1059,7 +1064,7 @@ static int alloc_stream_urbs(struct ua101 *ua, struct= ua101_stream *stream, void (*urb_complete)(struct urb *)) { unsigned max_packet_size =3D stream->max_packet_bytes; - struct ua101_urb *urb; + struct urb *urb; unsigned int b, u =3D 0; =20 for (b =3D 0; b < ARRAY_SIZE(stream->buffers); ++b) { @@ -1070,23 +1075,24 @@ static int alloc_stream_urbs(struct ua101 *ua, stru= ct ua101_stream *stream, while (size >=3D max_packet_size) { if (u >=3D stream->queue_length) goto bufsize_error; - urb =3D kmalloc_obj(*urb); + urb =3D usb_alloc_urb(1, GFP_KERNEL); if (!urb) return -ENOMEM; - usb_init_urb(&urb->urb); - urb->urb.dev =3D ua->dev; - urb->urb.pipe =3D stream->usb_pipe; - urb->urb.transfer_flags =3D URB_NO_TRANSFER_DMA_MAP; - urb->urb.transfer_buffer =3D addr; - urb->urb.transfer_dma =3D dma; - urb->urb.transfer_buffer_length =3D max_packet_size; - urb->urb.number_of_packets =3D 1; - urb->urb.interval =3D 1; - urb->urb.context =3D ua; - urb->urb.complete =3D urb_complete; - urb->urb.iso_frame_desc[0].offset =3D 0; - urb->urb.iso_frame_desc[0].length =3D max_packet_size; - stream->urbs[u++] =3D urb; + urb->dev =3D ua->dev; + urb->pipe =3D stream->usb_pipe; + urb->transfer_flags =3D URB_NO_TRANSFER_DMA_MAP; + urb->transfer_buffer =3D addr; + urb->transfer_dma =3D dma; + urb->transfer_buffer_length =3D max_packet_size; + urb->number_of_packets =3D 1; + urb->interval =3D 1; + urb->context =3D &stream->urbs[u]; + urb->complete =3D urb_complete; + urb->iso_frame_desc[0].offset =3D 0; + urb->iso_frame_desc[0].length =3D max_packet_size; + stream->urbs[u].ua =3D ua; + stream->urbs[u].urb =3D urb; + u++; size -=3D max_packet_size; addr +=3D max_packet_size; dma +=3D max_packet_size; @@ -1104,8 +1110,8 @@ static void free_stream_urbs(struct ua101_stream *str= eam) unsigned int i; =20 for (i =3D 0; i < stream->queue_length; ++i) { - kfree(stream->urbs[i]); - stream->urbs[i] =3D NULL; + usb_free_urb(stream->urbs[i].urb); + stream->urbs[i].urb =3D NULL; } } =20 --=20 2.55.0 From nobody Sat Sep 26 07:15:22 2026 Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.223.130]) (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 B66744BD119; Thu, 3 Sep 2026 14:57:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=195.135.223.130 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788447430; cv=none; b=rJ5qX2fgDWgP7H/jriA260OWWg3vnEfwscVzFGl5TUWilJzDiFrYCB1BEXWrw+/ZAewvdzI6roBpST8gMf2209odpGu7SJYWnunZ560LMun7yLui+ctK05VCKtuj2zwzKJM4ss3bwbkBeFCBeTBsf+DNLlTsnsGcp8iajJZq9sQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788447430; c=relaxed/simple; bh=qQdKwx47al/8YO6tail6zzQgg1sONfu8PfjJaiR4eLs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Xn69oC/WjFVnGMQs7CRr8Dd/IYUtgf9v1WCFh+Npo5tBldj2r2N15qFAB+54P8ltKJ+mV+HT83iKuOzVeY90Mbhv76xJBTVqBbwnKW4xHd7pH7++q1DEtds6x5MdmpkPDkc/DmVZDv1poabXDw0dKBYE5UOS+u4NvOxWPiKLIoo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=suse.de; spf=pass smtp.mailfrom=suse.de; dkim=pass (1024-bit key) header.d=suse.de header.i=@suse.de header.b=qRlqXN1E; dkim=permerror (0-bit key) header.d=suse.de header.i=@suse.de header.b=aLt1uW69; dkim=pass (1024-bit key) header.d=suse.de header.i=@suse.de header.b=Qo8t/bLz; dkim=permerror (0-bit key) header.d=suse.de header.i=@suse.de header.b=TFfhuXBq; arc=none smtp.client-ip=195.135.223.130 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=suse.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=suse.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=suse.de header.i=@suse.de header.b="qRlqXN1E"; dkim=permerror (0-bit key) header.d=suse.de header.i=@suse.de header.b="aLt1uW69"; dkim=pass (1024-bit key) header.d=suse.de header.i=@suse.de header.b="Qo8t/bLz"; dkim=permerror (0-bit key) header.d=suse.de header.i=@suse.de header.b="TFfhuXBq" Received: from imap1.dmz-prg2.suse.org (imap1.dmz-prg2.suse.org [IPv6:2a07:de40:b281:104:10:150:64:97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id 8947621EC5; Thu, 3 Sep 2026 14:56:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1788447422; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=QrNdELoVcr9YF74ohv2KVf3Smb1p8aaziHH2zBLwcyc=; b=qRlqXN1Eovnq/zB8TdzH+EIv0LxRJO6obulMW+OupDLWSOxdghKKFtOBmmPWRhIEUv2hMa YjmX27nMmEpWy/6mDLSDf6xxbV/gwupdes3D+bLitQ4P4PhibQnEJCIv4ksiGfU0+7zCW1 wMW0DWU3QOcq4WWryUuKjLGh8E2VXVM= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1788447422; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=QrNdELoVcr9YF74ohv2KVf3Smb1p8aaziHH2zBLwcyc=; b=aLt1uW69VBmiyA8iK//Cg2lUrlAmA9IfvBzWahLw1ZWLFvVHEyiba8Z+kvdtK6iNlOdaf/ YI13LnmO9+tFRQBg== Authentication-Results: smtp-out1.suse.de; dkim=pass header.d=suse.de header.s=susede2_rsa header.b="Qo8t/bLz"; dkim=pass header.d=suse.de header.s=susede2_ed25519 header.b=TFfhuXBq DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1788447418; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=QrNdELoVcr9YF74ohv2KVf3Smb1p8aaziHH2zBLwcyc=; b=Qo8t/bLzTyv6L9x9t/icdl9JuAkp8sSUjGw8IUTSV53YdR6rmv3HVj+YWmxzHgTHWyLLTK eSu95ZkNzp5vzKN7cpFJn3Ti4Qr9yUEAVJri51Ca2HdjJTg5cwsISvBdYXGoGB1k44r3mF 26w4fAhkuLOJASWdbioL7OhyN44Z3yw= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1788447418; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=QrNdELoVcr9YF74ohv2KVf3Smb1p8aaziHH2zBLwcyc=; b=TFfhuXBqO8B2lC7/f1+Rz0UAs5AkMBisXXlOW9O0LuiXRjoHoqeHx6rVhcNN4P5P+W8imc b9/p+35lGCKLa0Bg== Received: from imap1.dmz-prg2.suse.org (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by imap1.dmz-prg2.suse.org (Postfix) with ESMTPS id 4D45813738; Thu, 3 Sep 2026 14:56:58 +0000 (UTC) Received: from dovecot-director2.suse.de ([2a07:de40:b281:106:10:150:64:167]) by imap1.dmz-prg2.suse.org with ESMTPSA id WNK0EbqKmWo6MQAAD6G6ig (envelope-from ); Thu, 03 Sep 2026 14:56:58 +0000 From: Takashi Iwai To: linux-sound@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Michal Pecio Subject: [PATCH 2/3] ALSA: usb: hiface: Avoid embedded URBs Date: Thu, 3 Sep 2026 16:56:44 +0200 Message-ID: <20260903145648.1914352-3-tiwai@suse.de> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260903145648.1914352-1-tiwai@suse.de> References: <20260903145648.1914352-1-tiwai@suse.de> 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 X-Spam-Score: -3.01 X-Rspamd-Queue-Id: 8947621EC5 X-Rspamd-Server: rspamd1.dmz-prg2.suse.org X-Spam-Level: X-Rspamd-Action: no action X-Spamd-Result: default: False [-3.01 / 50.00]; BAYES_HAM(-3.00)[100.00%]; NEURAL_HAM_LONG(-1.00)[-1.000]; MID_CONTAINS_FROM(1.00)[]; R_MISSING_CHARSET(0.50)[]; R_DKIM_ALLOW(-0.20)[suse.de:s=susede2_rsa,suse.de:s=susede2_ed25519]; NEURAL_HAM_SHORT(-0.20)[-1.000]; MIME_GOOD(-0.10)[text/plain]; MX_GOOD(-0.01)[]; RCVD_VIA_SMTP_AUTH(0.00)[]; ARC_NA(0.00)[]; RCVD_COUNT_TWO(0.00)[2]; MIME_TRACE(0.00)[0:+]; FREEMAIL_CC(0.00)[vger.kernel.org,gmail.com]; SPAMHAUS_XBL(0.00)[2a07:de40:b281:104:10:150:64:97:from]; TO_DN_SOME(0.00)[]; TAGGED_RCPT(0.00)[]; RCVD_TLS_ALL(0.00)[]; DBL_BLOCKED_OPENRESOLVER(0.00)[suse.de:dkim,suse.de:email,suse.de:mid,imap1.dmz-prg2.suse.org:helo,imap1.dmz-prg2.suse.org:rdns]; TO_MATCH_ENVRCPT_ALL(0.00)[]; FROM_EQ_ENVFROM(0.00)[]; FREEMAIL_ENVRCPT(0.00)[gmail.com]; FROM_HAS_DN(0.00)[]; RCPT_COUNT_THREE(0.00)[3]; DKIM_SIGNED(0.00)[suse.de:s=susede2_rsa,suse.de:s=susede2_ed25519]; DKIM_TRACE(0.00)[suse.de:+] X-Spam-Flag: NO Content-Type: text/plain; charset="utf-8" The hiface driver uses URBs embedded in struct pcm_urb, and this is basically a buggy implementation nowadays; since a URB is managed with a refcount, this may lead to a UAF when the URB is released asynchronously. For addressing the problem, this patch converts the embedded URBs to ones that are properly allocated via usb_alloc_urb(). The conversion is rather straightforward; pcm_urb.instance became a pointer, assigned/freed via usb_alloc_urb() and usb_free_urb(), and the call with this is corrected accordingly. No functional changes, only compile-tested. Link: https://lore.kernel.org/20260903130757.0668310a.michal.pecio@gmail.com Signed-off-by: Takashi Iwai --- sound/usb/hiface/pcm.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/sound/usb/hiface/pcm.c b/sound/usb/hiface/pcm.c index cd1a4c871c5d..9571c9eabd57 100644 --- a/sound/usb/hiface/pcm.c +++ b/sound/usb/hiface/pcm.c @@ -24,7 +24,7 @@ struct pcm_urb { struct hiface_chip *chip; =20 - struct urb instance; + struct urb *instance; struct usb_anchor submitted; u8 *buffer; }; @@ -193,7 +193,7 @@ static void hiface_pcm_stream_stop(struct pcm_runtime *= rt) if (!time) usb_kill_anchored_urbs( &rt->out_urbs[i].submitted); - usb_kill_urb(&rt->out_urbs[i].instance); + usb_kill_urb(rt->out_urbs[i].instance); } =20 rt->stream_state =3D STREAM_DISABLED; @@ -215,9 +215,9 @@ static int hiface_pcm_stream_start(struct pcm_runtime *= rt) rt->stream_state =3D STREAM_STARTING; for (i =3D 0; i < PCM_N_URBS; i++) { memset(rt->out_urbs[i].buffer, 0, PCM_PACKET_SIZE); - usb_anchor_urb(&rt->out_urbs[i].instance, + usb_anchor_urb(rt->out_urbs[i].instance, &rt->out_urbs[i].submitted); - ret =3D usb_submit_urb(&rt->out_urbs[i].instance, + ret =3D usb_submit_urb(rt->out_urbs[i].instance, GFP_ATOMIC); if (ret) { hiface_pcm_stream_stop(rt); @@ -334,7 +334,7 @@ static void hiface_pcm_out_urb_handler(struct urb *usb_= urb) if (do_period_elapsed) snd_pcm_period_elapsed(sub->instance); =20 - ret =3D usb_submit_urb(&out_urb->instance, GFP_ATOMIC); + ret =3D usb_submit_urb(out_urb->instance, GFP_ATOMIC); if (ret < 0) goto out_fail; =20 @@ -492,16 +492,18 @@ static int hiface_pcm_init_urb(struct pcm_urb *urb, void (*handler)(struct urb *)) { urb->chip =3D chip; - usb_init_urb(&urb->instance); + urb->instance =3D usb_alloc_urb(0, GFP_KERNEL); + if (!urb->instance) + return -ENOMEM; =20 urb->buffer =3D kzalloc(PCM_PACKET_SIZE, GFP_KERNEL); if (!urb->buffer) return -ENOMEM; =20 - usb_fill_bulk_urb(&urb->instance, chip->dev, + usb_fill_bulk_urb(urb->instance, chip->dev, usb_sndbulkpipe(chip->dev, ep), (void *)urb->buffer, PCM_PACKET_SIZE, handler, urb); - if (usb_urb_ep_type_check(&urb->instance)) + if (usb_urb_ep_type_check(urb->instance)) return -EINVAL; init_usb_anchor(&urb->submitted); =20 @@ -525,8 +527,10 @@ static void hiface_pcm_destroy(struct hiface_chip *chi= p) struct pcm_runtime *rt =3D chip->pcm; int i; =20 - for (i =3D 0; i < PCM_N_URBS; i++) + for (i =3D 0; i < PCM_N_URBS; i++) { + usb_free_urb(rt->out_urbs[i].instance); kfree(rt->out_urbs[i].buffer); + } =20 kfree(chip->pcm); chip->pcm =3D NULL; --=20 2.55.0 From nobody Sat Sep 26 07:15:22 2026 Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.223.130]) (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 87C3D4BD109; Thu, 3 Sep 2026 14:57:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=195.135.223.130 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788447432; cv=none; b=j248OlJsm7+RS2FiTO8TiLNv6Y7jvUWxAjc+yaBT7FKNn9m44vgbDaeOOQ+PiQjCuz8uwthWTu+kfX1gNz+3L4Om2HO4s/LaIUXrTsYmPwYrDCQteKJNWYiNU3WWY4w40YmWT0WlUwLxPOCs4lsJ1fXYtz3/DYWx1rU1yyunQw0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788447432; c=relaxed/simple; bh=GDa3uB0fkXXrQgDiPTKMksox3GMZrL1iToldyS3dAEE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=rhXWd5TmqZr/GoVrfnFaNAAvp/rhi20LcDEH7hWEq+HJ0M7Hn0k1nGp/4OPrbpriqHyOWaQ+ABnp1LMVC2WP4bOLVNnbKzsfXtaSwXVV1nnIsSQMZkwU/AhD6EX7G4l/z6TMsZlPP5wOGoyPs9gYfwd8s8zyRoDA7pglfGy+EkU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=suse.de; spf=pass smtp.mailfrom=suse.de; dkim=pass (1024-bit key) header.d=suse.de header.i=@suse.de header.b=hMk2IhcR; dkim=permerror (0-bit key) header.d=suse.de header.i=@suse.de header.b=/frv8Cyo; dkim=pass (1024-bit key) header.d=suse.de header.i=@suse.de header.b=S2J4bK2x; dkim=permerror (0-bit key) header.d=suse.de header.i=@suse.de header.b=V/sC2u9V; arc=none smtp.client-ip=195.135.223.130 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=suse.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=suse.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=suse.de header.i=@suse.de header.b="hMk2IhcR"; dkim=permerror (0-bit key) header.d=suse.de header.i=@suse.de header.b="/frv8Cyo"; dkim=pass (1024-bit key) header.d=suse.de header.i=@suse.de header.b="S2J4bK2x"; dkim=permerror (0-bit key) header.d=suse.de header.i=@suse.de header.b="V/sC2u9V" Received: from imap1.dmz-prg2.suse.org (imap1.dmz-prg2.suse.org [IPv6:2a07:de40:b281:104:10:150:64:97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id AE8D421EE8; Thu, 3 Sep 2026 14:56:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1788447422; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=mmshAJ1731Boww9npn0a+nbYqHhhHkrhDKX1ASn8WdY=; b=hMk2IhcRtY7juh5BEsW7hlpIbbugQK5bsC/7vxzWSdXgg78FTQKoQrejhtpEWcxWa/YsdL iA/gBpsEVN+0vInA7Dd5YejEzaCmwRBAXlc+JBjLZFFUvfDPTIWvq94UGLfZ/UwVMpfmuH THfRqMzo6gr+t3ApkypdgUkNulM5Ui4= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1788447422; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=mmshAJ1731Boww9npn0a+nbYqHhhHkrhDKX1ASn8WdY=; b=/frv8CyoDGy2ByD5pDztavngwBh2ZduGRWSbfiF0TRV6lyZUGjz0pT4EnNYNUs12+ww1WB hKbz7xKaDX/EmSDA== Authentication-Results: smtp-out1.suse.de; dkim=pass header.d=suse.de header.s=susede2_rsa header.b=S2J4bK2x; dkim=pass header.d=suse.de header.s=susede2_ed25519 header.b="V/sC2u9V" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1788447418; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=mmshAJ1731Boww9npn0a+nbYqHhhHkrhDKX1ASn8WdY=; b=S2J4bK2xmlmRA4H4jVaYzW44BQmsRgy2YjESuyGSeNdNdT79IDWNnovLhjl27i+KcQFbgy gE3QQEdxv/IG7e8HN0foMGwdnoWRvIJl1XfA6FkZrZa4lON4Xis6BUw8ITurw0lqczBqjm y/9yHFZBUYIJnC+S+ohwzzwFmxlRgxw= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1788447418; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=mmshAJ1731Boww9npn0a+nbYqHhhHkrhDKX1ASn8WdY=; b=V/sC2u9Vw6NosUMZoPJsQSANvdWPhDX3FbuGT908zqZka3ouhDMa0EobhMEmhnMNlt7Btl qHMvV6bFuLEkQhDA== Received: from imap1.dmz-prg2.suse.org (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by imap1.dmz-prg2.suse.org (Postfix) with ESMTPS id 75F0B13869; Thu, 3 Sep 2026 14:56:58 +0000 (UTC) Received: from dovecot-director2.suse.de ([2a07:de40:b281:106:10:150:64:167]) by imap1.dmz-prg2.suse.org with ESMTPSA id SOqsG7qKmWo6MQAAD6G6ig (envelope-from ); Thu, 03 Sep 2026 14:56:58 +0000 From: Takashi Iwai To: linux-sound@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Michal Pecio Subject: [PATCH 3/3] ALSA: usb: 6fire: Avoid embedded URBs Date: Thu, 3 Sep 2026 16:56:45 +0200 Message-ID: <20260903145648.1914352-4-tiwai@suse.de> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260903145648.1914352-1-tiwai@suse.de> References: <20260903145648.1914352-1-tiwai@suse.de> 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 X-Spam-Level: X-Rspamd-Action: no action X-Rspamd-Server: rspamd2.dmz-prg2.suse.org X-Rspamd-Queue-Id: AE8D421EE8 X-Spamd-Result: default: False [-3.01 / 50.00]; BAYES_HAM(-3.00)[100.00%]; MID_CONTAINS_FROM(1.00)[]; NEURAL_HAM_LONG(-1.00)[-1.000]; R_MISSING_CHARSET(0.50)[]; R_DKIM_ALLOW(-0.20)[suse.de:s=susede2_rsa,suse.de:s=susede2_ed25519]; NEURAL_HAM_SHORT(-0.20)[-1.000]; MIME_GOOD(-0.10)[text/plain]; MX_GOOD(-0.01)[]; MIME_TRACE(0.00)[0:+]; RBL_SPAMHAUS_BLOCKED_OPENRESOLVER(0.00)[2a07:de40:b281:104:10:150:64:97:from]; DKIM_SIGNED(0.00)[suse.de:s=susede2_rsa,suse.de:s=susede2_ed25519]; ARC_NA(0.00)[]; TO_MATCH_ENVRCPT_ALL(0.00)[]; FREEMAIL_CC(0.00)[vger.kernel.org,gmail.com]; DKIM_TRACE(0.00)[suse.de:+]; TO_DN_SOME(0.00)[]; RCVD_COUNT_TWO(0.00)[2]; FROM_EQ_ENVFROM(0.00)[]; FROM_HAS_DN(0.00)[]; RCVD_TLS_ALL(0.00)[]; DBL_BLOCKED_OPENRESOLVER(0.00)[imap1.dmz-prg2.suse.org:rdns,imap1.dmz-prg2.suse.org:helo,suse.de:dkim,suse.de:email,suse.de:mid]; TAGGED_RCPT(0.00)[]; RECEIVED_SPAMHAUS_BLOCKED_OPENRESOLVER(0.00)[2a07:de40:b281:106:10:150:64:167:received]; RCPT_COUNT_THREE(0.00)[3]; RCVD_VIA_SMTP_AUTH(0.00)[]; FREEMAIL_ENVRCPT(0.00)[gmail.com] X-Spam-Flag: NO X-Spam-Score: -3.01 Content-Type: text/plain; charset="utf-8" The USB 6fire driver uses URBs embedded in different structs for PCM, MIDI and communication, and this is basically a buggy implementation nowadays; since a URB is managed with a refcount, this may lead to a UAF when the URB is released asynchronously. For addressing the problem, this patch converts those embedded URBs to ones that are properly allocated via usb_alloc_urb(). The pcm_urb.packets[] is gone, as it's allocated by usb_alloc_urb(), hence it's found in urb.iso_frame_desc[] instead. The conversions are rather straightforward; each embedded struct urb is changed to a pointer, and its callers are updated accordingly. The resource for those structs are released in the common destructor functions (usb6fire_comm_free(), etc), which are called at both the init error path and the disconnect. No functional changes, only compile-tested. Link: https://lore.kernel.org/20260903130757.0668310a.michal.pecio@gmail.com Signed-off-by: Takashi Iwai --- sound/usb/6fire/comm.c | 35 +++++++----- sound/usb/6fire/comm.h | 2 +- sound/usb/6fire/midi.c | 36 ++++++++----- sound/usb/6fire/midi.h | 2 +- sound/usb/6fire/pcm.c | 120 +++++++++++++++++++++++------------------ sound/usb/6fire/pcm.h | 5 +- 6 files changed, 117 insertions(+), 83 deletions(-) diff --git a/sound/usb/6fire/comm.c b/sound/usb/6fire/comm.c index d3b7cab85699..878e9b71076a 100644 --- a/sound/usb/6fire/comm.c +++ b/sound/usb/6fire/comm.c @@ -21,7 +21,6 @@ enum { static void usb6fire_comm_init_urb(struct comm_runtime *rt, struct urb *ur= b, u8 *buffer, void *context, void(*handler)(struct urb *urb)) { - usb_init_urb(urb); urb->transfer_buffer =3D buffer; urb->pipe =3D usb_sndintpipe(rt->chip->dev, COMM_EP); urb->complete =3D handler; @@ -142,6 +141,13 @@ static int usb6fire_comm_write16(struct comm_runtime *= rt, u8 request, return ret; } =20 +static void usb6fire_comm_free(struct comm_runtime *rt) +{ + usb_free_urb(rt->receiver); + kfree(rt->receiver_buffer); + kfree(rt); +} + int usb6fire_comm_init(struct sfire_chip *chip) { struct comm_runtime *rt =3D kzalloc_obj(struct comm_runtime); @@ -153,14 +159,18 @@ int usb6fire_comm_init(struct sfire_chip *chip) =20 rt->receiver_buffer =3D kzalloc(COMM_RECEIVER_BUFSIZE, GFP_KERNEL); if (!rt->receiver_buffer) { - kfree(rt); - return -ENOMEM; + ret =3D -ENOMEM; + goto error; } =20 - urb =3D &rt->receiver; + urb =3D usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + ret =3D -ENOMEM; + goto error; + } + rt->receiver =3D urb; rt->serial =3D 1; rt->chip =3D chip; - usb_init_urb(urb); rt->init_urb =3D usb6fire_comm_init_urb; rt->write8 =3D usb6fire_comm_write8; rt->write16 =3D usb6fire_comm_write16; @@ -175,13 +185,15 @@ int usb6fire_comm_init(struct sfire_chip *chip) urb->interval =3D 1; ret =3D usb_submit_urb(urb, GFP_KERNEL); if (ret < 0) { - kfree(rt->receiver_buffer); - kfree(rt); dev_err(&chip->dev->dev, "cannot create comm data receiver."); - return ret; + goto error; } chip->comm =3D rt; return 0; + + error: + usb6fire_comm_free(rt); + return ret; } =20 void usb6fire_comm_abort(struct sfire_chip *chip) @@ -189,14 +201,11 @@ void usb6fire_comm_abort(struct sfire_chip *chip) struct comm_runtime *rt =3D chip->comm; =20 if (rt) - usb_poison_urb(&rt->receiver); + usb_poison_urb(rt->receiver); } =20 void usb6fire_comm_destroy(struct sfire_chip *chip) { - struct comm_runtime *rt =3D chip->comm; - - kfree(rt->receiver_buffer); - kfree(rt); + usb6fire_comm_free(chip->comm); chip->comm =3D NULL; } diff --git a/sound/usb/6fire/comm.h b/sound/usb/6fire/comm.h index 2447d7ecf179..89976f510f6c 100644 --- a/sound/usb/6fire/comm.h +++ b/sound/usb/6fire/comm.h @@ -19,7 +19,7 @@ enum /* settings for comm */ struct comm_runtime { struct sfire_chip *chip; =20 - struct urb receiver; + struct urb *receiver; u8 *receiver_buffer; =20 u8 serial; /* urb serial */ diff --git a/sound/usb/6fire/midi.c b/sound/usb/6fire/midi.c index 6b0bb096f27a..4e3b749ffccd 100644 --- a/sound/usb/6fire/midi.c +++ b/sound/usb/6fire/midi.c @@ -66,7 +66,7 @@ static void usb6fire_midi_out_trigger( struct snd_rawmidi_substream *alsa_sub, int up) { struct midi_runtime *rt =3D alsa_sub->rmidi->private_data; - struct urb *urb =3D &rt->out_urb; + struct urb *urb =3D rt->out_urb; __s8 ret; =20 guard(spinlock_irqsave)(&rt->out_lock); @@ -137,6 +137,13 @@ static const struct snd_rawmidi_ops in_ops =3D { .trigger =3D usb6fire_midi_in_trigger }; =20 +static void usb6fire_midi_free(struct midi_runtime *rt) +{ + usb_free_urb(rt->out_urb); + kfree(rt->out_buffer); + kfree(rt); +} + int usb6fire_midi_init(struct sfire_chip *chip) { int ret; @@ -148,8 +155,14 @@ int usb6fire_midi_init(struct sfire_chip *chip) =20 rt->out_buffer =3D kzalloc(MIDI_BUFSIZE, GFP_KERNEL); if (!rt->out_buffer) { - kfree(rt); - return -ENOMEM; + ret =3D -ENOMEM; + goto error; + } + + rt->out_urb =3D usb_alloc_urb(0, GFP_KERNEL); + if (!rt->out_urb) { + ret =3D -ENOMEM; + goto error; } =20 rt->chip =3D chip; @@ -160,15 +173,13 @@ int usb6fire_midi_init(struct sfire_chip *chip) spin_lock_init(&rt->in_lock); spin_lock_init(&rt->out_lock); =20 - comm_rt->init_urb(comm_rt, &rt->out_urb, rt->out_buffer, rt, + comm_rt->init_urb(comm_rt, rt->out_urb, rt->out_buffer, rt, usb6fire_midi_out_handler); =20 ret =3D snd_rawmidi_new(chip->card, "6FireUSB", 0, 1, 1, &rt->instance); if (ret < 0) { - kfree(rt->out_buffer); - kfree(rt); dev_err(&chip->dev->dev, "unable to create midi.\n"); - return ret; + goto error; } rt->instance->private_data =3D rt; strscpy(rt->instance->name, "DMX6FireUSB MIDI"); @@ -182,6 +193,10 @@ int usb6fire_midi_init(struct sfire_chip *chip) =20 chip->midi =3D rt; return 0; + + error: + usb6fire_midi_free(rt); + return ret; } =20 void usb6fire_midi_abort(struct sfire_chip *chip) @@ -189,14 +204,11 @@ void usb6fire_midi_abort(struct sfire_chip *chip) struct midi_runtime *rt =3D chip->midi; =20 if (rt) - usb_poison_urb(&rt->out_urb); + usb_poison_urb(rt->out_urb); } =20 void usb6fire_midi_destroy(struct sfire_chip *chip) { - struct midi_runtime *rt =3D chip->midi; - - kfree(rt->out_buffer); - kfree(rt); + usb6fire_midi_free(chip->midi); chip->midi =3D NULL; } diff --git a/sound/usb/6fire/midi.h b/sound/usb/6fire/midi.h index 47640c845903..8716ab8a863a 100644 --- a/sound/usb/6fire/midi.h +++ b/sound/usb/6fire/midi.h @@ -22,7 +22,7 @@ struct midi_runtime { spinlock_t in_lock; spinlock_t out_lock; struct snd_rawmidi_substream *out; - struct urb out_urb; + struct urb *out_urb; u8 out_serial; /* serial number of out packet */ u8 *out_buffer; int buffer_offset; diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c index d2e274b731fe..c57ef2c9f004 100644 --- a/sound/usb/6fire/pcm.c +++ b/sound/usb/6fire/pcm.c @@ -138,8 +138,8 @@ static void usb6fire_pcm_stream_stop(struct pcm_runtime= *rt) rt->stream_state =3D STREAM_STOPPING; =20 for (i =3D 0; i < PCM_N_URBS; i++) { - usb_kill_urb(&rt->in_urbs[i].instance); - usb_kill_urb(&rt->out_urbs[i].instance); + usb_kill_urb(rt->in_urbs[i].instance); + usb_kill_urb(rt->out_urbs[i].instance); } ctrl_rt->usb_streaming =3D false; ctrl_rt->update_streaming(ctrl_rt); @@ -161,13 +161,13 @@ static int usb6fire_pcm_stream_start(struct pcm_runti= me *rt) rt->stream_state =3D STREAM_STARTING; for (i =3D 0; i < PCM_N_URBS; i++) { for (k =3D 0; k < PCM_N_PACKETS_PER_URB; k++) { - packet =3D &rt->in_urbs[i].packets[k]; + packet =3D &rt->in_urbs[i].instance->iso_frame_desc[k]; packet->offset =3D k * rt->in_packet_size; packet->length =3D rt->in_packet_size; packet->actual_length =3D 0; packet->status =3D 0; } - ret =3D usb_submit_urb(&rt->in_urbs[i].instance, + ret =3D usb_submit_urb(rt->in_urbs[i].instance, GFP_ATOMIC); if (ret) { usb6fire_pcm_stream_stop(rt); @@ -197,6 +197,7 @@ static void usb6fire_pcm_capture(struct pcm_substream *= sub, struct pcm_urb *urb) unsigned int total_length =3D 0; struct pcm_runtime *rt =3D snd_pcm_substream_chip(sub->instance); struct snd_pcm_runtime *alsa_rt =3D sub->instance->runtime; + struct usb_iso_packet_descriptor *isoc; u32 *src =3D NULL; u32 *dest =3D (u32 *) (alsa_rt->dma_area + sub->dma_off * (alsa_rt->frame_bits >> 3)); @@ -207,8 +208,9 @@ static void usb6fire_pcm_capture(struct pcm_substream *= sub, struct pcm_urb *urb) for (i =3D 0; i < PCM_N_PACKETS_PER_URB; i++) { /* at least 4 header bytes for valid packet. * after that: 32 bits per sample for analog channels */ - if (urb->packets[i].actual_length > 4) - frame_count =3D (urb->packets[i].actual_length - 4) + isoc =3D &urb->instance->iso_frame_desc[i]; + if (isoc->actual_length > 4) + frame_count =3D (isoc->actual_length - 4) / (rt->in_n_analog << 2); else frame_count =3D 0; @@ -220,7 +222,7 @@ static void usb6fire_pcm_capture(struct pcm_substream *= sub, struct pcm_urb *urb) else return; src++; /* skip leading 4 bytes of every packet */ - total_length +=3D urb->packets[i].length; + total_length +=3D isoc->length; for (frame =3D 0; frame < frame_count; frame++) { memcpy(dest, src, bytes_per_frame); dest +=3D alsa_rt->channels; @@ -244,6 +246,7 @@ static void usb6fire_pcm_playback(struct pcm_substream = *sub, int frame_count; struct pcm_runtime *rt =3D snd_pcm_substream_chip(sub->instance); struct snd_pcm_runtime *alsa_rt =3D sub->instance->runtime; + struct usb_iso_packet_descriptor *isoc; u32 *src =3D (u32 *) (alsa_rt->dma_area + sub->dma_off * (alsa_rt->frame_bits >> 3)); u32 *src_end =3D (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size @@ -263,8 +266,9 @@ static void usb6fire_pcm_playback(struct pcm_substream = *sub, for (i =3D 0; i < PCM_N_PACKETS_PER_URB; i++) { /* at least 4 header bytes for valid packet. * after that: 32 bits per sample for analog channels */ - if (urb->packets[i].length > 4) - frame_count =3D (urb->packets[i].length - 4) + isoc =3D &urb->instance->iso_frame_desc[i]; + if (isoc->length > 4) + frame_count =3D (isoc->length - 4) / (rt->out_n_analog << 2); else frame_count =3D 0; @@ -289,6 +293,7 @@ static void usb6fire_pcm_in_urb_handler(struct urb *usb= _urb) struct pcm_urb *out_urb =3D in_urb->peer; struct pcm_runtime *rt =3D in_urb->chip->pcm; struct pcm_substream *sub; + struct usb_iso_packet_descriptor *isoc; bool period_elapsed; int total_length =3D 0; int frame_count; @@ -299,11 +304,13 @@ static void usb6fire_pcm_in_urb_handler(struct urb *u= sb_urb) =20 if (usb_urb->status || rt->panic || rt->stream_state =3D=3D STREAM_STOPPI= NG) return; - for (i =3D 0; i < PCM_N_PACKETS_PER_URB; i++) - if (in_urb->packets[i].status) { + for (i =3D 0; i < PCM_N_PACKETS_PER_URB; i++) { + isoc =3D &in_urb->instance->iso_frame_desc[i]; + if (isoc->status) { rt->panic =3D true; return; } + } =20 if (rt->stream_state =3D=3D STREAM_DISABLED) { dev_err(&rt->chip->dev->dev, @@ -328,12 +335,12 @@ static void usb6fire_pcm_in_urb_handler(struct urb *u= sb_urb) =20 /* setup out urb structure */ for (i =3D 0; i < PCM_N_PACKETS_PER_URB; i++) { - out_urb->packets[i].offset =3D total_length; - out_urb->packets[i].length =3D (in_urb->packets[i].actual_length - - 4) / (rt->in_n_analog << 2) + isoc =3D &out_urb->instance->iso_frame_desc[i]; + isoc->offset =3D total_length; + isoc->length =3D (isoc->actual_length - 4) / (rt->in_n_analog << 2) * (rt->out_n_analog << 2) + 4; - out_urb->packets[i].status =3D 0; - total_length +=3D out_urb->packets[i].length; + isoc->status =3D 0; + total_length +=3D isoc->length; } memset(out_urb->buffer, 0, total_length); =20 @@ -354,9 +361,10 @@ static void usb6fire_pcm_in_urb_handler(struct urb *us= b_urb) =20 /* setup the 4th byte of each sample (0x40 for analog channels) */ dest =3D out_urb->buffer; - for (i =3D 0; i < PCM_N_PACKETS_PER_URB; i++) - if (out_urb->packets[i].length >=3D 4) { - frame_count =3D (out_urb->packets[i].length - 4) + for (i =3D 0; i < PCM_N_PACKETS_PER_URB; i++) { + isoc =3D &out_urb->instance->iso_frame_desc[i]; + if (isoc->length >=3D 4) { + frame_count =3D (isoc->length - 4) / (rt->out_n_analog << 2); *(dest++) =3D 0xaa; *(dest++) =3D 0xaa; @@ -370,8 +378,10 @@ static void usb6fire_pcm_in_urb_handler(struct urb *us= b_urb) *(dest++) =3D 0x40; } } - usb_submit_urb(&out_urb->instance, GFP_ATOMIC); - usb_submit_urb(&in_urb->instance, GFP_ATOMIC); + } + + usb_submit_urb(out_urb->instance, GFP_ATOMIC); + usb_submit_urb(in_urb->instance, GFP_ATOMIC); } =20 static void usb6fire_pcm_out_urb_handler(struct urb *usb_urb) @@ -534,22 +544,25 @@ static const struct snd_pcm_ops pcm_ops =3D { .pointer =3D usb6fire_pcm_pointer, }; =20 -static void usb6fire_pcm_init_urb(struct pcm_urb *urb, - struct sfire_chip *chip, bool in, int ep, - void (*handler)(struct urb *)) +static int usb6fire_pcm_init_urb(struct pcm_urb *urb, + struct sfire_chip *chip, bool in, int ep, + void (*handler)(struct urb *)) { urb->chip =3D chip; - usb_init_urb(&urb->instance); - urb->instance.transfer_buffer =3D urb->buffer; - urb->instance.transfer_buffer_length =3D + urb->instance =3D usb_alloc_urb(PCM_N_PACKETS_PER_URB, GFP_KERNEL); + if (!urb->instance) + return -ENOMEM; + urb->instance->transfer_buffer =3D urb->buffer; + urb->instance->transfer_buffer_length =3D PCM_N_PACKETS_PER_URB * PCM_MAX_PACKET_SIZE; - urb->instance.dev =3D chip->dev; - urb->instance.pipe =3D in ? usb_rcvisocpipe(chip->dev, ep) + urb->instance->dev =3D chip->dev; + urb->instance->pipe =3D in ? usb_rcvisocpipe(chip->dev, ep) : usb_sndisocpipe(chip->dev, ep); - urb->instance.interval =3D 1; - urb->instance.complete =3D handler; - urb->instance.context =3D urb; - urb->instance.number_of_packets =3D PCM_N_PACKETS_PER_URB; + urb->instance->interval =3D 1; + urb->instance->complete =3D handler; + urb->instance->context =3D urb; + urb->instance->number_of_packets =3D PCM_N_PACKETS_PER_URB; + return 0; } =20 static int usb6fire_pcm_buffers_init(struct pcm_runtime *rt) @@ -571,14 +584,17 @@ static int usb6fire_pcm_buffers_init(struct pcm_runti= me *rt) return 0; } =20 -static void usb6fire_pcm_buffers_destroy(struct pcm_runtime *rt) +static void usb6fire_pcm_free(struct pcm_runtime *rt) { int i; =20 for (i =3D 0; i < PCM_N_URBS; i++) { + usb_free_urb(rt->out_urbs[i].instance); kfree(rt->out_urbs[i].buffer); + usb_free_urb(rt->in_urbs[i].instance); kfree(rt->in_urbs[i].buffer); } + kfree(rt); } =20 int usb6fire_pcm_init(struct sfire_chip *chip) @@ -593,11 +609,8 @@ int usb6fire_pcm_init(struct sfire_chip *chip) return -ENOMEM; =20 ret =3D usb6fire_pcm_buffers_init(rt); - if (ret) { - usb6fire_pcm_buffers_destroy(rt); - kfree(rt); - return ret; - } + if (ret) + goto error; =20 rt->chip =3D chip; rt->stream_state =3D STREAM_DISABLED; @@ -609,10 +622,14 @@ int usb6fire_pcm_init(struct sfire_chip *chip) spin_lock_init(&rt->capture.lock); =20 for (i =3D 0; i < PCM_N_URBS; i++) { - usb6fire_pcm_init_urb(&rt->in_urbs[i], chip, true, IN_EP, - usb6fire_pcm_in_urb_handler); - usb6fire_pcm_init_urb(&rt->out_urbs[i], chip, false, OUT_EP, - usb6fire_pcm_out_urb_handler); + ret =3D usb6fire_pcm_init_urb(&rt->in_urbs[i], chip, true, IN_EP, + usb6fire_pcm_in_urb_handler); + if (ret < 0) + goto error; + ret =3D usb6fire_pcm_init_urb(&rt->out_urbs[i], chip, false, OUT_EP, + usb6fire_pcm_out_urb_handler); + if (ret < 0) + goto error; =20 rt->in_urbs[i].peer =3D &rt->out_urbs[i]; rt->out_urbs[i].peer =3D &rt->in_urbs[i]; @@ -620,10 +637,8 @@ int usb6fire_pcm_init(struct sfire_chip *chip) =20 ret =3D snd_pcm_new(chip->card, "DMX6FireUSB", 0, 1, 1, &pcm); if (ret < 0) { - usb6fire_pcm_buffers_destroy(rt); - kfree(rt); dev_err(&chip->dev->dev, "cannot create pcm instance.\n"); - return ret; + goto error; } =20 pcm->private_data =3D rt; @@ -636,6 +651,10 @@ int usb6fire_pcm_init(struct sfire_chip *chip) =20 chip->pcm =3D rt; return 0; + + error: + usb6fire_pcm_free(rt); + return ret; } =20 void usb6fire_pcm_abort(struct sfire_chip *chip) @@ -653,8 +672,8 @@ void usb6fire_pcm_abort(struct sfire_chip *chip) snd_pcm_stop_xrun(rt->capture.instance); =20 for (i =3D 0; i < PCM_N_URBS; i++) { - usb_poison_urb(&rt->in_urbs[i].instance); - usb_poison_urb(&rt->out_urbs[i].instance); + usb_poison_urb(rt->in_urbs[i].instance); + usb_poison_urb(rt->out_urbs[i].instance); } =20 } @@ -662,9 +681,6 @@ void usb6fire_pcm_abort(struct sfire_chip *chip) =20 void usb6fire_pcm_destroy(struct sfire_chip *chip) { - struct pcm_runtime *rt =3D chip->pcm; - - usb6fire_pcm_buffers_destroy(rt); - kfree(rt); + usb6fire_pcm_free(chip->pcm); chip->pcm =3D NULL; } diff --git a/sound/usb/6fire/pcm.h b/sound/usb/6fire/pcm.h index 5a092dfd69f5..b586fe220fd1 100644 --- a/sound/usb/6fire/pcm.h +++ b/sound/usb/6fire/pcm.h @@ -24,10 +24,7 @@ enum /* settings for pcm */ struct pcm_urb { struct sfire_chip *chip; =20 - /* BEGIN DO NOT SEPARATE */ - struct urb instance; - struct usb_iso_packet_descriptor packets[PCM_N_PACKETS_PER_URB]; - /* END DO NOT SEPARATE */ + struct urb *instance; u8 *buffer; =20 struct pcm_urb *peer; --=20 2.55.0