mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	ALSA: mixer: oss: Fix racy access to slots
The OSS mixer can reassign the mapping slots dynamically via proc file. Although the addition and deletion of those slots are protected by mixer->reg_mutex, the access to slots aren't, hence this may cause UAF when the slots in use are deleted concurrently. This patch applies the mixer->reg_mutex in all appropriate code paths (i.e. the ioctl functions) that may access slots. Reported-by: syzbot+9988f17cf72a1045a189@syzkaller.appspotmail.com Reviewed-by: Jaroslav Kysela <perex@perex.cz> Cc: <stable@vger.kernel.org> Link: https://lore.kernel.org/r/00000000000036adc005ceca9175@google.com Link: https://lore.kernel.org/r/20211020164846.922-1-tiwai@suse.de Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
		
							parent
							
								
									2966492372
								
							
						
					
					
						commit
						411cef6adf
					
				
					 1 changed files with 33 additions and 11 deletions
				
			
		| 
						 | 
				
			
			@ -130,11 +130,13 @@ static int snd_mixer_oss_devmask(struct snd_mixer_oss_file *fmixer)
 | 
			
		|||
 | 
			
		||||
	if (mixer == NULL)
 | 
			
		||||
		return -EIO;
 | 
			
		||||
	mutex_lock(&mixer->reg_mutex);
 | 
			
		||||
	for (chn = 0; chn < 31; chn++) {
 | 
			
		||||
		pslot = &mixer->slots[chn];
 | 
			
		||||
		if (pslot->put_volume || pslot->put_recsrc)
 | 
			
		||||
			result |= 1 << chn;
 | 
			
		||||
	}
 | 
			
		||||
	mutex_unlock(&mixer->reg_mutex);
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -146,11 +148,13 @@ static int snd_mixer_oss_stereodevs(struct snd_mixer_oss_file *fmixer)
 | 
			
		|||
 | 
			
		||||
	if (mixer == NULL)
 | 
			
		||||
		return -EIO;
 | 
			
		||||
	mutex_lock(&mixer->reg_mutex);
 | 
			
		||||
	for (chn = 0; chn < 31; chn++) {
 | 
			
		||||
		pslot = &mixer->slots[chn];
 | 
			
		||||
		if (pslot->put_volume && pslot->stereo)
 | 
			
		||||
			result |= 1 << chn;
 | 
			
		||||
	}
 | 
			
		||||
	mutex_unlock(&mixer->reg_mutex);
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -161,6 +165,7 @@ static int snd_mixer_oss_recmask(struct snd_mixer_oss_file *fmixer)
 | 
			
		|||
 | 
			
		||||
	if (mixer == NULL)
 | 
			
		||||
		return -EIO;
 | 
			
		||||
	mutex_lock(&mixer->reg_mutex);
 | 
			
		||||
	if (mixer->put_recsrc && mixer->get_recsrc) {	/* exclusive */
 | 
			
		||||
		result = mixer->mask_recsrc;
 | 
			
		||||
	} else {
 | 
			
		||||
| 
						 | 
				
			
			@ -172,6 +177,7 @@ static int snd_mixer_oss_recmask(struct snd_mixer_oss_file *fmixer)
 | 
			
		|||
				result |= 1 << chn;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	mutex_unlock(&mixer->reg_mutex);
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -182,12 +188,12 @@ static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer)
 | 
			
		|||
 | 
			
		||||
	if (mixer == NULL)
 | 
			
		||||
		return -EIO;
 | 
			
		||||
	mutex_lock(&mixer->reg_mutex);
 | 
			
		||||
	if (mixer->put_recsrc && mixer->get_recsrc) {	/* exclusive */
 | 
			
		||||
		int err;
 | 
			
		||||
		unsigned int index;
 | 
			
		||||
		err = mixer->get_recsrc(fmixer, &index);
 | 
			
		||||
		if (err < 0)
 | 
			
		||||
			return err;
 | 
			
		||||
		result = mixer->get_recsrc(fmixer, &index);
 | 
			
		||||
		if (result < 0)
 | 
			
		||||
			goto unlock;
 | 
			
		||||
		result = 1 << index;
 | 
			
		||||
	} else {
 | 
			
		||||
		struct snd_mixer_oss_slot *pslot;
 | 
			
		||||
| 
						 | 
				
			
			@ -202,7 +208,10 @@ static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer)
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return mixer->oss_recsrc = result;
 | 
			
		||||
	mixer->oss_recsrc = result;
 | 
			
		||||
 unlock:
 | 
			
		||||
	mutex_unlock(&mixer->reg_mutex);
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsrc)
 | 
			
		||||
