VYPR
Unrated severityNVD Advisory· Published May 27, 2026· Updated May 27, 2026

CVE-2026-46048

CVE-2026-46048

Description

In the Linux kernel, the following vulnerability has been resolved:

ALSA: caiaq: fix usb_dev refcount leak on probe failure

create_card() takes a reference on the USB device with usb_get_dev() and stores the matching usb_put_dev() in card_free(), which is installed as the snd_card's ->private_free destructor.

However, ->private_free is only assigned near the end of init_card(), after several failure points (usb_set_interface(), EP type checks, usb_submit_urb(), the EP1_CMD_GET_DEVICE_INFO exchange, and its timeout). When any of those fail, init_card() returns an error to snd_probe(), which calls snd_card_free(card). Because ->private_free is still NULL, card_free() never runs, the usb_get_dev() reference is not dropped, and the struct usb_device leaks along with its descriptor allocations and device_private.

syzbot reproduces this with a malformed UAC3 device whose only valid altsetting is 0; init_card()'s usb_set_interface(usb_dev, 0, 1) call fails with -EIO and triggers the leak.

Move the ->private_free assignment into create_card(), immediately after usb_get_dev(), so that every error path reaching snd_card_free() balances the reference. card_free()'s callees (snd_usb_caiaq_input_free, free_urbs, kfree) already tolerate the partially-initialized state because the chip private area is zero-initialized by snd_card_new().

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

In the Linux kernel's ALSA caiaq driver, a usb_dev refcount leak on probe failure can be triggered by a malicious USB device, leading to memory exhaustion.

Vulnerability

In the Linux kernel's ALSA caiaq driver (sound/usb/caiaq/device.c), the usb_dev reference count is not properly released on probe failure. The function create_card() takes a reference with usb_get_dev() and stores the matching usb_put_dev() in card_free(), which is installed as the snd_card's private_free destructor. However, private_free is only assigned near the end of init_card(), after several failure points (usb_set_interface(), endpoint type checks, usb_submit_urb(), the EP1_CMD_GET_DEVICE_INFO exchange, and its timeout). When any of those fail, init_card() returns an error to snd_probe(), which calls snd_card_free(card). Because private_free is still NULL, card_free() never runs, and the usb_get_dev() reference is not dropped, causing a leak of the struct usb_device along with its descriptor allocations and device_private. The bug affects Linux kernel versions before the fix commit da3b8fd6a202d94fef11a443abc9171c52426a1c [1].

Exploitation

An attacker with physical access or the ability to connect a malicious USB device can trigger the vulnerability. The attacker crafts a USB device (e.g., a malformed UAC3 device whose only valid altsetting is 0) that causes init_card() to fail at one of the early failure points, such as usb_set_interface(usb_dev, 0, 1) returning -EIO. No authentication or special privileges are required; the attack is performed by inserting the malicious device into a system with the vulnerable driver loaded. The leak occurs each time the probe fails, allowing the attacker to repeatedly trigger the refcount leak.

Impact

Successful exploitation results in a memory leak of the struct usb_device and associated kernel allocations. Over time, repeated leaks can exhaust system memory, leading to denial of service (system instability, resource exhaustion, or crash). The vulnerability does not allow privilege escalation, code execution, or information disclosure; the impact is limited to availability.

Mitigation

The fix is included in Linux kernel commit da3b8fd6a202d94fef11a443abc9171c52426a1c, which moves the private_free assignment into create_card(), immediately after usb_get_dev(), ensuring that every error path reaching snd_card_free() balances the reference [1]. Users should update to a kernel version containing this commit (e.g., stable releases that backport the fix). No workaround is available; the only mitigation is to apply the kernel patch.

AI Insight generated on May 27, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

2

Patches

10
50c6a1f05973

