Takashi Iwai c7c3df
From b088b53e20c7d09b5ab84c5688e609f478e5c417 Mon Sep 17 00:00:00 2001
Takashi Iwai c7c3df
From: Takashi Iwai <tiwai@suse.de>
Takashi Iwai c7c3df
Date: Fri, 5 Jan 2018 16:15:33 +0100
Takashi Iwai c7c3df
Subject: [PATCH] ALSA: aloop: Fix inconsistent format due to incomplete rule
Takashi Iwai c7c3df
Git-commit: b088b53e20c7d09b5ab84c5688e609f478e5c417
Takashi Iwai c7c3df
Patch-mainline: v4.15-rc8
Takashi Iwai c7c3df
References: bsc#1051510
Takashi Iwai c7c3df
Takashi Iwai c7c3df
The extra hw constraint rule for the formats the aloop driver
Takashi Iwai c7c3df
introduced has a slight flaw, where it doesn't return a positive value
Takashi Iwai c7c3df
when the mask got changed.  It came from the fact that it's basically
Takashi Iwai c7c3df
a copy&paste from snd_hw_constraint_mask64().  The original code is
Takashi Iwai c7c3df
supposed to be a single-shot and it modifies the mask bits only once
Takashi Iwai c7c3df
and never after, while what we need for aloop is the dynamic hw rule
Takashi Iwai c7c3df
that limits the mask bits.
Takashi Iwai c7c3df
Takashi Iwai c7c3df
This difference results in the inconsistent state, as the hw_refine
Takashi Iwai c7c3df
doesn't apply the dependencies fully.  The worse and surprisingly
Takashi Iwai c7c3df
result is that it causes a crash in OSS emulation when multiple
Takashi Iwai c7c3df
full-duplex reads/writes are performed concurrently (I leave why it
Takashi Iwai c7c3df
triggers Oops to readers as a homework).
Takashi Iwai c7c3df
Takashi Iwai c7c3df
For fixing this, replace a few open-codes with the standard
Takashi Iwai c7c3df
snd_mask_*() macros.
Takashi Iwai c7c3df
Takashi Iwai c7c3df
Reported-by: syzbot+3902b5220e8ca27889ca@syzkaller.appspotmail.com
Takashi Iwai c7c3df
Fixes: b1c73fc8e697 ("ALSA: snd-aloop: Fix hw_params restrictions and checking")
Takashi Iwai c7c3df
Cc: <stable@vger.kernel.org>
Takashi Iwai c7c3df
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Takashi Iwai c7c3df
Takashi Iwai c7c3df
---
Takashi Iwai c7c3df
 sound/drivers/aloop.c |   13 ++++++-------
Takashi Iwai c7c3df
 1 file changed, 6 insertions(+), 7 deletions(-)
Takashi Iwai c7c3df
Takashi Iwai c7c3df
--- a/sound/drivers/aloop.c
Takashi Iwai c7c3df
+++ b/sound/drivers/aloop.c
Takashi Iwai c7c3df
@@ -39,6 +39,7 @@
Takashi Iwai c7c3df
 #include <sound/core.h>
Takashi Iwai c7c3df
 #include <sound/control.h>
Takashi Iwai c7c3df
 #include <sound/pcm.h>
Takashi Iwai c7c3df
+#include <sound/pcm_params.h>
Takashi Iwai c7c3df
 #include <sound/info.h>
Takashi Iwai c7c3df
 #include <sound/initval.h>
Takashi Iwai c7c3df
 
Takashi Iwai c7c3df
@@ -622,14 +623,12 @@ static int rule_format(struct snd_pcm_hw
Takashi Iwai c7c3df
 {
Takashi Iwai c7c3df
 
Takashi Iwai c7c3df
 	struct snd_pcm_hardware *hw = rule->private;
Takashi Iwai c7c3df
-	struct snd_mask *maskp = hw_param_mask(params, rule->var);
Takashi Iwai c7c3df
+	struct snd_mask m;
Takashi Iwai c7c3df
 
Takashi Iwai c7c3df
-	maskp->bits[0] &= (u_int32_t)hw->formats;
Takashi Iwai c7c3df
-	maskp->bits[1] &= (u_int32_t)(hw->formats >> 32);
Takashi Iwai c7c3df
-	memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX-64) / 8); /* clear rest */
Takashi Iwai c7c3df
-	if (! maskp->bits[0] && ! maskp->bits[1])
Takashi Iwai c7c3df
-		return -EINVAL;
Takashi Iwai c7c3df
-	return 0;
Takashi Iwai c7c3df
+	snd_mask_none(&m);
Takashi Iwai c7c3df
+	m.bits[0] = (u_int32_t)hw->formats;
Takashi Iwai c7c3df
+	m.bits[1] = (u_int32_t)(hw->formats >> 32);
Takashi Iwai c7c3df
+	return snd_mask_refine(hw_param_mask(params, rule->var), &m);
Takashi Iwai c7c3df
 }
Takashi Iwai c7c3df
 
Takashi Iwai c7c3df
 static int rule_rate(struct snd_pcm_hw_params *params,