OSDN Git Service

ALSA: seq: Protect racy pool manipulation from OSS sequencer
authorTakashi Iwai <tiwai@suse.de>
Fri, 12 Apr 2019 10:44:39 +0000 (12:44 +0200)
committerTakashi Iwai <tiwai@suse.de>
Fri, 12 Apr 2019 11:07:25 +0000 (13:07 +0200)
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: Takashi Iwai <tiwai@suse.de>
sound/core/seq/oss/seq_oss_device.h
sound/core/seq/seq_clientmgr.c
sound/core/seq/seq_clientmgr.h

index 2d0e9ea..77eb1fe 100644 (file)
@@ -30,6 +30,7 @@
 #include <sound/rawmidi.h>
 #include <sound/seq_kernel.h>
 #include <sound/info.h>
+#include "../seq_clientmgr.h"
 
 /* max. applications */
 #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
        return snd_seq_kernel_client_dispatch(dp->cseq, ev, atomic, hop);
 }
 
-/* ioctl */
+/* ioctl for writeq */
 static inline int
 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 */
index 0af5b14..a5c9d59 100644 (file)
@@ -179,6 +179,36 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
        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)
 {
        res->cur += num;
@@ -2247,11 +2277,15 @@ int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event *ev,
        if (cptr == NULL)
                return -EINVAL;
        
-       if (! cptr->accept_output)
+       if (!cptr->accept_output) {
                result = -EPERM;
-       else /* send it */
+       } else { /* send it */
+               mutex_lock(&cptr->ioctl_mutex);
                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);
        return result;
index 66ad3d5..28a51dc 100644 (file)
@@ -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,
                                       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];
 
 #endif