Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7aa1cf25 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -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,
+1 −1
Original line number Diff line number Diff line
@@ -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;
+54 −74
Original line number Diff line number Diff line
@@ -35,104 +35,84 @@
#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;
	struct uac_clock_source_descriptor *cs = p;
	return cs->bLength == sizeof(*cs) && cs->bClockID == id;
}

	return NULL;
}

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;
		}
	struct uac3_clock_source_descriptor *cs = p;
	return cs->bLength == sizeof(*cs) && cs->bClockID == id;
}

	return NULL;
}

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;
	struct uac_clock_selector_descriptor *cs = p;
	return cs->bLength >= sizeof(*cs) && cs->bClockID == id &&
		cs->bLength == 7 + cs->bNrInPins;
}

	return NULL;
}

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;
	struct uac3_clock_selector_descriptor *cs = p;
	return cs->bLength >= sizeof(*cs) && cs->bClockID == id &&
		cs->bLength == 11 + cs->bNrInPins;
}

	return NULL;
}

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;
	struct uac_clock_multiplier_descriptor *cs = p;
	return cs->bLength == sizeof(*cs) && cs->bClockID == id;
}

	return NULL;
}
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)
{