Skip to contentSkip to conversation

FAILED: patch "[PATCH] ALSA: usbusx2y: validate URB actual_length in interrupt" failed to apply to 5.15-stable tree

PATCH New [email protected] 2 participants 4 messages Sep 16

Subsystems (2)
lore
Share & tools
lore

[email protected]

author maintainer
#0 lore raw

The patch below does not apply to the 5.15-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.

To reproduce the conflict and resubmit, you may use the following commands:

git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.15.y
git checkout FETCH_HEAD
git cherry-pick -x 8f5ef203abda9dd36b2af473c7b737d544f807bd
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026091646-catalyst-goldmine-6801@gregkh' --subject-prefix 'PATCH 5.15.y' 'HEAD^..'

Possible dependencies:

thanks,

greg k-h

------------------ original commit in Linus's tree ------------------

From 8f5ef203abda9dd36b2af473c7b737d544f807bd Mon Sep 17 00:00:00 2001
From: Tristan Madani <[email protected]>
Date: Fri, 4 Sep 2026 20:58:26 +0000
Subject: [PATCH] ALSA: usbusx2y: validate URB actual_length in interrupt
callback

i_usx2y_in04_int() processes the interrupt URB data without checking urb->actual_length. A short transfer from a malfunctioning device would cause the handler to process uninitialized heap data from the kmalloc-allocated in04_buf, which is then copied to the mmap-accessible ctl_snapshot[] array.

Fix by using kzalloc() for in04_buf to zero-initialize the buffer, and adding an actual_length check to skip processing on short transfers while still resubmitting the URB.

sound/usb/usx2y/usbusx2y.c +5 -1
index 200b708aacd6..108f9bddf9aa 100644
@@ -189,6 +189,9 @@ static void i_usx2y_in04_int(struct urb *urb)
 		return;
 	}
 
+	if (urb->actual_length < USX2Y_IN04_SIZE)
+		goto resubmit;
+
 	if (us428ctls) {
 		diff = -1;
 		if (us428ctls->ctl_snapshot_last == -2) {
@@ -253,6 +256,7 @@ static void i_usx2y_in04_int(struct urb *urb)
 	if (err)
 		dev_err(&urb->dev->dev, "in04_int() usb_submit_urb err=%i\n", err);
 
+resubmit:
 	urb->dev = usx2y->dev;
 	usb_submit_urb(urb, GFP_ATOMIC);
 }
@@ -305,7 +309,7 @@ int usx2y_in04_init(struct usx2ydev *usx2y)
 		goto error;
 	}
 
-	usx2y->in04_buf = kmalloc(USX2Y_IN04_SIZE, GFP_KERNEL);
+	usx2y->in04_buf = kzalloc(USX2Y_IN04_SIZE, GFP_KERNEL);
 	if (!usx2y->in04_buf) {
 		err = -ENOMEM;
 		goto error;
maintainer
#1 lore raw

PATCH 1/3 ALSA: usx2y: Use standard print API

From: Takashi Iwai <[email protected]>

[ Upstream commit f8466d91f36d97e237ea1b3c6f19de980054a1b6 ]

Use the standard print API with dev_*() instead of the old house-baked one. It gives better information and allows dynamically control of debug prints.

Some superfluous debug prints are dropped, and some ambiguous messages are slightly rephrased. The sk.dev pointer is set properly for allowing to call dev_*() functions, too.

Stable-dep-of: 8f5ef203abda ("ALSA: usbusx2y: validate URB actual_length in interrupt callback")

---
 sound/usb/usx2y/us122l.c        | 45 ++++++----------
 sound/usb/usx2y/usX2Yhwdep.c    | 25 +++------
 sound/usb/usx2y/usb_stream.c    | 92 +++++++++++++++------------------
 sound/usb/usx2y/usb_stream.h    |  1 +
 sound/usb/usx2y/usbusx2y.c      |  7 ++-
 sound/usb/usx2y/usbusx2yaudio.c | 67 ++++++++++++++----------
 sound/usb/usx2y/usx2yhwdeppcm.c | 54 ++++++++++---------
 7 files changed, 141 insertions(+), 150 deletions(-)
sound/usb/usx2y/us122l.c +17 -28
index 23d7d542a3de6..79ddf58ee4033 100644
@@ -84,12 +84,9 @@ static int us144_create_usbmidi(struct snd_card *card)
 
 static void pt_info_set(struct usb_device *dev, u8 v)
 {
-	int ret;
-
-	ret = usb_control_msg_send(dev, 0, 'I',
-				   USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-				   v, 0, NULL, 0, 1000, GFP_NOIO);
-	snd_printdd(KERN_DEBUG "%i\n", ret);
+	usb_control_msg_send(dev, 0, 'I',
+			     USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			     v, 0, NULL, 0, 1000, GFP_NOIO);
 }
 
 static void usb_stream_hwdep_vm_open(struct vm_area_struct *area)
@@ -97,7 +94,6 @@ static void usb_stream_hwdep_vm_open(struct vm_area_struct *area)
 	struct us122l *us122l = area->vm_private_data;
 
 	atomic_inc(&us122l->mmap_count);
-	snd_printdd(KERN_DEBUG "%i\n", atomic_read(&us122l->mmap_count));
 }
 
 static vm_fault_t usb_stream_hwdep_vm_fault(struct vm_fault *vmf)
@@ -141,7 +137,6 @@ static void usb_stream_hwdep_vm_close(struct vm_area_struct *area)
 	struct us122l *us122l = area->vm_private_data;
 
 	atomic_dec(&us122l->mmap_count);
-	snd_printdd(KERN_DEBUG "%i\n", atomic_read(&us122l->mmap_count));
 }
 
 static const struct vm_operations_struct usb_stream_hwdep_vm_ops = {
@@ -155,7 +150,6 @@ static int usb_stream_hwdep_open(struct snd_hwdep *hw, struct file *file)
 	struct us122l	*us122l = hw->private_data;
 	struct usb_interface *iface;
 
-	snd_printdd(KERN_DEBUG "%p %p\n", hw, file);
 	if (hw->used >= 2)
 		return -EBUSY;
 
@@ -176,8 +170,6 @@ static int usb_stream_hwdep_release(struct snd_hwdep *hw, struct file *file)
 	struct us122l	*us122l = hw->private_data;
 	struct usb_interface *iface;
 
-	snd_printdd(KERN_DEBUG "%p %p\n", hw, file);
-
 	if (us122l->is_us144) {
 		iface = usb_ifnum_to_if(us122l->dev, 0);
 		usb_autopm_put_interface(iface);
@@ -213,12 +205,10 @@ static int usb_stream_hwdep_mmap(struct snd_hwdep *hw,
 		err = -EPERM;
 		goto out;
 	}
-	snd_printdd(KERN_DEBUG "%lu %u\n", size,
-		    read ? s->read_size : s->write_size);
 	/* if userspace tries to mmap beyond end of our buffer, fail */
 	if (size > PAGE_ALIGN(read ? s->read_size : s->write_size)) {
-		snd_printk(KERN_WARNING "%lu > %u\n", size,
-			   read ? s->read_size : s->write_size);
+		dev_warn(hw->card->dev, "%s: size %lu > %u\n", __func__,
+			 size, read ? s->read_size : s->write_size);
 		err = -EINVAL;
 		goto out;
 	}
@@ -289,8 +279,8 @@ static int us122l_set_sample_rate(struct usb_device *dev, int rate)
 				   UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, data, 3,
 				   1000, GFP_NOIO);
 	if (err)
-		snd_printk(KERN_ERR "%d: cannot set freq %d to ep 0x%x\n",
-			   dev->devnum, rate, ep);
+		dev_err(&dev->dev, "%d: cannot set freq %d to ep 0x%x\n",
+			dev->devnum, rate, ep);
 	return err;
 }
 
@@ -326,13 +316,13 @@ static bool us122l_start(struct us122l *us122l,
 	err = us122l_set_sample_rate(us122l->dev, rate);
 	if (err < 0) {
 		us122l_stop(us122l);
-		snd_printk(KERN_ERR "us122l_set_sample_rate error\n");
+		dev_err(&us122l->dev->dev, "us122l_set_sample_rate error\n");
 		goto out;
 	}
 	err = usb_stream_start(&us122l->sk);
 	if (err < 0) {
 		us122l_stop(us122l);
-		snd_printk(KERN_ERR "%s error %i\n", __func__, err);
+		dev_err(&us122l->dev->dev, "%s error %i\n", __func__, err);
 		goto out;
 	}
 	list_for_each(p, &us122l->midi_list)
@@ -445,13 +435,13 @@ static bool us122l_create_card(struct snd_card *card)
 	if (us122l->is_us144) {
 		err = usb_set_interface(us122l->dev, 0, 1);
 		if (err) {
-			snd_printk(KERN_ERR "usb_set_interface error\n");
+			dev_err(card->dev, "usb_set_interface error\n");
 			return false;
 		}
 	}
 	err = usb_set_interface(us122l->dev, 1, 1);
 	if (err) {
-		snd_printk(KERN_ERR "usb_set_interface error\n");
+		dev_err(card->dev, "usb_set_interface error\n");
 		return false;
 	}
 
@@ -466,7 +456,7 @@ static bool us122l_create_card(struct snd_card *card)
 	else
 		err = us122l_create_usbmidi(card);
 	if (err < 0) {
-		snd_printk(KERN_ERR "us122l_create_usbmidi error %i\n", err);
+		dev_err(card->dev, "us122l_create_usbmidi error %i\n", err);
 		goto stop;
 	}
 	err = usb_stream_hwdep_new(card);
@@ -517,6 +507,7 @@ static int usx2y_create_card(struct usb_device *device,
 	card->private_free = snd_us122l_free;
 	US122L(card)->dev = device;
 	mutex_init(&US122L(card)->mutex);
+	US122L(card)->sk.dev = device;
 	init_waitqueue_head(&US122L(card)->sk.sleep);
 	US122L(card)->is_us144 = flags & US122L_FLAG_US144;
 	INIT_LIST_HEAD(&US122L(card)->midi_list);
@@ -572,12 +563,10 @@ static int snd_us122l_probe(struct usb_interface *intf,
 
 	if (id->driver_info & US122L_FLAG_US144 &&
 			device->speed == USB_SPEED_HIGH) {
-		snd_printk(KERN_ERR "disable ehci-hcd to run US-144\n");
+		dev_err(&device->dev, "disable ehci-hcd to run US-144\n");
 		return -ENODEV;
 	}
 
-	snd_printdd(KERN_DEBUG"%p:%i\n",
-		    intf, intf->cur_altsetting->desc.bInterfaceNumber);
 	if (intf->cur_altsetting->desc.bInterfaceNumber != 1)
 		return 0;
 
@@ -665,13 +654,13 @@ static int snd_us122l_resume(struct usb_interface *intf)
 	if (us122l->is_us144) {
 		err = usb_set_interface(us122l->dev, 0, 1);
 		if (err) {
-			snd_printk(KERN_ERR "usb_set_interface error\n");
+			dev_err(&us122l->dev->dev, "usb_set_interface error\n");
 			goto unlock;
 		}
 	}
 	err = usb_set_interface(us122l->dev, 1, 1);
 	if (err) {
-		snd_printk(KERN_ERR "usb_set_interface error\n");
+		dev_err(&us122l->dev->dev, "usb_set_interface error\n");
 		goto unlock;
 	}
 
@@ -681,7 +670,7 @@ static int snd_us122l_resume(struct usb_interface *intf)
 	err = us122l_set_sample_rate(us122l->dev,
 				     us122l->sk.s->cfg.sample_rate);
 	if (err < 0) {
-		snd_printk(KERN_ERR "us122l_set_sample_rate error\n");
+		dev_err(&us122l->dev->dev, "us122l_set_sample_rate error\n");
 		goto unlock;
 	}
 	err = usb_stream_start(&us122l->sk);
sound/usb/usx2y/usX2Yhwdep.c +8 -17
index c0293af448fe7..a863d77610b6c 100644
@@ -24,10 +24,6 @@ static vm_fault_t snd_us428ctls_vm_fault(struct vm_fault *vmf)
 	struct page *page;
 	void *vaddr;
 
-	snd_printdd("ENTER, start %lXh, pgoff %ld\n",
-		   vmf->vma->vm_start,
-		   vmf->pgoff);
-
 	offset = vmf->pgoff << PAGE_SHIFT;
 	if (offset >= US428_SHAREDMEM_PAGES)
 		return VM_FAULT_SIGBUS;
@@ -36,9 +32,6 @@ static vm_fault_t snd_us428ctls_vm_fault(struct vm_fault *vmf)
 	get_page(page);
 	vmf->page = page;
 
-	snd_printdd("vaddr=%p made us428ctls_vm_fault() page %p\n",
-		    vaddr, page);
-
 	return 0;
 }
 
@@ -58,7 +51,8 @@ static int snd_us428ctls_mmap(struct snd_hwdep *hw, struct file *filp, struct vm
 
 	/* if userspace tries to mmap beyond end of our buffer, fail */
 	if (size > US428_SHAREDMEM_PAGES) {
-		snd_printd("%lu > %lu\n", size, (unsigned long)US428_SHAREDMEM_PAGES);
+		dev_dbg(hw->card->dev, "%s: mmap size %lu > %lu\n", __func__,
+			size, (unsigned long)US428_SHAREDMEM_PAGES);
 		return -EINVAL;
 	}
 
@@ -152,7 +146,6 @@ static int usx2y_create_usbmidi(struct snd_card *card)
 		le16_to_cpu(dev->descriptor.idProduct) == USB_ID_US428 ?
 		&quirk_2 : &quirk_1;
 
-	snd_printdd("%s\n", __func__);
 	return snd_usbmidi_create(card, iface, &usx2y(card)->midi_list, quirk);
 }
 
@@ -162,7 +155,8 @@ static int usx2y_create_alsa_devices(struct snd_card *card)
 
 	err = usx2y_create_usbmidi(card);
 	if (err < 0) {
-		snd_printk(KERN_ERR "%s: usx2y_create_usbmidi error %i\n", __func__, err);
+		dev_err(card->dev, "%s: usx2y_create_usbmidi error %i\n",
+			__func__, err);
 		return err;
 	}
 	err = usx2y_audio_create(card);
@@ -185,15 +179,13 @@ static int snd_usx2y_hwdep_dsp_load(struct snd_hwdep *hw,
 	int lret, err;
 	char *buf;
 
-	snd_printdd("dsp_load %s\n", dsp->name);
-
 	buf = memdup_user(dsp->image, dsp->length);
 	if (IS_ERR(buf))
 		return PTR_ERR(buf);
 
 	err = usb_set_interface(dev, 0, 1);
 	if (err)
-		snd_printk(KERN_ERR "usb_set_interface error\n");
+		dev_err(&dev->dev, "usb_set_interface error\n");
 	else
 		err = usb_bulk_msg(dev, usb_sndbulkpipe(dev, 2), buf, dsp->length, &lret, 6000);
 	kfree(buf);
@@ -203,21 +195,20 @@ static int snd_usx2y_hwdep_dsp_load(struct snd_hwdep *hw,
 		msleep(250);				// give the device some time
 		err = usx2y_async_seq04_init(priv);
 		if (err) {
-			snd_printk(KERN_ERR "usx2y_async_seq04_init error\n");
+			dev_err(&dev->dev, "usx2y_async_seq04_init error\n");
 			return err;
 		}
 		err = usx2y_in04_init(priv);
 		if (err) {
-			snd_printk(KERN_ERR "usx2y_in04_init error\n");
+			dev_err(&dev->dev, "usx2y_in04_init error\n");
 			return err;
 		}
 		err = usx2y_create_alsa_devices(hw->card);
 		if (err) {
-			snd_printk(KERN_ERR "usx2y_create_alsa_devices error %i\n", err);
+			dev_err(&dev->dev, "usx2y_create_alsa_devices error %i\n", err);
 			return err;
 		}
 		priv->chip_status |= USX2Y_STAT_CHIP_INIT;
-		snd_printdd("%s: alsa all started\n", hw->name);
 	}
 	return err;
 }
sound/usb/usx2y/usb_stream.c +43 -49

226 lines not on this page · raw message

sound/usb/usx2y/usb_stream.h +1 -0
index 73e57b341adc8..2ed10add49f1a 100644
@@ -9,6 +9,7 @@
 
 struct usb_stream_kernel {
 	struct usb_stream *s;
+	struct usb_device *dev;
 
 	void *write_page;
 
sound/usb/usx2y/usbusx2y.c +3 -4
index b8f0c0298f14a..bbf7567780f08 100644
@@ -169,7 +169,7 @@ static void i_usx2y_out04_int(struct urb *urb)
 
 		for (i = 0; i < 10 && usx2y->as04.urb[i] != urb; i++)
 			;
-		snd_printdd("%s urb %i status=%i\n", __func__, i, urb->status);
+		dev_dbg(&urb->dev->dev, "%s urb %i status=%i\n", __func__, i, urb->status);
 	}
 #endif
 }
@@ -185,11 +185,10 @@ static void i_usx2y_in04_int(struct urb *urb)
 	usx2y->in04_int_calls++;
 
 	if (urb->status) {
-		snd_printdd("Interrupt Pipe 4 came back with status=%i\n", urb->status);
+		dev_dbg(&urb->dev->dev, "Interrupt Pipe 4 came back with status=%i\n", urb->status);
 		return;
 	}
 
-	//	printk("%i:0x%02X ", 8, (int)((unsigned char*)usx2y->in04_buf)[8]); Master volume shows 0 here if fader is at max during boot ?!?
 	if (us428ctls) {
 		diff = -1;
 		if (us428ctls->ctl_snapshot_last == -2) {
@@ -245,7 +244,7 @@ static void i_usx2y_in04_int(struct urb *urb)
 	}
 
 	if (err)
-		snd_printk(KERN_ERR "in04_int() usb_submit_urb err=%i\n", err);
+		dev_err(&urb->dev->dev, "in04_int() usb_submit_urb err=%i\n", err);
 
 	urb->dev = usx2y->dev;
 	usb_submit_urb(urb, GFP_ATOMIC);
sound/usb/usx2y/usbusx2yaudio.c +39 -28

187 lines not on this page · raw message

sound/usb/usx2y/usx2yhwdeppcm.c +30 -24

132 lines not on this page · raw message

Signature · 1 line
2.53.0
maintainer
#2 lore raw

PATCH 2/3 ALSA: usbusx2y: fix in04_last array size mismatch with in04_buf

From: Tristan Madani <[email protected]>

[ Upstream commit 861111a14740e12c36d363e9830f8daa734279c9 ]

The in04_last array in struct usx2ydev is declared as char[24], but in04_buf is allocated as sizeof(struct us428_ctls) which is 21 bytes. In i_usx2y_in04_int(), when ctl_snapshot_last == -2 (initialization path):

    memcpy(usx2y->in04_last, usx2y->in04_buf, sizeof(usx2y->in04_last));

This copies 24 bytes from a 21-byte slab allocation, reading 3 bytes past the end of the source object.

Introduce a USX2Y_IN04_SIZE constant defined as sizeof(struct us428_ctls) and use it consistently for the in04_last array, the in04_buf allocation, the URB transfer length, and the comparison loop, replacing the bare 24 and 21 literals throughout.

Stable-dep-of: 8f5ef203abda ("ALSA: usbusx2y: validate URB actual_length in interrupt callback")

---
 sound/usb/usx2y/usbusx2y.c | 6 +++---
 sound/usb/usx2y/usbusx2y.h | 4 +++-
 2 files changed, 6 insertions(+), 4 deletions(-)
sound/usb/usx2y/usbusx2y.c +3 -3
index bbf7567780f08..9f305de713bbf 100644
@@ -196,7 +196,7 @@ static void i_usx2y_in04_int(struct urb *urb)
 			memcpy(usx2y->in04_last, usx2y->in04_buf, sizeof(usx2y->in04_last));
 			us428ctls->ctl_snapshot_last = -1;
 		} else {
-			for (i = 0; i < 21; i++) {
+			for (i = 0; i < USX2Y_IN04_SIZE; i++) {
 				if (usx2y->in04_last[i] != ((char *)usx2y->in04_buf)[i]) {
 					if (diff < 0)
 						diff = i;
@@ -298,7 +298,7 @@ int usx2y_in04_init(struct usx2ydev *usx2y)
 		goto error;
 	}
 
-	usx2y->in04_buf = kmalloc(21, GFP_KERNEL);
+	usx2y->in04_buf = kmalloc(USX2Y_IN04_SIZE, GFP_KERNEL);
 	if (!usx2y->in04_buf) {
 		err = -ENOMEM;
 		goto error;
@@ -306,7 +306,7 @@ int usx2y_in04_init(struct usx2ydev *usx2y)
 
 	init_waitqueue_head(&usx2y->in04_wait_queue);
 	usb_fill_int_urb(usx2y->in04_urb, usx2y->dev, usb_rcvintpipe(usx2y->dev, 0x4),
-			 usx2y->in04_buf, 21,
+			 usx2y->in04_buf, USX2Y_IN04_SIZE,
 			 i_usx2y_in04_int, usx2y,
 			 10);
 	if (usb_urb_ep_type_check(usx2y->in04_urb)) {
sound/usb/usx2y/usbusx2y.h +3 -1
index 0538c457921e6..a2f1e3755eb91 100644
@@ -5,6 +5,8 @@
 #include "../midi.h"
 #include "usbus428ctldefs.h"
 
+#define USX2Y_IN04_SIZE	sizeof(struct us428_ctls)
+
 #define NRURBS	        2
 
 /* Default value used for nr of packs per urb.
@@ -55,7 +57,7 @@ struct usx2ydev {
 	int			stride;
 	struct urb		*in04_urb;
 	void			*in04_buf;
-	char			in04_last[24];
+	char			in04_last[USX2Y_IN04_SIZE];
 	unsigned int		in04_int_calls;
 	struct snd_usx2y_urb_seq	*us04;
 	wait_queue_head_t	in04_wait_queue;
Signature · 1 line
2.53.0
maintainer
#3 lore raw

PATCH 3/3 ALSA: usbusx2y: validate URB actual_length in interrupt callback

In reply to Sasha Levin

From: Tristan Madani <[email protected]>

[ Upstream commit 8f5ef203abda9dd36b2af473c7b737d544f807bd ]

i_usx2y_in04_int() processes the interrupt URB data without checking urb->actual_length. A short transfer from a malfunctioning device would cause the handler to process uninitialized heap data from the kmalloc-allocated in04_buf, which is then copied to the mmap-accessible ctl_snapshot[] array.

Fix by using kzalloc() for in04_buf to zero-initialize the buffer, and adding an actual_length check to skip processing on short transfers while still resubmitting the URB.

---
 sound/usb/usx2y/usbusx2y.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
sound/usb/usx2y/usbusx2y.c +5 -1
index 9f305de713bbf..4e1ef6d80277e 100644
@@ -189,6 +189,9 @@ static void i_usx2y_in04_int(struct urb *urb)
 		return;
 	}
 
+	if (urb->actual_length < USX2Y_IN04_SIZE)
+		goto resubmit;
+
 	if (us428ctls) {
 		diff = -1;
 		if (us428ctls->ctl_snapshot_last == -2) {
@@ -246,6 +249,7 @@ static void i_usx2y_in04_int(struct urb *urb)
 	if (err)
 		dev_err(&urb->dev->dev, "in04_int() usb_submit_urb err=%i\n", err);
 
+resubmit:
 	urb->dev = usx2y->dev;
 	usb_submit_urb(urb, GFP_ATOMIC);
 }
@@ -298,7 +302,7 @@ int usx2y_in04_init(struct usx2ydev *usx2y)
 		goto error;
 	}
 
-	usx2y->in04_buf = kmalloc(USX2Y_IN04_SIZE, GFP_KERNEL);
+	usx2y->in04_buf = kzalloc(USX2Y_IN04_SIZE, GFP_KERNEL);
 	if (!usx2y->in04_buf) {
 		err = -ENOMEM;
 		goto error;
Signature · 1 line
2.53.0