mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
ALSA: usb-audio: Fix data race at mixer_ctl_feature_info()
The info callback for USB-audio mixer controls for feature unit has a dynamic initialization of the contents with the check of cval->initialized flag. But, since the info callback may be concurrently called, this may lead to a data race, giving back an inconsistent state. Similarly, get and put callbacks may have concurrent accesses and can get bogus states. For avoiding the data race, introduce a mutex locking for the controls and protect against concurrent info callback calls. Reported-by: Sashiko <sashiko-bot@kernel.org> Signed-off-by: Takashi Iwai <tiwai@suse.de> Link: https://patch.msgid.link/20261007172051.13240-6-tiwai@suse.de
This commit is contained in:
parent
c01fb2ed90
commit
f701f6738d
|
|
@ -1531,6 +1531,7 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol,
|
|||
struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol);
|
||||
int ret;
|
||||
|
||||
guard(mutex)(&cval->head.mixer->lock);
|
||||
if (cval->val_type == USB_MIXER_BOOLEAN ||
|
||||
cval->val_type == USB_MIXER_INV_BOOLEAN)
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
|
||||
|
|
@ -1565,6 +1566,7 @@ static int mixer_ctl_feature_get(struct snd_kcontrol *kcontrol,
|
|||
struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol);
|
||||
int c, cnt, val, err;
|
||||
|
||||
guard(mutex)(&cval->head.mixer->lock);
|
||||
ucontrol->value.integer.value[0] = cval->min;
|
||||
if (cval->cmask) {
|
||||
cnt = 0;
|
||||
|
|
@ -1595,10 +1597,12 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol);
|
||||
int max_val = get_max_exposed(cval);
|
||||
int max_val;
|
||||
int c, cnt, val, oval, err;
|
||||
int changed = 0;
|
||||
|
||||
guard(mutex)(&cval->head.mixer->lock);
|
||||
max_val = get_max_exposed(cval);
|
||||
if (cval->cmask) {
|
||||
cnt = 0;
|
||||
for (c = 0; c < MAX_CHANNELS; c++) {
|
||||
|
|
@ -1646,6 +1650,7 @@ static int mixer_ctl_master_bool_get(struct snd_kcontrol *kcontrol,
|
|||
struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol);
|
||||
int val, err;
|
||||
|
||||
guard(mutex)(&cval->head.mixer->lock);
|
||||
err = snd_usb_get_cur_mix_value(cval, 0, 0, &val);
|
||||
if (err < 0)
|
||||
return filter_error(cval, err);
|
||||
|
|
@ -2592,6 +2597,7 @@ static int mixer_ctl_procunit_get(struct snd_kcontrol *kcontrol,
|
|||
struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol);
|
||||
int err, val;
|
||||
|
||||
guard(mutex)(&cval->head.mixer->lock);
|
||||
err = get_cur_ctl_value(cval, cval->control << 8, &val);
|
||||
if (err < 0) {
|
||||
ucontrol->value.integer.value[0] = cval->min;
|
||||
|
|
@ -2609,6 +2615,7 @@ static int mixer_ctl_procunit_put(struct snd_kcontrol *kcontrol,
|
|||
struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol);
|
||||
int val, oval, err;
|
||||
|
||||
guard(mutex)(&cval->head.mixer->lock);
|
||||
err = get_cur_ctl_value(cval, cval->control << 8, &oval);
|
||||
if (err < 0)
|
||||
return filter_error(cval, err);
|
||||
|
|
@ -2960,6 +2967,7 @@ static int mixer_ctl_selector_get(struct snd_kcontrol *kcontrol,
|
|||
struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol);
|
||||
int val, err;
|
||||
|
||||
guard(mutex)(&cval->head.mixer->lock);
|
||||
err = get_cur_ctl_value(cval, cval->control << 8, &val);
|
||||
if (err < 0) {
|
||||
ucontrol->value.enumerated.item[0] = 0;
|
||||
|
|
@ -2977,6 +2985,7 @@ static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol,
|
|||
struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol);
|
||||
int val, oval, err;
|
||||
|
||||
guard(mutex)(&cval->head.mixer->lock);
|
||||
err = get_cur_ctl_value(cval, cval->control << 8, &oval);
|
||||
if (err < 0)
|
||||
return filter_error(cval, err);
|
||||
|
|
@ -3249,6 +3258,7 @@ static void snd_usb_mixer_free(struct usb_mixer_interface *mixer)
|
|||
}
|
||||
usb_free_urb(mixer->rc_urb);
|
||||
kfree(mixer->rc_setup_packet);
|
||||
mutex_destroy(&mixer->lock);
|
||||
kfree(mixer);
|
||||
}
|
||||
|
||||
|
|
@ -3893,6 +3903,8 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
mutex_init(&mixer->lock);
|
||||
|
||||
mixer->hostif = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0];
|
||||
switch (get_iface_desc(mixer->hostif)->bInterfaceProtocol) {
|
||||
case UAC_VERSION_1:
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ struct usb_mixer_interface {
|
|||
struct usb_host_interface *hostif;
|
||||
struct list_head list;
|
||||
unsigned int ignore_ctl_error;
|
||||
struct mutex lock; /* lock for feature unit callbacks */
|
||||
/* UAC2 status interrupt endpoint; owned by mixer.c */
|
||||
struct urb *urb;
|
||||
/* array[MAX_ID_ELEMS], indexed by unit id */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user