Commit 1626d9a3 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull sound fixes from Takashi Iwai:
 "This contains quite a few device-specific fixes for usual HD- and
  USB-audio in addition to a couple of ALSA core fixes (a UAF fix in
  sequencer and a fix for a misplaced PCM 32bit compat ioctl).

  Nothing really stands out"

* tag 'sound-5.15-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound:
  ALSA: usb-audio: Add quirk for VF0770
  ALSA: hda: avoid write to STATESTS if controller is in reset
  ALSA: hda/realtek: Fix the mic type detection issue for ASUS G551JW
  ALSA: pcm: Workaround for a wrong offset in SYNC_PTR compat ioctl
  ALSA: hda/realtek: Fix for quirk to enable speaker output on the Lenovo 13s Gen2
  ALSA: hda: intel: Allow repeatedly probing on codec configuration errors
  ALSA: hda/realtek: Add quirk for TongFang PHxTxX1
  ALSA: hda/realtek - ALC236 headset MIC recording issue
  ALSA: usb-audio: Enable rate validation for Scarlett devices
  ALSA: hda/realtek: Add quirk for Clevo X170KM-G
  ALSA: hda/realtek: Complete partial device name to avoid ambiguity
  ALSA: hda - Enable headphone mic on Dell Latitude laptops with ALC3254
  ALSA: seq: Fix a potential UAF by wrong private_free call order
  ALSA: hda/realtek: Enable 4-speaker output for Dell Precision 5560 laptop
  ALSA: usb-audio: Fix a missing error check in scarlett gen2 mixer
parents 348949d9 48827e1d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -224,6 +224,7 @@ struct hda_codec {
#endif

	/* misc flags */
	unsigned int configured:1; /* codec was configured */
	unsigned int in_freeing:1; /* being released */
	unsigned int registered:1; /* codec was registered */
	unsigned int display_power_control:1; /* needs display power */
+71 −1
Original line number Diff line number Diff line
@@ -468,6 +468,76 @@ static int snd_pcm_ioctl_sync_ptr_x32(struct snd_pcm_substream *substream,
}
#endif /* CONFIG_X86_X32 */

#ifdef __BIG_ENDIAN
typedef char __pad_before_u32[4];
typedef char __pad_after_u32[0];
#else
typedef char __pad_before_u32[0];
typedef char __pad_after_u32[4];
#endif

/* PCM 2.0.15 API definition had a bug in mmap control; it puts the avail_min
 * at the wrong offset due to a typo in padding type.
 * The bug hits only 32bit.
 * A workaround for incorrect read/write is needed only in 32bit compat mode.
 */
struct __snd_pcm_mmap_control64_buggy {
	__pad_before_u32 __pad1;
	__u32 appl_ptr;
	__pad_before_u32 __pad2;	/* SiC! here is the bug */
	__pad_before_u32 __pad3;
	__u32 avail_min;
	__pad_after_uframe __pad4;
};

static int snd_pcm_ioctl_sync_ptr_buggy(struct snd_pcm_substream *substream,
					struct snd_pcm_sync_ptr __user *_sync_ptr)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct snd_pcm_sync_ptr sync_ptr;
	struct __snd_pcm_mmap_control64_buggy *sync_cp;
	volatile struct snd_pcm_mmap_status *status;
	volatile struct snd_pcm_mmap_control *control;
	int err;

	memset(&sync_ptr, 0, sizeof(sync_ptr));
	sync_cp = (struct __snd_pcm_mmap_control64_buggy *)&sync_ptr.c.control;
	if (get_user(sync_ptr.flags, (unsigned __user *)&(_sync_ptr->flags)))
		return -EFAULT;
	if (copy_from_user(sync_cp, &(_sync_ptr->c.control), sizeof(*sync_cp)))
		return -EFAULT;
	status = runtime->status;
	control = runtime->control;
	if (sync_ptr.flags & SNDRV_PCM_SYNC_PTR_HWSYNC) {
		err = snd_pcm_hwsync(substream);
		if (err < 0)
			return err;
	}
	snd_pcm_stream_lock_irq(substream);
	if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) {
		err = pcm_lib_apply_appl_ptr(substream, sync_cp->appl_ptr);
		if (err < 0) {
			snd_pcm_stream_unlock_irq(substream);
			return err;
		}
	} else {
		sync_cp->appl_ptr = control->appl_ptr;
	}
	if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
		control->avail_min = sync_cp->avail_min;
	else
		sync_cp->avail_min = control->avail_min;
	sync_ptr.s.status.state = status->state;
	sync_ptr.s.status.hw_ptr = status->hw_ptr;
	sync_ptr.s.status.tstamp = status->tstamp;
	sync_ptr.s.status.suspended_state = status->suspended_state;
	sync_ptr.s.status.audio_tstamp = status->audio_tstamp;
	snd_pcm_stream_unlock_irq(substream);
	if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr)))
		return -EFAULT;
	return 0;
}

