summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2018-01-05 16:15:33 +0100
committerBen Hutchings <ben@decadent.org.uk>2018-03-03 15:52:14 +0000
commit97f9eaacded09ec3c6ec0a50279af3a0708f8799 (patch)
tree4bd0208a2b83c07b60d0b68bbba91415e8f999c1
parent8418d2262143ce2f1e7171c3fb1e0896a7a9d009 (diff)
ALSA: aloop: Fix inconsistent format due to incomplete rule
commit b088b53e20c7d09b5ab84c5688e609f478e5c417 upstream. The extra hw constraint rule for the formats the aloop driver introduced has a slight flaw, where it doesn't return a positive value when the mask got changed. It came from the fact that it's basically a copy&paste from snd_hw_constraint_mask64(). The original code is supposed to be a single-shot and it modifies the mask bits only once and never after, while what we need for aloop is the dynamic hw rule that limits the mask bits. This difference results in the inconsistent state, as the hw_refine doesn't apply the dependencies fully. The worse and surprisingly result is that it causes a crash in OSS emulation when multiple full-duplex reads/writes are performed concurrently (I leave why it triggers Oops to readers as a homework). For fixing this, replace a few open-codes with the standard snd_mask_*() macros. Reported-by: syzbot+3902b5220e8ca27889ca@syzkaller.appspotmail.com Fixes: b1c73fc8e697 ("ALSA: snd-aloop: Fix hw_params restrictions and checking") Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
-rw-r--r--sound/drivers/aloop.c13
1 files changed, 6 insertions, 7 deletions
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
index 65beb96a0273..fef1b0da2826 100644
--- a/sound/drivers/aloop.c
+++ b/sound/drivers/aloop.c
@@ -39,6 +39,7 @@
#include <sound/core.h>
#include <sound/control.h>
#include <sound/pcm.h>
+#include <sound/pcm_params.h>
#include <sound/info.h>
#include <sound/initval.h>
@@ -623,14 +624,12 @@ static int rule_format(struct snd_pcm_hw_params *params,
{
struct snd_pcm_hardware *hw = rule->private;
- struct snd_mask *maskp = hw_param_mask(params, rule->var);
+ struct snd_mask m;
- maskp->bits[0] &= (u_int32_t)hw->formats;
- maskp->bits[1] &= (u_int32_t)(hw->formats >> 32);
- memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX-64) / 8); /* clear rest */
- if (! maskp->bits[0] && ! maskp->bits[1])
- return -EINVAL;
- return 0;
+ snd_mask_none(&m);
+ m.bits[0] = (u_int32_t)hw->formats;
+ m.bits[1] = (u_int32_t)(hw->formats >> 32);
+ return snd_mask_refine(hw_param_mask(params, rule->var), &m);
}
static int rule_rate(struct snd_pcm_hw_params *params,