sound fixes for 4.17-rc1

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.
 -----BEGIN PGP SIGNATURE-----
 
 iQJCBAABCAAsFiEEIXTw5fNLNI7mMiVaLtJE4w1nLE8FAlrLiZ4OHHRpd2FpQHN1
 c2UuZGUACgkQLtJE4w1nLE8YshAAr0j8P7eUfHs6laTZhYaTzFmGBHpabL1rIw1U
 QvcqbGDXAACSELud+wQe91nML2vKsv8LE18aCRqjA5ZSY5beHa0wXurAyQdxx4tb
 LPZVUEUTeh1Vs1SCrVE4ZHtMZPcDiOVsm3Y4YfMcg3bqyNXTGDyVk7Co+p4dzGA0
 XU4z/K93aXPWEG8zomYNdbyiubxz7Kwuo0gVGSuRNarNDLKZS0cdOoiYCvA7vits
 HVTG5O/GOxFmKTYnrxByKclFkVH5PhUylIdvDwecxyIOVM6tmKwjCRG0q8DGi1ic
 QKxjbnDvbMkJBj1N9aFJ4QbgVKFhZP4DJil9T874OjscWnzXc/9z1EKlNbHWdYH+
 mQNtN94Z0YK0jFPdJZf/WePIcyb7XeTAmhKY8cNhkO12bcfzQbcef9I3dsISMCc3
 o0z6RQdc9KWuawXvLNIYh+/O4seWXNG026qZhZcFRpoIQ4HhaJxxsSPz7aZE47ha
 AmLRUiwmv0aDHgvGgnBQuwqa2qi0tre/OyW8ciiN9uY+hAC+P7mnD/wdEBYoSPqP
 0i1zFe/ikxbJXL4vg7+SXTN6pZ8l2ZRQrldXmxEB7mf7WWBM3JoDH4QBRILkobA0
 qc+0NF3oxpQFOJjwefeRr3dwaRvIrqYt2agY5UwvxhNYQmiIbwgBz8VsUMK1CYNZ
 95u57q8=
 =3GP4
 -----END PGP SIGNATURE-----

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
This commit is contained in:
Linus Torvalds 2018-04-10 10:16:04 -07:00
commit 7aa1cf254c
3 changed files with 60 additions and 79 deletions

View File

@ -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 */
/* 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)
{
int err;
struct snd_pcm_runtime *runtime = substream->runtime;
if (!runtime->oss.prepare)
return 0;
err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL);
if (err < 0) {
pcm_dbg(substream->pcm,

View File

@ -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);
else
changed = snd_pcm_hw_param_last(pcm, params, *v, NULL);
if (snd_BUG_ON(changed < 0))
if (changed < 0)
return changed;
if (changed == 0)
continue;

View File

@ -35,105 +35,85 @@
#include "clock.h"
#include "quirks.h"
static struct uac_clock_source_descriptor *
snd_usb_find_clock_source(struct usb_host_interface *ctrl_iface,
int clock_id)
static void *find_uac_clock_desc(struct usb_host_interface *iface, int id,
bool (*validator)(void *, int), u8 type)
{
struct uac_clock_source_descriptor *cs = NULL;
void *cs = NULL;
while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra,
ctrl_iface->extralen,
cs, UAC2_CLOCK_SOURCE))) {
if (cs->bLength >= sizeof(*cs) && cs->bClockID == clock_id)
while ((cs = snd_usb_find_csint_desc(iface->extra, iface->extralen,
cs, type))) {
if (validator(cs, id))
return cs;
}
return NULL;
}
static struct uac3_clock_source_descriptor *
snd_usb_find_clock_source_v3(struct usb_host_interface *ctrl_iface,
int clock_id)
static bool validate_clock_source_v2(void *p, int id)
{
struct uac3_clock_source_descriptor *cs = NULL;
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;
struct uac_clock_source_descriptor *cs = p;
return cs->bLength == sizeof(*cs) && cs->bClockID == id;
}
static struct uac_clock_selector_descriptor *
snd_usb_find_clock_selector(struct usb_host_interface *ctrl_iface,
int clock_id)
static bool validate_clock_source_v3(void *p, int id)
{
struct uac_clock_selector_descriptor *cs = NULL;
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;
struct uac3_clock_source_descriptor *cs = p;
return cs->bLength == sizeof(*cs) && cs->bClockID == id;
}
static struct uac3_clock_selector_descriptor *
snd_usb_find_clock_selector_v3(struct usb_host_interface *ctrl_iface,
int clock_id)
static bool validate_clock_selector_v2(void *p, int id)
{
struct uac3_clock_selector_descriptor *cs = NULL;
while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra,
ctrl_iface->extralen,
cs, UAC3_CLOCK_SELECTOR))) {
if (cs->bClockID == clock_id)
return cs;
}
return NULL;
struct uac_clock_selector_descriptor *cs = p;
return cs->bLength >= sizeof(*cs) && cs->bClockID == id &&
cs->bLength == 7 + cs->bNrInPins;
}
static struct uac_clock_multiplier_descriptor *
snd_usb_find_clock_multiplier(struct usb_host_interface *ctrl_iface,
int clock_id)
static bool validate_clock_selector_v3(void *p, int id)
{
struct uac_clock_multiplier_descriptor *cs = NULL;
while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra,
ctrl_iface->extralen,
cs, UAC2_CLOCK_MULTIPLIER))) {
if (cs->bLength >= sizeof(*cs) && cs->bClockID == clock_id)
return cs;
}
return NULL;
struct uac3_clock_selector_descriptor *cs = p;
return cs->bLength >= sizeof(*cs) && cs->bClockID == id &&
cs->bLength == 11 + cs->bNrInPins;
}
static struct uac3_clock_multiplier_descriptor *
snd_usb_find_clock_multiplier_v3(struct usb_host_interface *ctrl_iface,
int clock_id)
static bool validate_clock_multiplier_v2(void *p, int id)
{
struct uac3_clock_multiplier_descriptor *cs = NULL;
while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra,
ctrl_iface->extralen,
cs, UAC3_CLOCK_MULTIPLIER))) {
if (cs->bClockID == clock_id)
return cs;
}
return NULL;
struct uac_clock_multiplier_descriptor *cs = p;
return cs->bLength == sizeof(*cs) && cs->bClockID == id;
}
static bool validate_clock_multiplier_v3(void *p, int id)
{
struct uac3_clock_multiplier_descriptor *cs = p;
return cs->bLength == sizeof(*cs) && cs->bClockID == id;
}
#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)
{
unsigned char buf;