Commit 6b580f52 authored by Takashi Iwai's avatar Takashi Iwai

ALSA: seq: Protect racy pool manipulation from OSS sequencer

OSS sequencer emulation still allows to queue and issue the events
that manipulate the client pool concurrently in a racy way.  This
patch serializes the access like the normal sequencer write / ioctl
via taking the client ioctl_mutex.  Since the access to the sequencer
client is done indirectly via a client id number, a new helper to
take/release the mutex is introduced.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 6740ea67
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <sound/rawmidi.h> #include <sound/rawmidi.h>
#include <sound/seq_kernel.h> #include <sound/seq_kernel.h>
#include <sound/info.h> #include <sound/info.h>
#include "../seq_clientmgr.h"
/* max. applications */ /* max. applications */
#define SNDRV_SEQ_OSS_MAX_CLIENTS 16 #define SNDRV_SEQ_OSS_MAX_CLIENTS 16
...@@ -150,11 +151,16 @@ snd_seq_oss_dispatch(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, int a ...@@ -150,11 +151,16 @@ snd_seq_oss_dispatch(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, int a
return snd_seq_kernel_client_dispatch(dp->cseq, ev, atomic, hop); return snd_seq_kernel_client_dispatch(dp->cseq, ev, atomic, hop);
} }
/* ioctl */ /* ioctl for writeq */
static inline int static inline int
snd_seq_oss_control(struct seq_oss_devinfo *dp, unsigned int type, void *arg) snd_seq_oss_control(struct seq_oss_devinfo *dp, unsigned int type, void *arg)
{ {
return snd_seq_kernel_client_ctl(dp->cseq, type, arg); int err;
snd_seq_client_ioctl_lock(dp->cseq);
err = snd_seq_kernel_client_ctl(dp->cseq, type, arg);
snd_seq_client_ioctl_unlock(dp->cseq);
return err;
} }
/* fill the addresses in header */ /* fill the addresses in header */
......
...@@ -179,6 +179,36 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid) ...@@ -179,6 +179,36 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
return client; return client;
} }
/* Take refcount and perform ioctl_mutex lock on the given client;
* used only for OSS sequencer
* Unlock via snd_seq_client_ioctl_unlock() below
*/
bool snd_seq_client_ioctl_lock(int clientid)
{
struct snd_seq_client *client;
client = snd_seq_client_use_ptr(clientid);
if (!client)
return false;
mutex_lock(&client->ioctl_mutex);
return true;
}
EXPORT_SYMBOL_GPL(snd_seq_client_ioctl_lock);
/* Unlock and unref the given client; for OSS sequencer use only */
void snd_seq_client_ioctl_unlock(int clientid)
{
struct snd_seq_client *client;
client = snd_seq_client_use_ptr(clientid);
if (WARN_ON(!client))
return;
mutex_unlock(&client->ioctl_mutex);
snd_use_lock_free(&client->use_lock);
snd_seq_client_unlock(client);
}
EXPORT_SYMBOL_GPL(snd_seq_client_ioctl_unlock);
static void usage_alloc(struct snd_seq_usage *res, int num) static void usage_alloc(struct snd_seq_usage *res, int num)
{ {
res->cur += num; res->cur += num;
...@@ -2247,11 +2277,15 @@ int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event *ev, ...@@ -2247,11 +2277,15 @@ int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event *ev,
if (cptr == NULL) if (cptr == NULL)
return -EINVAL; return -EINVAL;
if (! cptr->accept_output) if (!cptr->accept_output) {
result = -EPERM; result = -EPERM;
else /* send it */ } else { /* send it */
mutex_lock(&cptr->ioctl_mutex);
result = snd_seq_client_enqueue_event(cptr, ev, file, blocking, result = snd_seq_client_enqueue_event(cptr, ev, file, blocking,
false, 0, NULL); false, 0,
&cptr->ioctl_mutex);
mutex_unlock(&cptr->ioctl_mutex);
}
snd_seq_client_unlock(cptr); snd_seq_client_unlock(cptr);
return result; return result;
......
...@@ -97,6 +97,10 @@ int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table ...@@ -97,6 +97,10 @@ int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table
int snd_seq_client_notify_subscription(int client, int port, int snd_seq_client_notify_subscription(int client, int port,
struct snd_seq_port_subscribe *info, int evtype); struct snd_seq_port_subscribe *info, int evtype);
/* only for OSS sequencer */
bool snd_seq_client_ioctl_lock(int clientid);
void snd_seq_client_ioctl_unlock(int clientid);
extern int seq_client_load[15]; extern int seq_client_load[15];
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment