[PATCH] ALSA: firewire-motu: fix invalid memory access when operating hwdep character device

Takashi Iwai tiwai at suse.de
Wed Oct 20 07:40:46 CEST 2021


On Wed, 20 Oct 2021 06:25:55 +0200,
Takashi Sakamoto wrote:
> 
> ALSA firewire-motu driver recently got support for event notification via
> ALSA HwDep interface for register DSP models. However, when polling ALSA
> HwDep cdev, the driver can cause null pointer dereference for the other
> models due to accessing to unallocated memory or uninitialized memory.
> 
> This commit fixes the bug by check the type of model before accessing to
> the memory.
> 
> Fixes: 634ec0b2906e ("ALSA: firewire-motu: notify event for parameter change in register DSP model")
> Signed-off-by: Takashi Sakamoto <o-takashi at sakamocchi.jp>

Wouldn't it be simpler to add the flag check in
snd_motu_register_dsp_message_parser_count_event() and return 0 if
SND_MOTU_SPEC_REGISTER_DSP isn't set there?


thanks,

Takashi

> ---
>  sound/firewire/motu/motu-hwdep.c | 72 ++++++++++++++++++++------------
>  1 file changed, 45 insertions(+), 27 deletions(-)
> 
> diff --git a/sound/firewire/motu/motu-hwdep.c b/sound/firewire/motu/motu-hwdep.c
> index 9c2e457ce692..ae2d01ddc8d3 100644
> --- a/sound/firewire/motu/motu-hwdep.c
> +++ b/sound/firewire/motu/motu-hwdep.c
> @@ -16,6 +16,47 @@
>  
>  #include "motu.h"
>  
> +static bool has_dsp_event(struct snd_motu *motu)
> +{
> +	if (motu->spec->flags & SND_MOTU_SPEC_REGISTER_DSP)
> +		return (snd_motu_register_dsp_message_parser_count_event(motu) > 0);
> +	else
> +		return false;
> +}
> +
> +// NOTE: Take care of page fault due to accessing to userspace.
> +static long copy_dsp_event_to_user(struct snd_motu *motu, char __user *buf, long count,
> +				   struct snd_firewire_event_motu_register_dsp_change *event)
> +{
> +	if (motu->spec->flags & SND_MOTU_SPEC_REGISTER_DSP) {
> +		size_t consumed = 0;
> +		u32 __user *ptr;
> +		u32 ev;
> +
> +		// Header is filled later.
> +		consumed += sizeof(*event);
> +
> +		while (consumed < count &&
> +		       snd_motu_register_dsp_message_parser_copy_event(motu, &ev)) {
> +			ptr = (u32 __user *)(buf + consumed);
> +			if (put_user(ev, ptr))
> +				return -EFAULT;
> +			consumed += sizeof(ev);
> +		}
> +
> +		event->type = SNDRV_FIREWIRE_EVENT_MOTU_REGISTER_DSP_CHANGE;
> +		event->count = (consumed - sizeof(*event)) / 4;
> +		if (copy_to_user(buf, &event, sizeof(*event)))
> +			return -EFAULT;
> +
> +		count = consumed;
> +	} else {
> +		count = 0;
> +	}
> +
> +	return count;
> +}
> +
>  static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
>  		       loff_t *offset)
>  {
> @@ -25,8 +66,7 @@ static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
>  
>  	spin_lock_irq(&motu->lock);
>  
> -	while (!motu->dev_lock_changed && motu->msg == 0 &&
> -			snd_motu_register_dsp_message_parser_count_event(motu) == 0) {
> +	while (!motu->dev_lock_changed && motu->msg == 0 && !has_dsp_event(motu)) {
>  		prepare_to_wait(&motu->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
>  		spin_unlock_irq(&motu->lock);
>  		schedule();
> @@ -55,31 +95,10 @@ static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
>  		count = min_t(long, count, sizeof(event));
>  		if (copy_to_user(buf, &event, count))
>  			return -EFAULT;
> -	} else if (snd_motu_register_dsp_message_parser_count_event(motu) > 0) {
> -		size_t consumed = 0;
> -		u32 __user *ptr;
> -		u32 ev;
> -
> +	} else if (has_dsp_event(motu)) {
>  		spin_unlock_irq(&motu->lock);
>  
> -		// Header is filled later.
> -		consumed += sizeof(event.motu_register_dsp_change);
> -
> -		while (consumed < count &&
> -		       snd_motu_register_dsp_message_parser_copy_event(motu, &ev)) {
> -			ptr = (u32 __user *)(buf + consumed);
> -			if (put_user(ev, ptr))
> -				return -EFAULT;
> -			consumed += sizeof(ev);
> -		}
> -
> -		event.motu_register_dsp_change.type = SNDRV_FIREWIRE_EVENT_MOTU_REGISTER_DSP_CHANGE;
> -		event.motu_register_dsp_change.count =
> -			(consumed - sizeof(event.motu_register_dsp_change)) / 4;
> -		if (copy_to_user(buf, &event, sizeof(event.motu_register_dsp_change)))
> -			return -EFAULT;
> -
> -		count = consumed;
> +		count = copy_dsp_event_to_user(motu, buf, count, &event.motu_register_dsp_change);
>  	}
>  
>  	return count;
> @@ -94,8 +113,7 @@ static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
>  	poll_wait(file, &motu->hwdep_wait, wait);
>  
>  	spin_lock_irq(&motu->lock);
> -	if (motu->dev_lock_changed || motu->msg ||
> -	    snd_motu_register_dsp_message_parser_count_event(motu) > 0)
> +	if (motu->dev_lock_changed || motu->msg || has_dsp_event(motu))
>  		events = EPOLLIN | EPOLLRDNORM;
>  	else
>  		events = 0;
> -- 
> 2.30.2
> 


More information about the Alsa-devel mailing list