• Takashi Iwai's avatar
    ALSA: hda - Fix incorrect TLV callback check introduced during set_fs() removal · a91d6612
    Takashi Iwai authored
    The commit 99b5c5bb ("ALSA: hda - Remove the use of set_fs()")
    converted the get_kctl_0dB_offset() call for killing set_fs() usage in
    HD-audio codec code.  The conversion assumed that the TLV callback
    used in HD-audio code is only snd_hda_mixer_amp() and applies the TLV
    calculation locally.
    
    Although this assumption is correct, and all slave kctls are actually
    with that callback, the current code is still utterly buggy; it
    doesn't hit this condition and falls back to the next check.  It's
    because the function gets called after adding slave kctls to vmaster.
    By assigning a slave kctl, the slave kctl object is faked inside
    vmaster code, and the whole kctl ops are overridden.  Thus the
    callback op points to a different value from what we've assumed.
    
    More badly, as reported by the KERNEXEC and UDEREF features of PaX,
    the code flow turns into the unexpected pitfall.  The next fallback
    check is SNDRV_CTL_ELEM_ACCESS_TLV_READ access bit, and this always
    hits for each kctl with TLV.  Then it evaluates the callback function
    pointer wrongly as if it were a TLV array.  Although currently its
    side-effect is fairly limited, this incorrect reference may lead to an
    unpleasant result.
    
    For addressing the regression, this patch introduces a new helper to
    vmaster code, snd_ctl_apply_vmaster_slaves().  This works similarly
    like the existing map_slaves() in hda_codec.c: it loops over the slave
    list of the given master, and applies the given function to each
    slave.  Then the initializer function receives the right kctl object
    and we can compare the correct pointer instead of the faked one.
    
    Also, for catching the similar breakage in future, give an error
    message when the unexpected TLV callback is found and bail out
    immediately.
    
    Fixes: 99b5c5bb ("ALSA: hda - Remove the use of set_fs()")
    Reported-by: default avatarPaX Team <pageexec@freemail.hu>
    Cc: <stable@vger.kernel.org> # v4.13
    Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
    a91d6612
vmaster.c 13.5 KB