Commit 7aa1cf25 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'sound-fix-4.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound

Pull sound fixes from Takashi Iwai:
 "The main purpose of this pull request is a fix for a regression in the
  recent PCM OSS emulation code that may lead to RCU stall. Since
  syzkaller hits this too often, I send the pull request now with a
  minimal collection. Possibly another pull request may follow before
  RC1.

  The other fixes here are for USB-audio class 2 and 3 to improve the
  parser for the clock descriptors. These are rather cleanups but good
  for security, too.

  Last but not least, another included fix is the trivial one to remove
  superfluous WARN_ON() that annoyed syzbot"

* tag 'sound-fix-4.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound:
  ALSA: pcm: Remove WARN_ON() at snd_pcm_hw_params() error
  ALSA: pcm: Fix endless loop for XRUN recovery in OSS emulation
  ALSA: usb-audio: Add sanity checks in UAC3 clock parsers
  ALSA: usb-audio: More strict sanity checks for clock parsers
  ALSA: usb-audio: Refactor clock finder helpers
parents d3626005 e1a3a981
...@@ -1128,13 +1128,14 @@ static int snd_pcm_oss_get_active_substream(struct snd_pcm_oss_file *pcm_oss_fil ...@@ -1128,13 +1128,14 @@ static int snd_pcm_oss_get_active_substream(struct snd_pcm_oss_file *pcm_oss_fil
} }
/* call with params_lock held */ /* call with params_lock held */
/* NOTE: this always call PREPARE unconditionally no matter whether
* runtime->oss.prepare is set or not
*/
static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream) static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream)
{ {
int err; int err;
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
if (!runtime->oss.prepare)
return 0;
err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL); err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL);
if (err < 0) { if (err < 0) {
pcm_dbg(substream->pcm, pcm_dbg(substream->pcm,
......
...@@ -617,7 +617,7 @@ static int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm, ...@@ -617,7 +617,7 @@ static int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm,
changed = snd_pcm_hw_param_first(pcm, params, *v, NULL); changed = snd_pcm_hw_param_first(pcm, params, *v, NULL);
else else
changed = snd_pcm_hw_param_last(pcm, params, *v, NULL); changed = snd_pcm_hw_param_last(pcm, params, *v, NULL);
if (snd_BUG_ON(changed < 0)) if (changed < 0)
return changed; return changed;
if (changed == 0) if (changed == 0)
continue; continue;
......
...@@ -35,105 +35,85 @@ ...@@ -35,105 +35,85 @@
#include "clock.h" #include "clock.h"
#include "quirks.h" #include "quirks.h"
static struct uac_clock_source_descriptor * static void *find_uac_clock_desc(struct usb_host_interface *iface, int id,
snd_usb_find_clock_source(struct usb_host_interface *ctrl_iface, bool (*validator)(void *, int), u8 type)
int clock_id)
{ {
struct uac_clock_source_descriptor *cs = NULL; void *cs = NULL;
while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra, while ((cs = snd_usb_find_csint_desc(iface->extra, iface->extralen,
ctrl_iface->extralen, cs, type))) {
cs, UAC2_CLOCK_SOURCE))) { if (validator(cs, id))
if (cs->bLength >= sizeof(*cs) && cs->bClockID == clock_id)
return cs; return cs;
} }
return NULL; return NULL;
} }
static struct uac3_clock_source_descriptor * static bool validate_clock_source_v2(void *p, int id)
snd_usb_find_clock_source_v3(struct usb_host_interface *ctrl_iface,
int clock_id)
{ {
struct uac3_clock_source_descriptor *cs = NULL; struct uac_clock_source_descriptor *cs = p;
return cs->bLength == sizeof(*cs) && cs->bClockID == id;
while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra,
ctrl_iface->extralen,
cs, UAC3_CLOCK_SOURCE))) {
if (cs->bClockID == clock_id)
return cs;
}
return NULL;
} }
static struct uac_clock_selector_descriptor * static bool validate_clock_source_v3(void *p, int id)
snd_usb_find_clock_selector(struct usb_host_interface *ctrl_iface,
int clock_id)
{ {
struct uac_clock_selector_descriptor *cs = NULL; struct uac3_clock_source_descriptor *cs = p;
return cs->bLength == sizeof(*cs) && cs->bClockID == id;
while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra,
ctrl_iface->extralen,
cs, UAC2_CLOCK_SELECTOR))) {
if (cs->bLength >= sizeof(*cs) && cs->bClockID == clock_id) {
if (cs->bLength < 5 + cs->bNrInPins)
return NULL;
return cs;
}
}
return NULL;
} }
static struct uac3_clock_selector_descriptor * static bool validate_clock_selector_v2(void *p, int id)
snd_usb_find_clock_selector_v3(struct usb_host_interface *ctrl_iface,
int clock_id)
{ {
struct uac3_clock_selector_descriptor *cs = NULL; struct uac_clock_selector_descriptor *cs = p;
return cs->bLength >= sizeof(*cs) && cs->bClockID == id &&
while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra, cs->bLength == 7 + cs->bNrInPins;
ctrl_iface->extralen,
cs, UAC3_CLOCK_SELECTOR))) {
if (cs->bClockID == clock_id)
return cs;
}
return NULL;
} }
static struct uac_clock_multiplier_descriptor * static bool validate_clock_selector_v3(void *p, int id)
snd_usb_find_clock_multiplier(struct usb_host_interface *ctrl_iface,
int clock_id)
{ {
struct uac_clock_multiplier_descriptor *cs = NULL; struct uac3_clock_selector_descriptor *cs = p;
return cs->bLength >= sizeof(*cs) && cs->bClockID == id &&
while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra, cs->bLength == 11 + cs->bNrInPins;
ctrl_iface->extralen,
cs, UAC2_CLOCK_MULTIPLIER))) {
if (cs->bLength >= sizeof(*cs) && cs->bClockID == clock_id)
return cs;
}
return NULL;
} }
static struct uac3_clock_multiplier_descriptor * static bool validate_clock_multiplier_v2(void *p, int id)
snd_usb_find_clock_multiplier_v3(struct usb_host_interface *ctrl_iface,
int clock_id)
{ {
struct uac3_clock_multiplier_descriptor *cs = NULL; struct uac_clock_multiplier_descriptor *cs = p;
return cs->bLength == sizeof(*cs) && cs->bClockID == id;
}
while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra, static bool validate_clock_multiplier_v3(void *p, int id)
ctrl_iface->extralen, {
cs, UAC3_CLOCK_MULTIPLIER))) { struct uac3_clock_multiplier_descriptor *cs = p;
if (cs->bClockID == clock_id) return cs->bLength == sizeof(*cs) && cs->bClockID == id;
return cs; }
}
return NULL; #define DEFINE_FIND_HELPER(name, obj, validator, type) \
static obj *name(struct usb_host_interface *iface, int id) \
{ \
return find_uac_clock_desc(iface, id, validator, type); \
} }
DEFINE_FIND_HELPER(snd_usb_find_clock_source,
struct uac_clock_source_descriptor,
validate_clock_source_v2, UAC2_CLOCK_SOURCE);
DEFINE_FIND_HELPER(snd_usb_find_clock_source_v3,
struct uac3_clock_source_descriptor,
validate_clock_source_v3, UAC3_CLOCK_SOURCE);
DEFINE_FIND_HELPER(snd_usb_find_clock_selector,
struct uac_clock_selector_descriptor,
validate_clock_selector_v2, UAC2_CLOCK_SELECTOR);
DEFINE_FIND_HELPER(snd_usb_find_clock_selector_v3,
struct uac3_clock_selector_descriptor,
validate_clock_selector_v3, UAC3_CLOCK_SELECTOR);
DEFINE_FIND_HELPER(snd_usb_find_clock_multiplier,
struct uac_clock_multiplier_descriptor,
validate_clock_multiplier_v2, UAC2_CLOCK_MULTIPLIER);
DEFINE_FIND_HELPER(snd_usb_find_clock_multiplier_v3,
struct uac3_clock_multiplier_descriptor,
validate_clock_multiplier_v3, UAC3_CLOCK_MULTIPLIER);
static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_id) static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_id)
{ {
unsigned char buf; unsigned char buf;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment