mirror of
https://github.com/LineageOS/android_kernel_fxtec_sm6115.git
synced 2026-08-18 15:01:07 +00:00
ALSA: 6fire: fix use-after-free on disconnect
commit b9c826916fdce6419b94eb0cd8810fdac18c2386 upstream.
In usb6fire_chip_abort(), the chip struct is allocated as the card's
private data (via snd_card_new with sizeof(struct sfire_chip)). When
snd_card_free_when_closed() is called and no file handles are open, the
card and embedded chip are freed synchronously. The subsequent
chip->card = NULL write then hits freed slab memory.
Call trace:
usb6fire_chip_abort sound/usb/6fire/chip.c:59 [inline]
usb6fire_chip_disconnect+0x348/0x358 sound/usb/6fire/chip.c:182
usb_unbind_interface+0x1a8/0x88c drivers/usb/core/driver.c:458
...
hub_event+0x1a04/0x4518 drivers/usb/core/hub.c:5953
Fix by moving the card lifecycle out of usb6fire_chip_abort() and into
usb6fire_chip_disconnect(). The card pointer is saved in a local
before any teardown, snd_card_disconnect() is called first to prevent
new opens, URBs are aborted while chip is still valid, and
snd_card_free_when_closed() is called last so chip is never accessed
after the card may be freed.
Fixes: a0810c3d6dd2 ("ALSA: 6fire: Release resources at card release")
Cc: stable@vger.kernel.org
Cc: Andrey Konovalov <andreyknvl@gmail.com>
Signed-off-by: Berk Cem Goksel <berkcgoksel@gmail.com>
Link: https://patch.msgid.link/20260410051341.1069716-1-berkcgoksel@gmail.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Ulrich Hecht <uli@kernel.org>
This commit is contained in:
committed by
Ulrich Hecht
parent
28de3a9075
commit
3e69dc4eae
@ -58,11 +58,6 @@ static void usb6fire_chip_abort(struct sfire_chip *chip)
|
||||
usb6fire_comm_abort(chip);
|
||||
if (chip->control)
|
||||
usb6fire_control_abort(chip);
|
||||
if (chip->card) {
|
||||
snd_card_disconnect(chip->card);
|
||||
snd_card_free_when_closed(chip->card);
|
||||
chip->card = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -175,6 +170,7 @@ destroy_chip:
|
||||
static void usb6fire_chip_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
struct sfire_chip *chip;
|
||||
struct snd_card *card;
|
||||
|
||||
chip = usb_get_intfdata(intf);
|
||||
if (chip) { /* if !chip, fw upload has been performed */
|
||||
@ -185,8 +181,19 @@ static void usb6fire_chip_disconnect(struct usb_interface *intf)
|
||||
chips[chip->regidx] = NULL;
|
||||
mutex_unlock(®ister_mutex);
|
||||
|
||||
/*
|
||||
* Save card pointer before teardown.
|
||||
* snd_card_free_when_closed() may free card (and
|
||||
* the embedded chip) immediately, so it must be
|
||||
* called last and chip must not be accessed after.
|
||||
*/
|
||||
card = chip->card;
|
||||
chip->shutdown = true;
|
||||
if (card)
|
||||
snd_card_disconnect(card);
|
||||
usb6fire_chip_abort(chip);
|
||||
if (card)
|
||||
snd_card_free_when_closed(card);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user