| 
						 | 
				
			
			@ -215,6 +224,7 @@ static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsr
 | 
			
		|||
 | 
			
		||||
	if (mixer == NULL)
 | 
			
		||||
		return -EIO;
 | 
			
		||||
	mutex_lock(&mixer->reg_mutex);
 | 
			
		||||
	if (mixer->get_recsrc && mixer->put_recsrc) {	/* exclusive input */
 | 
			
		||||
		if (recsrc & ~mixer->oss_recsrc)
 | 
			
		||||
			recsrc &= ~mixer->oss_recsrc;
 | 
			
		||||
| 
						 | 
				
			
			@ -240,6 +250,7 @@ static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsr
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	mutex_unlock(&mixer->reg_mutex);
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -251,6 +262,7 @@ static int snd_mixer_oss_get_volume(struct snd_mixer_oss_file *fmixer, int slot)
 | 
			
		|||
 | 
			
		||||
	if (mixer == NULL || slot > 30)
 | 
			
		||||
		return -EIO;
 | 
			
		||||
	mutex_lock(&mixer->reg_mutex);
 | 
			
		||||
	pslot = &mixer->slots[slot];
 | 
			
		||||
	left = pslot->volume[0];
 | 
			
		||||
	right = pslot->volume[1];
 | 
			
		||||
| 
						 | 
				
			
			@ -258,15 +270,21 @@ static int snd_mixer_oss_get_volume(struct snd_mixer_oss_file *fmixer, int slot)
 | 
			
		|||
		result = pslot->get_volume(fmixer, pslot, &left, &right);
 | 
			
		||||
	if (!pslot->stereo)
 | 
			
		||||
		right = left;
 | 
			
		||||
	if (snd_BUG_ON(left < 0 || left > 100))
 | 
			
		||||
		return -EIO;
 | 
			
		||||
	if (snd_BUG_ON(right < 0 || right > 100))
 | 
			
		||||
		return -EIO;
 | 
			
		||||
	if (snd_BUG_ON(left < 0 || left > 100)) {
 | 
			
		||||
		result = -EIO;
 | 
			
		||||
		goto unlock;
 | 
			
		||||
	}
 | 
			
		||||
	if (snd_BUG_ON(right < 0 || right > 100)) {
 | 
			
		||||
		result = -EIO;
 | 
			
		||||
		goto unlock;
 | 
			
		||||
	}
 | 
			
		||||
	if (result >= 0) {
 | 
			
		||||
		pslot->volume[0] = left;
 | 
			
		||||
		pslot->volume[1] = right;
 | 
			
		||||
	 	result = (left & 0xff) | ((right & 0xff) << 8);
 | 
			
		||||
	}
 | 
			
		||||
 unlock:
 | 
			
		||||
	mutex_unlock(&mixer->reg_mutex);
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -279,6 +297,7 @@ static int snd_mixer_oss_set_volume(struct snd_mixer_oss_file *fmixer,
 | 
			
		|||
 | 
			
		||||
	if (mixer == NULL || slot > 30)
 | 
			
		||||
		return -EIO;
 | 
			
		||||
	mutex_lock(&mixer->reg_mutex);
 | 
			
		||||
	pslot = &mixer->slots[slot];
 | 
			
		||||
	if (left > 100)
 | 
			
		||||
		left = 100;
 | 
			
		||||
| 
						 | 
				
			
			@ -289,10 +308,13 @@ static int snd_mixer_oss_set_volume(struct snd_mixer_oss_file *fmixer,
 | 
			
		|||
	if (pslot->put_volume)
 | 
			
		||||
		result = pslot->put_volume(fmixer, pslot, left, right);
 | 
			
		||||
	if (result < 0)
 | 
			
		||||
		return result;
 | 
			
		||||
		goto unlock;
 | 
			
		||||
	pslot->volume[0] = left;
 | 
			
		||||
	pslot->volume[1] = right;
 | 
			
		||||
 	return (left & 0xff) | ((right & 0xff) << 8);
 | 
			
		||||
	result = (left & 0xff) | ((right & 0xff) << 8);
 | 
			
		||||
 unlock:
 | 
			
		||||
	mutex_lock(&mixer->reg_mutex);
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int snd_mixer_oss_ioctl1(struct snd_mixer_oss_file *fmixer, unsigned int cmd, unsigned long arg)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue