]> git.alsa-project.org Git - alsa-lib.git/commitdiff
Add check of binding ranges in direct plugins
authorTakashi Iwai <tiwai@suse.de>
Wed, 26 Apr 2006 16:30:44 +0000 (18:30 +0200)
committerTakashi Iwai <tiwai@suse.de>
Wed, 26 Apr 2006 16:30:44 +0000 (18:30 +0200)
Add checks of slave channel numbers in bindings of dmix/dsnoop/dshare
plugins to avoid segfault.
Also, fix a possible memory leaks in the error path.

src/pcm/pcm_direct.c
src/pcm/pcm_direct.h
src/pcm/pcm_dmix.c
src/pcm/pcm_dshare.c
src/pcm/pcm_dsnoop.c

index a442c85acac26d791fbc03c1897ee165234a9a6a..46664a13d0a3368527b103ff13a08f3bcfe1ddbb 100644 (file)
@@ -1223,10 +1223,13 @@ int snd_pcm_direct_check_interleave(snd_pcm_direct_t *dmix, snd_pcm_t *pcm)
  * id == client channel
  * value == slave's channel
  */
-int snd_pcm_direct_parse_bindings(snd_pcm_direct_t *dmix, snd_config_t *cfg)
+int snd_pcm_direct_parse_bindings(snd_pcm_direct_t *dmix,
+                                 struct slave_params *params,
+                                 snd_config_t *cfg)
 {
        snd_config_iterator_t i, next;
        unsigned int chn, chn1, count = 0;
+       unsigned int *bindings;
        int err;
 
        dmix->channels = UINT_MAX;
@@ -1256,11 +1259,11 @@ int snd_pcm_direct_parse_bindings(snd_pcm_direct_t *dmix, snd_config_t *cfg)
                SNDERR("client channel out of range");
                return -EINVAL;
        }
-       dmix->bindings = malloc(count * sizeof(unsigned int));
-       if (dmix->bindings == NULL)
+       bindings = malloc(count * sizeof(unsigned int));
+       if (bindings == NULL)
                return -ENOMEM;
        for (chn = 0; chn < count; chn++)
-               dmix->bindings[chn] = UINT_MAX;         /* don't route */
+               bindings[chn] = UINT_MAX;               /* don't route */
        snd_config_for_each(i, next, cfg) {
                snd_config_t *n = snd_config_iterator_entry(i);
                const char *id;
@@ -1270,9 +1273,16 @@ int snd_pcm_direct_parse_bindings(snd_pcm_direct_t *dmix, snd_config_t *cfg)
                safe_strtol(id, &cchannel);
                if (snd_config_get_integer(n, &schannel) < 0) {
                        SNDERR("unable to get slave channel (should be integer type) in binding: %s\n", id);
+                       free(bindings);
                        return -EINVAL;
                }
-               dmix->bindings[cchannel] = schannel;
+               if (schannel < 0 || schannel >= params->channels) {
+                       SNDERR("invalid slave channel number %d in binding to %d",
+                              schannel, cchannel);
+                       free(bindings);
+                       return -EINVAL;
+               }
+               bindings[cchannel] = schannel;
        }
        if (dmix->type == SND_PCM_TYPE_DSNOOP)
                goto __skip_same_dst;
@@ -1280,13 +1290,15 @@ int snd_pcm_direct_parse_bindings(snd_pcm_direct_t *dmix, snd_config_t *cfg)
                for (chn1 = 0; chn1 < count; chn1++) {
                        if (chn == chn1)
                                continue;
-                       if (dmix->bindings[chn] == dmix->bindings[chn1]) {
-                               SNDERR("unable to route channels %d,%d to same destination %d", chn, chn1, dmix->bindings[chn]);
+                       if (bindings[chn] == dmix->bindings[chn1]) {
+                               SNDERR("unable to route channels %d,%d to same destination %d", chn, chn1, bindings[chn]);
+                               free(bindings);
                                return -EINVAL;
                        }
                }
        }
       __skip_same_dst:
+       dmix->bindings = bindings;
        dmix->channels = count;
        return 0;
 }
index d520e53e58c1a6f2aa267c313cd69846b90b6dbf..b094fcf3d39352bfc5e35ed4a49190378fa24b5a 100644 (file)
@@ -170,7 +170,9 @@ int snd_pcm_direct_client_discard(snd_pcm_direct_t *dmix);
 int snd_pcm_direct_initialize_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, struct slave_params *params);
 int snd_pcm_direct_initialize_poll_fd(snd_pcm_direct_t *dmix);
 int snd_pcm_direct_check_interleave(snd_pcm_direct_t *dmix, snd_pcm_t *pcm);
-int snd_pcm_direct_parse_bindings(snd_pcm_direct_t *dmix, snd_config_t *cfg);
+int snd_pcm_direct_parse_bindings(snd_pcm_direct_t *dmix,
+                                 struct slave_params *params,
+                                 snd_config_t *cfg);
 int snd_pcm_direct_nonblock(snd_pcm_t *pcm, int nonblock);
 int snd_pcm_direct_async(snd_pcm_t *pcm, int sig, pid_t pid);
 int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
index d8cc8adf88d73598fee74bd84cf195b81c4d4e47..366d69f6e58050a3e81a482492d0cbe28cab6338 100644 (file)
@@ -808,7 +808,7 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
                goto _err_nosem;
        }
        
-       ret = snd_pcm_direct_parse_bindings(dmix, opts->bindings);
+       ret = snd_pcm_direct_parse_bindings(dmix, params, opts->bindings);
        if (ret < 0)
                goto _err_nosem;
        
index 665dffddde656bed405c355d43f183cf72d15333..88535e567884a6b4435578913f5229c80a3551d7 100644 (file)
@@ -614,7 +614,7 @@ int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name,
                goto _err_nosem;
        }
        
-       ret = snd_pcm_direct_parse_bindings(dshare, opts->bindings);
+       ret = snd_pcm_direct_parse_bindings(dshare, params, opts->bindings);
        if (ret < 0)
                goto _err_nosem;
                
index 4d44e76f23e255d3def6709eb0dc7ff68eb95806..537e09cb786fd2d51269c53f5a5949558eaee7bb 100644 (file)
@@ -502,7 +502,7 @@ int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
                goto _err_nosem;
        }
        
-       ret = snd_pcm_direct_parse_bindings(dsnoop, opts->bindings);
+       ret = snd_pcm_direct_parse_bindings(dsnoop, params, opts->bindings);
        if (ret < 0)
                goto _err_nosem;