/*
 */
enum {
@@ -537,7 +607,7 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
		if (in_x32_syscall())
			return snd_pcm_ioctl_sync_ptr_x32(substream, argp);
#endif /* CONFIG_X86_X32 */
		return snd_pcm_common_ioctl(file, substream, cmd, argp);
		return snd_pcm_ioctl_sync_ptr_buggy(substream, argp);
	case SNDRV_PCM_IOCTL_HW_REFINE32:
		return snd_pcm_ioctl_hw_params_compat(substream, 1, argp);
	case SNDRV_PCM_IOCTL_HW_PARAMS32:
+3 −5
Original line number Diff line number Diff line
@@ -156,6 +156,8 @@ static int snd_seq_device_dev_free(struct snd_device *device)
	struct snd_seq_device *dev = device->device_data;

	cancel_autoload_drivers();
	if (dev->private_free)
		dev->private_free(dev);
	put_device(&dev->dev);
	return 0;
}
@@ -183,11 +185,7 @@ static int snd_seq_device_dev_disconnect(struct snd_device *device)

static void snd_seq_dev_release(struct device *dev)
{
	struct snd_seq_device *sdev = to_seq_dev(dev);

	if (sdev->private_free)
		sdev->private_free(sdev);
	kfree(sdev);
	kfree(to_seq_dev(dev));
}

/*
+3 −2
Original line number Diff line number Diff line
@@ -421,7 +421,8 @@ int snd_hdac_bus_reset_link(struct hdac_bus *bus, bool full_reset)
	if (!full_reset)
		goto skip_reset;

	/* clear STATESTS */
	/* clear STATESTS if not in reset */
	if (snd_hdac_chip_readb(bus, GCTL) & AZX_GCTL_RESET)
		snd_hdac_chip_writew(bus, STATESTS, STATESTS_INT_MASK);

	/* reset controller */
+11 −9
Original line number Diff line number Diff line
@@ -298,29 +298,31 @@ int snd_hda_codec_configure(struct hda_codec *codec)
{
	int err;

	if (codec->configured)
		return 0;

	if (is_generic_config(codec))
		codec->probe_id = HDA_CODEC_ID_GENERIC;
	else
		codec->probe_id = 0;

	if (!device_is_registered(&codec->core.dev)) {
		err = snd_hdac_device_register(&codec->core);
		if (err < 0)
			return err;
	}

	if (!codec->preset)
		codec_bind_module(codec);
	if (!codec->preset) {
		err = codec_bind_generic(codec);
		if (err < 0) {
			codec_err(codec, "Unable to bind the codec\n");
			goto error;
			codec_dbg(codec, "Unable to bind the codec\n");
			return err;
		}
	}

	codec->configured = 1;
	return 0;

 error:
	snd_hdac_device_unregister(&codec->core);
	return err;
}
EXPORT_SYMBOL_GPL(snd_hda_codec_configure);
Loading