Revert "ALSA: pcm: Fix races among concurrent hw_params and hw_free calls"

This reverts commit 33061d0fba.

It will come back after the next ABI break as it is needed to resolve
CVE-2022-1048.  But for now, while testing, it can be reverted in order
to preserve the ABI.

Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Change-Id: Iebd89734d6d1b0bdb3aaa9e8b52fc07345377a64
This commit is contained in:
Greg Kroah-Hartman
2022-03-29 12:55:26 +02:00
parent 9f368dfefd
commit 162cbdd807
3 changed files with 22 additions and 42 deletions

View File

@@ -398,7 +398,6 @@ struct snd_pcm_runtime {
wait_queue_head_t tsleep; /* transfer sleep */ wait_queue_head_t tsleep; /* transfer sleep */
struct fasync_struct *fasync; struct fasync_struct *fasync;
bool stop_operating; /* sync_stop will be called */ bool stop_operating; /* sync_stop will be called */
struct mutex buffer_mutex; /* protect for buffer changes */
/* -- private section -- */ /* -- private section -- */
void *private_data; void *private_data;

View File

@@ -969,7 +969,6 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
init_waitqueue_head(&runtime->tsleep); init_waitqueue_head(&runtime->tsleep);
runtime->status->state = SNDRV_PCM_STATE_OPEN; runtime->status->state = SNDRV_PCM_STATE_OPEN;
mutex_init(&runtime->buffer_mutex);
substream->runtime = runtime; substream->runtime = runtime;
substream->private_data = pcm->private_data; substream->private_data = pcm->private_data;
@@ -1003,7 +1002,6 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
} else { } else {
substream->runtime = NULL; substream->runtime = NULL;
} }
mutex_destroy(&runtime->buffer_mutex);
kfree(runtime); kfree(runtime);
put_pid(substream->pid); put_pid(substream->pid);
substream->pid = NULL; substream->pid = NULL;

View File

@@ -672,40 +672,33 @@ static int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm,
return 0; return 0;
} }
#if IS_ENABLED(CONFIG_SND_PCM_OSS)
#define is_oss_stream(substream) ((substream)->oss.oss)
#else
#define is_oss_stream(substream) false
#endif
static int snd_pcm_hw_params(struct snd_pcm_substream *substream, static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params) struct snd_pcm_hw_params *params)
{ {
struct snd_pcm_runtime *runtime; struct snd_pcm_runtime *runtime;
int err = 0, usecs; int err, usecs;
unsigned int bits; unsigned int bits;
snd_pcm_uframes_t frames; snd_pcm_uframes_t frames;
if (PCM_RUNTIME_CHECK(substream)) if (PCM_RUNTIME_CHECK(substream))
return -ENXIO; return -ENXIO;
runtime = substream->runtime; runtime = substream->runtime;
mutex_lock(&runtime->buffer_mutex);
snd_pcm_stream_lock_irq(substream); snd_pcm_stream_lock_irq(substream);
switch (runtime->status->state) { switch (runtime->status->state) {
case SNDRV_PCM_STATE_OPEN: case SNDRV_PCM_STATE_OPEN:
case SNDRV_PCM_STATE_SETUP: case SNDRV_PCM_STATE_SETUP:
case SNDRV_PCM_STATE_PREPARED: case SNDRV_PCM_STATE_PREPARED:
if (!is_oss_stream(substream) &&
atomic_read(&substream->mmap_count))
err = -EBADFD;
break; break;
default: default:
err = -EBADFD; snd_pcm_stream_unlock_irq(substream);
break; return -EBADFD;
} }
snd_pcm_stream_unlock_irq(substream); snd_pcm_stream_unlock_irq(substream);
if (err) #if IS_ENABLED(CONFIG_SND_PCM_OSS)
goto unlock; if (!substream->oss.oss)
#endif
if (atomic_read(&substream->mmap_count))
return -EBADFD;
snd_pcm_sync_stop(substream, true); snd_pcm_sync_stop(substream, true);
@@ -793,21 +786,16 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
if (usecs >= 0) if (usecs >= 0)
cpu_latency_qos_add_request(&substream->latency_pm_qos_req, cpu_latency_qos_add_request(&substream->latency_pm_qos_req,
usecs); usecs);
err = 0; return 0;
_error: _error:
if (err) { /* hardware might be unusable from this time,
/* hardware might be unusable from this time, so we force application to retry to set
* so we force application to retry to set the correct hardware parameter settings */
* the correct hardware parameter settings snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
*/ if (substream->ops->hw_free != NULL)
snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); substream->ops->hw_free(substream);
if (substream->ops->hw_free != NULL) if (substream->managed_buffer_alloc)
substream->ops->hw_free(substream); snd_pcm_lib_free_pages(substream);
if (substream->managed_buffer_alloc)
snd_pcm_lib_free_pages(substream);
}
unlock:
mutex_unlock(&runtime->buffer_mutex);
return err; return err;
} }
@@ -847,31 +835,26 @@ static int do_hw_free(struct snd_pcm_substream *substream)
static int snd_pcm_hw_free(struct snd_pcm_substream *substream) static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
{ {
struct snd_pcm_runtime *runtime; struct snd_pcm_runtime *runtime;
int result = 0; int result;
if (PCM_RUNTIME_CHECK(substream)) if (PCM_RUNTIME_CHECK(substream))
return -ENXIO; return -ENXIO;
runtime = substream->runtime; runtime = substream->runtime;
mutex_lock(&runtime->buffer_mutex);
snd_pcm_stream_lock_irq(substream); snd_pcm_stream_lock_irq(substream);
switch (runtime->status->state) { switch (runtime->status->state) {
case SNDRV_PCM_STATE_SETUP: case SNDRV_PCM_STATE_SETUP:
case SNDRV_PCM_STATE_PREPARED: case SNDRV_PCM_STATE_PREPARED:
if (atomic_read(&substream->mmap_count))
result = -EBADFD;
break; break;
default: default:
result = -EBADFD; snd_pcm_stream_unlock_irq(substream);
break; return -EBADFD;
} }
snd_pcm_stream_unlock_irq(substream); snd_pcm_stream_unlock_irq(substream);
if (result) if (atomic_read(&substream->mmap_count))
goto unlock; return -EBADFD;
result = do_hw_free(substream); result = do_hw_free(substream);
snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
cpu_latency_qos_remove_request(&substream->latency_pm_qos_req); cpu_latency_qos_remove_request(&substream->latency_pm_qos_req);
unlock:
mutex_unlock(&runtime->buffer_mutex);
return result; return result;
} }