ALSA: caiaq: fix usb_dev refcount leak on probe failure

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitDeepanshu KartikeyApr 26, 2026Fixed in 6.6.140via kernel-cna
1 file changed · +1 2
  • sound/usb/caiaq/device.c+1 2 modified
    diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
    index e78980ab17567d..b20aae0caf60a4 100644
    --- a/sound/usb/caiaq/device.c
    +++ b/sound/usb/caiaq/device.c
    @@ -423,6 +423,7 @@ static int create_card(struct usb_device *usb_dev,
     
     	cdev = caiaqdev(card);
     	cdev->chip.dev = usb_get_dev(usb_dev);
    +	card->private_free = card_free;
     	cdev->chip.card = card;
     	cdev->chip.usb_id = USB_ID(le16_to_cpu(usb_dev->descriptor.idVendor),
     				  le16_to_cpu(usb_dev->descriptor.idProduct));
    @@ -511,7 +512,6 @@ static int init_card(struct snd_usb_caiaqdev *cdev)
     	scnprintf(card->longname, sizeof(card->longname), "%s %s (%s)",
     		       cdev->vendor_name, cdev->product_name, usbpath);
     
    -	card->private_free = card_free;
     	err = setup_card(cdev);
     	if (err < 0)
     		goto err_kill_urb;
    -- 
    cgit 1.3-korg
    
    
    
da3b8fd6a202

ALSA: caiaq: fix usb_dev refcount leak on probe failure

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitDeepanshu KartikeyApr 26, 2026Fixed in 6.12.86via kernel-cna
1 file changed · +1 2
  • sound/usb/caiaq/device.c+1 2 modified
    diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
    index e78980ab17567d..b20aae0caf60a4 100644
    --- a/sound/usb/caiaq/device.c
    +++ b/sound/usb/caiaq/device.c
    @@ -423,6 +423,7 @@ static int create_card(struct usb_device *usb_dev,
     
     	cdev = caiaqdev(card);
     	cdev->chip.dev = usb_get_dev(usb_dev);
    +	card->private_free = card_free;
     	cdev->chip.card = card;
     	cdev->chip.usb_id = USB_ID(le16_to_cpu(usb_dev->descriptor.idVendor),
     				  le16_to_cpu(usb_dev->descriptor.idProduct));
    @@ -511,7 +512,6 @@ static int init_card(struct snd_usb_caiaqdev *cdev)
     	scnprintf(card->longname, sizeof(card->longname), "%s %s (%s)",
     		       cdev->vendor_name, cdev->product_name, usbpath);
     
    -	card->private_free = card_free;
     	err = setup_card(cdev);
     	if (err < 0)
     		goto err_kill_urb;
    -- 
    cgit 1.3-korg
    
    
    
6153878c5255

ALSA: caiaq: fix usb_dev refcount leak on probe failure

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitDeepanshu KartikeyApr 26, 2026Fixed in 6.18.27via kernel-cna
1 file changed · +1 2
  • sound/usb/caiaq/device.c+1 2 modified
    diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
    index e78980ab17567d..b20aae0caf60a4 100644
    --- a/sound/usb/caiaq/device.c
    +++ b/sound/usb/caiaq/device.c
    @@ -423,6 +423,7 @@ static int create_card(struct usb_device *usb_dev,
     
     	cdev = caiaqdev(card);
     	cdev->chip.dev = usb_get_dev(usb_dev);
    +	card->private_free = card_free;
     	cdev->chip.card = card;
     	cdev->chip.usb_id = USB_ID(le16_to_cpu(usb_dev->descriptor.idVendor),
     				  le16_to_cpu(usb_dev->descriptor.idProduct));
    @@ -511,7 +512,6 @@ static int init_card(struct snd_usb_caiaqdev *cdev)
     	scnprintf(card->longname, sizeof(card->longname), "%s %s (%s)",
     		       cdev->vendor_name, cdev->product_name, usbpath);
     
    -	card->private_free = card_free;
     	err = setup_card(cdev);
     	if (err < 0)
     		goto err_kill_urb;
    -- 
    cgit 1.3-korg
    
    
    
21ca595aafa4

ALSA: caiaq: fix usb_dev refcount leak on probe failure

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitDeepanshu KartikeyApr 26, 2026Fixed in 7.0.4via kernel-cna
1 file changed · +1 2
  • sound/usb/caiaq/device.c+1 2 modified
    diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
    index e78980ab17567d..b20aae0caf60a4 100644
    --- a/sound/usb/caiaq/device.c
    +++ b/sound/usb/caiaq/device.c
    @@ -423,6 +423,7 @@ static int create_card(struct usb_device *usb_dev,
     
     	cdev = caiaqdev(card);
     	cdev->chip.dev = usb_get_dev(usb_dev);
    +	card->private_free = card_free;
     	cdev->chip.card = card;
     	cdev->chip.usb_id = USB_ID(le16_to_cpu(usb_dev->descriptor.idVendor),
     				  le16_to_cpu(usb_dev->descriptor.idProduct));
    @@ -511,7 +512,6 @@ static int init_card(struct snd_usb_caiaqdev *cdev)
     	scnprintf(card->longname, sizeof(card->longname), "%s %s (%s)",
     		       cdev->vendor_name, cdev->product_name, usbpath);
     
    -	card->private_free = card_free;
     	err = setup_card(cdev);
     	if (err < 0)
     		goto err_kill_urb;
    -- 
    cgit 1.3-korg
    
    
    
7a5f1cd22d47

ALSA: caiaq: fix usb_dev refcount leak on probe failure

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitDeepanshu KartikeyApr 26, 2026Fixed in 7.1-rc2via kernel-cna
1 file changed · +1 2
  • sound/usb/caiaq/device.c+1 2 modified
    diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
    index 8af0c04041ee3e..ad9f744b496bfb 100644
    --- a/sound/usb/caiaq/device.c
    +++ b/sound/usb/caiaq/device.c
    @@ -423,6 +423,7 @@ static int create_card(struct usb_device *usb_dev,
     
     	cdev = caiaqdev(card);
     	cdev->chip.dev = usb_get_dev(usb_dev);
    +	card->private_free = card_free;
     	cdev->chip.card = card;
     	cdev->chip.usb_id = USB_ID(le16_to_cpu(usb_dev->descriptor.idVendor),
     				  le16_to_cpu(usb_dev->descriptor.idProduct));
    @@ -511,7 +512,6 @@ static int init_card(struct snd_usb_caiaqdev *cdev)
     	scnprintf(card->longname, sizeof(card->longname), "%s %s (%s)",
     		       cdev->vendor_name, cdev->product_name, usbpath);
     
    -	card->private_free = card_free;
     	err = setup_card(cdev);
     	if (err < 0)
     		return err;
    -- 
    cgit 1.3-korg
    
    
    
50c6a1f05973

ALSA: caiaq: fix usb_dev refcount leak on probe failure

1 file changed · +1 2
  • sound/usb/caiaq/device.c+1 2 modified
    diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
    index e78980ab17567d..b20aae0caf60a4 100644
    --- a/sound/usb/caiaq/device.c
    +++ b/sound/usb/caiaq/device.c
    @@ -423,6 +423,7 @@ static int create_card(struct usb_device *usb_dev,
     
     	cdev = caiaqdev(card);
     	cdev->chip.dev = usb_get_dev(usb_dev);
    +	card->private_free = card_free;
     	cdev->chip.card = card;
     	cdev->chip.usb_id = USB_ID(le16_to_cpu(usb_dev->descriptor.idVendor),
     				  le16_to_cpu(usb_dev->descriptor.idProduct));
    @@ -511,7 +512,6 @@ static int init_card(struct snd_usb_caiaqdev *cdev)
     	scnprintf(card->longname, sizeof(card->longname), "%s %s (%s)",
     		       cdev->vendor_name, cdev->product_name, usbpath);
     
    -	card->private_free = card_free;
     	err = setup_card(cdev);
     	if (err < 0)
     		goto err_kill_urb;
    -- 
    cgit 1.3-korg
    
    
    
da3b8fd6a202

ALSA: caiaq: fix usb_dev refcount leak on probe failure

1 file changed · +1 2
  • sound/usb/caiaq/device.c+1 2 modified
    diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
    index e78980ab17567d..b20aae0caf60a4 100644
    --- a/sound/usb/caiaq/device.c
    +++ b/sound/usb/caiaq/device.c
    @@ -423,6 +423,7 @@ static int create_card(struct usb_device *usb_dev,
     
     	cdev = caiaqdev(card);
     	cdev->chip.dev = usb_get_dev(usb_dev);
    +	card->private_free = card_free;
     	cdev->chip.card = card;
     	cdev->chip.usb_id = USB_ID(le16_to_cpu(usb_dev->descriptor.idVendor),
     				  le16_to_cpu(usb_dev->descriptor.idProduct));
    @@ -511,7 +512,6 @@ static int init_card(struct snd_usb_caiaqdev *cdev)
     	scnprintf(card->longname, sizeof(card->longname), "%s %s (%s)",
     		       cdev->vendor_name, cdev->product_name, usbpath);
     
    -	card->private_free = card_free;
     	err = setup_card(cdev);
     	if (err < 0)
     		goto err_kill_urb;
    -- 
    cgit 1.3-korg
    
    
    
21ca595aafa4

ALSA: caiaq: fix usb_dev refcount leak on probe failure

1 file changed · +1 2
  • sound/usb/caiaq/device.c+1 2 modified
    diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
    index e78980ab17567d..b20aae0caf60a4 100644
    --- a/sound/usb/caiaq/device.c
    +++ b/sound/usb/caiaq/device.c
    @@ -423,6 +423,7 @@ static int create_card(struct usb_device *usb_dev,
     
     	cdev = caiaqdev(card);
     	cdev->chip.dev = usb_get_dev(usb_dev);
    +	card->private_free = card_free;
     	cdev->chip.card = card;
     	cdev->chip.usb_id = USB_ID(le16_to_cpu(usb_dev->descriptor.idVendor),
     				  le16_to_cpu(usb_dev->descriptor.idProduct));
    @@ -511,7 +512,6 @@ static int init_card(struct snd_usb_caiaqdev *cdev)
     	scnprintf(card->longname, sizeof(card->longname), "%s %s (%s)",
     		       cdev->vendor_name, cdev->product_name, usbpath);
     
    -	card->private_free = card_free;
     	err = setup_card(cdev);
     	if (err < 0)
     		goto err_kill_urb;
    -- 
    cgit 1.3-korg
    
    
    
7a5f1cd22d47

ALSA: caiaq: fix usb_dev refcount leak on probe failure

1 file changed · +1 2
  • sound/usb/caiaq/device.c+1 2 modified
    diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
    index 8af0c04041ee3e..ad9f744b496bfb 100644
    --- a/sound/usb/caiaq/device.c
    +++ b/sound/usb/caiaq/device.c
    @@ -423,6 +423,7 @@ static int create_card(struct usb_device *usb_dev,
     
     	cdev = caiaqdev(card);
     	cdev->chip.dev = usb_get_dev(usb_dev);
    +	card->private_free = card_free;
     	cdev->chip.card = card;
     	cdev->chip.usb_id = USB_ID(le16_to_cpu(usb_dev->descriptor.idVendor),
     				  le16_to_cpu(usb_dev->descriptor.idProduct));
    @@ -511,7 +512,6 @@ static int init_card(struct snd_usb_caiaqdev *cdev)
     	scnprintf(card->longname, sizeof(card->longname), "%s %s (%s)",
     		       cdev->vendor_name, cdev->product_name, usbpath);
     
    -	card->private_free = card_free;
     	err = setup_card(cdev);
     	if (err < 0)
     		return err;
    -- 
    cgit 1.3-korg
    
    
    
6153878c5255

ALSA: caiaq: fix usb_dev refcount leak on probe failure

1 file changed · +1 2
  • sound/usb/caiaq/device.c+1 2 modified
    diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
    index e78980ab17567d..b20aae0caf60a4 100644
    --- a/sound/usb/caiaq/device.c
    +++ b/sound/usb/caiaq/device.c
    @@ -423,6 +423,7 @@ static int create_card(struct usb_device *usb_dev,
     
     	cdev = caiaqdev(card);
     	cdev->chip.dev = usb_get_dev(usb_dev);
    +	card->private_free = card_free;
     	cdev->chip.card = card;
     	cdev->chip.usb_id = USB_ID(le16_to_cpu(usb_dev->descriptor.idVendor),
     				  le16_to_cpu(usb_dev->descriptor.idProduct));
    @@ -511,7 +512,6 @@ static int init_card(struct snd_usb_caiaqdev *cdev)
     	scnprintf(card->longname, sizeof(card->longname), "%s %s (%s)",
     		       cdev->vendor_name, cdev->product_name, usbpath);
     
    -	card->private_free = card_free;
     	err = setup_card(cdev);
     	if (err < 0)
     		goto err_kill_urb;
    -- 
    cgit 1.3-korg
    
    
    

Vulnerability mechanics

Root cause

"The snd_card's ->private_free destructor (card_free), which calls usb_put_dev(), was assigned too late in init_card(), after several failure points, so any probe failure before that assignment caused the usb_get_dev() reference taken in create_card() to never be released."

Attack vector

An attacker with physical access to a USB port can plug a malformed UAC3 device whose only valid altsetting is 0. When the caiaq driver probes this device, init_card() calls usb_set_interface(usb_dev, 0, 1), which fails with -EIO. Because the ->private_free destructor had not yet been assigned at that point in the code path, snd_card_free() does not invoke card_free(), and the usb_get_dev() reference taken in create_card() is never dropped. This leaks the struct usb_device along with its descriptor allocations and device_private [patch_id=2660149].

Affected code

The bug is in sound/usb/caiaq/device.c, in the functions create_card() and init_card(). The assignment `card->private_free = card_free` was originally placed at line 512 inside init_card(), after several failure points (usb_set_interface, endpoint type checks, usb_submit_urb, EP1_CMD_GET_DEVICE_INFO exchange). The patch moves it to line 423 in create_card(), right after the usb_get_dev() call [patch_id=2660149].

What the fix does

The patch moves the `card->private_free = card_free` assignment from near the end of init_card() (sound/usb/caiaq/device.c line 512) to immediately after `usb_get_dev()` in create_card() (line 423). This ensures that snd_card_free() on any error path will call card_free(), which drops the USB device reference via usb_put_dev(). The callees of card_free() (snd_usb_caiaq_input_free, free_urbs, kfree) are safe to call on a partially-initialized chip because the private area is zero-initialized by snd_card_new() [patch_id=2660149].

Preconditions

  • physical_accessAttacker must have physical access to a USB port to connect a malicious or malformed USB device.
  • inputThe malformed device must present itself as a UAC3 device whose only valid altsetting is 0, causing usb_set_interface() to fail with -EIO.
  • configThe caiaq driver must be loaded and probe the device.

Generated on May 27, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.