OSDN Git Service

ALSA: seq: Check the conflicting port at port creation
authorTakashi Iwai <tiwai@suse.de>
Tue, 23 May 2023 07:53:42 +0000 (09:53 +0200)
committerTakashi Iwai <tiwai@suse.de>
Tue, 23 May 2023 10:11:17 +0000 (12:11 +0200)
We didn't check if a port with the given port number has been already
present at creating a new port.  Check it and return -EBUSY properly
if the port number conflicts.

Reviewed-by: Jaroslav Kysela <perex@perex.cz>
Link: https://lore.kernel.org/r/20230523075358.9672-22-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/core/seq/seq_clientmgr.c
sound/core/seq/seq_ports.c
sound/core/seq/seq_ports.h

index 019af13..0674311 100644 (file)
@@ -1194,15 +1194,19 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, void *arg)
        struct snd_seq_port_info *info = arg;
        struct snd_seq_client_port *port;
        struct snd_seq_port_callback *callback;
-       int port_idx;
+       int port_idx, err;
 
        /* it is not allowed to create the port for an another client */
        if (info->addr.client != client->number)
                return -EPERM;
 
-       port = snd_seq_create_port(client, (info->flags & SNDRV_SEQ_PORT_FLG_GIVEN_PORT) ? info->addr.port : -1);
-       if (port == NULL)
-               return -ENOMEM;
+       if (info->flags & SNDRV_SEQ_PORT_FLG_GIVEN_PORT)
+               port_idx = info->addr.port;
+       else
+               port_idx = -1;
+       err = snd_seq_create_port(client, port_idx, &port);
+       if (err < 0)
+               return err;
 
        if (client->type == USER_CLIENT && info->kernel) {
                port_idx = port->addr.port;
index 25fcf5a..500b1a5 100644 (file)
@@ -107,33 +107,34 @@ static void port_subs_info_init(struct snd_seq_port_subs_info *grp)
 }
 
 
-/* create a port, port number is returned (-1 on failure);
+/* create a port, port number or a negative error code is returned
  * the caller needs to unref the port via snd_seq_port_unlock() appropriately
  */
-struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
-                                               int port)
+int snd_seq_create_port(struct snd_seq_client *client, int port,
+                       struct snd_seq_client_port **port_ret)
 {
        struct snd_seq_client_port *new_port, *p;
-       int num = -1;
+       int num;
        
+       *port_ret = NULL;
+
        /* sanity check */
        if (snd_BUG_ON(!client))
-               return NULL;
+               return -EINVAL;
 
        if (client->num_ports >= SNDRV_SEQ_MAX_PORTS) {
                pr_warn("ALSA: seq: too many ports for client %d\n", client->number);
-               return NULL;
+               return -EINVAL;
        }
 
        /* create a new port */
        new_port = kzalloc(sizeof(*new_port), GFP_KERNEL);
        if (!new_port)
-               return NULL;    /* failure, out of memory */
+               return -ENOMEM; /* failure, out of memory */
        /* init port data */
        new_port->addr.client = client->number;
        new_port->addr.port = -1;
        new_port->owner = THIS_MODULE;
-       sprintf(new_port->name, "port-%d", num);
        snd_use_lock_init(&new_port->use_lock);
        port_subs_info_init(&new_port->c_src);
        port_subs_info_init(&new_port->c_dest);
@@ -143,6 +144,10 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
        mutex_lock(&client->ports_mutex);
        write_lock_irq(&client->ports_lock);
        list_for_each_entry(p, &client->ports_list_head, list) {
+               if (p->addr.port == port) {
+                       num = -EBUSY;
+                       goto unlock;
+               }
                if (p->addr.port > num)
                        break;
                if (port < 0) /* auto-probe mode */
@@ -153,10 +158,12 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
        client->num_ports++;
        new_port->addr.port = num;      /* store the port number in the port */
        sprintf(new_port->name, "port-%d", num);
+       *port_ret = new_port;
+ unlock:
        write_unlock_irq(&client->ports_lock);
        mutex_unlock(&client->ports_mutex);
 
-       return new_port;
+       return num;
 }
 
 /* */
index b1f2c49..44f0e9e 100644 (file)
@@ -86,8 +86,9 @@ struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *cl
 /* unlock the port */
 #define snd_seq_port_unlock(port) snd_use_lock_free(&(port)->use_lock)
 
-/* create a port, port number is returned (-1 on failure) */
-struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, int port_index);
+/* create a port, port number or a negative error code is returned */
+int snd_seq_create_port(struct snd_seq_client *client, int port_index,
+                       struct snd_seq_client_port **port_ret);
 
 /* delete a port */
 int snd_seq_delete_port(struct snd_seq_client *client, int port);