ALSA: pcm: Fix UAF in snd_pcm_oss_get_formats()
authorTakashi Iwai <tiwai@suse.de>
Sat, 10 Mar 2018 22:04:23 +0000 (23:04 +0100)
committerTakashi Iwai <tiwai@suse.de>
Sun, 11 Mar 2018 09:25:10 +0000 (10:25 +0100)
snd_pcm_oss_get_formats() has an obvious use-after-free around
snd_mask_test() calls, as spotted by syzbot.  The passed format_mask
argument is a pointer to the hw_params object that is freed before the
loop.  What a surprise that it has been present since the original
code of decades ago...

Reported-by: syzbot+4090700a4f13fccaf648@syzkaller.appspotmail.com
Cc: <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/core/oss/pcm_oss.c

index b044c0a5a674b116e9441c13558deb0c0a4e70f9..02298c9c602046b56406b7da87d0c86ff89f2a24 100644 (file)
@@ -1762,10 +1762,9 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
                return -ENOMEM;
        _snd_pcm_hw_params_any(params);
        err = snd_pcm_hw_refine(substream, params);
-       format_mask = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
-       kfree(params);
        if (err < 0)
-               return err;
+               goto error;
+       format_mask = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
        for (fmt = 0; fmt < 32; ++fmt) {
                if (snd_mask_test(format_mask, fmt)) {
                        int f = snd_pcm_oss_format_to(fmt);
@@ -1773,7 +1772,10 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
                                formats |= f;
                }
        }
-       return formats;
+
+ error:
+       kfree(params);
+       return err < 0 ? err : formats;
 }
 
 static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int format)