lkml.org 
[lkml]   [2020]   [Jun]   [29]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.4 107/135] ALSA: usb-audio: Fix OOB access of mixer element list
    Date
    From: Takashi Iwai <tiwai@suse.de>

    [ Upstream commit 220345e98f1cdc768eeb6e3364a0fa7ab9647fe7 ]

    The USB-audio mixer code holds a linked list of usb_mixer_elem_list,
    and several operations are performed for each mixer element. A few of
    them (snd_usb_mixer_notify_id() and snd_usb_mixer_interrupt_v2())
    assume each mixer element being a usb_mixer_elem_info object that is a
    subclass of usb_mixer_elem_list, cast via container_of() and access it
    members. This may result in an out-of-bound access when a
    non-standard list element has been added, as spotted by syzkaller
    recently.

    This patch adds a new field, is_std_info, in usb_mixer_elem_list to
    indicate that the element is the usb_mixer_elem_info type or not, and
    skip the access to such an element if needed.

    Reported-by: syzbot+fb14314433463ad51625@syzkaller.appspotmail.com
    Reported-by: syzbot+2405ca3401e943c538b5@syzkaller.appspotmail.com
    Cc: <stable@vger.kernel.org>
    Link: https://lore.kernel.org/r/20200624122340.9615-1-tiwai@suse.de
    Signed-off-by: Takashi Iwai <tiwai@suse.de>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    sound/usb/mixer.c | 15 +++++++++++----
    sound/usb/mixer.h | 9 +++++++--
    sound/usb/mixer_quirks.c | 3 ++-
    3 files changed, 20 insertions(+), 7 deletions(-)

    diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
    index c29931cd461fc..9b9d653d5e90b 100644
    --- a/sound/usb/mixer.c
    +++ b/sound/usb/mixer.c
    @@ -584,8 +584,9 @@ static int check_matrix_bitmap(unsigned char *bmap,
    * if failed, give up and free the control instance.
    */

    -int snd_usb_mixer_add_control(struct usb_mixer_elem_list *list,
    - struct snd_kcontrol *kctl)
    +int snd_usb_mixer_add_list(struct usb_mixer_elem_list *list,
    + struct snd_kcontrol *kctl,
    + bool is_std_info)
    {
    struct usb_mixer_interface *mixer = list->mixer;
    int err;
    @@ -598,6 +599,7 @@ int snd_usb_mixer_add_control(struct usb_mixer_elem_list *list,
    return err;
    }
    list->kctl = kctl;
    + list->is_std_info = is_std_info;
    list->next_id_elem = mixer->id_elems[list->id];
    mixer->id_elems[list->id] = list;
    return 0;
    @@ -2331,8 +2333,11 @@ void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid)
    struct usb_mixer_elem_list *list;

    for_each_mixer_elem(list, mixer, unitid) {
    - struct usb_mixer_elem_info *info =
    - mixer_elem_list_to_info(list);
    + struct usb_mixer_elem_info *info;
    +
    + if (!list->is_std_info)
    + continue;
    + info = mixer_elem_list_to_info(list);
    /* invalidate cache, so the value is read from the device */
    info->cached = 0;
    snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
    @@ -2410,6 +2415,8 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer,

    if (!list->kctl)
    continue;
    + if (!list->is_std_info)
    + continue;

    info = mixer_elem_list_to_info(list);
    if (count > 1 && info->control != control)
    diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h
    index 004d99037210f..7d16a92210705 100644
    --- a/sound/usb/mixer.h
    +++ b/sound/usb/mixer.h
    @@ -48,6 +48,7 @@ struct usb_mixer_elem_list {
    struct usb_mixer_elem_list *next_id_elem; /* list of controls with same id */
    struct snd_kcontrol *kctl;
    unsigned int id;
    + bool is_std_info;
    usb_mixer_elem_dump_func_t dump;
    usb_mixer_elem_resume_func_t resume;
    };
    @@ -85,8 +86,12 @@ void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid);
    int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
    int request, int validx, int value_set);

    -int snd_usb_mixer_add_control(struct usb_mixer_elem_list *list,
    - struct snd_kcontrol *kctl);
    +int snd_usb_mixer_add_list(struct usb_mixer_elem_list *list,
    + struct snd_kcontrol *kctl,
    + bool is_std_info);
    +
    +#define snd_usb_mixer_add_control(list, kctl) \
    + snd_usb_mixer_add_list(list, kctl, true)

    void snd_usb_mixer_elem_init_std(struct usb_mixer_elem_list *list,
    struct usb_mixer_interface *mixer,
    diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
    index 5d6af9c861ad9..198515f86fcc2 100644
    --- a/sound/usb/mixer_quirks.c
    +++ b/sound/usb/mixer_quirks.c
    @@ -168,7 +168,8 @@ static int add_single_ctl_with_resume(struct usb_mixer_interface *mixer,
    return -ENOMEM;
    }
    kctl->private_free = snd_usb_mixer_elem_free;
    - return snd_usb_mixer_add_control(list, kctl);
    + /* don't use snd_usb_mixer_add_control() here, this is a special list element */
    + return snd_usb_mixer_add_list(list, kctl, false);
    }

    /*
    --
    2.25.1
    \
     
     \ /
      Last update: 2020-06-29 20:57    [W:2.224 / U:0.020 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site