From 6ff727bb7f44b0d7b5bb21013efea710075de93c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 26 Apr 2006 18:30:44 +0200 Subject: [PATCH] Add check of binding ranges in direct plugins 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 | 26 +++++++++++++++++++------- src/pcm/pcm_direct.h | 4 +++- src/pcm/pcm_dmix.c | 2 +- src/pcm/pcm_dshare.c | 2 +- src/pcm/pcm_dsnoop.c | 2 +- 5 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c index a442c85a..46664a13 100644 --- a/src/pcm/pcm_direct.c +++ b/src/pcm/pcm_direct.c @@ -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; } diff --git a/src/pcm/pcm_direct.h b/src/pcm/pcm_direct.h index d520e53e..b094fcf3 100644 --- a/src/pcm/pcm_direct.h +++ b/src/pcm/pcm_direct.h @@ -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); diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c index d8cc8adf..366d69f6 100644 --- a/src/pcm/pcm_dmix.c +++ b/src/pcm/pcm_dmix.c @@ -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; diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c index 665dffdd..88535e56 100644 --- a/src/pcm/pcm_dshare.c +++ b/src/pcm/pcm_dshare.c @@ -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; diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c index 4d44e76f..537e09cb 100644 --- a/src/pcm/pcm_dsnoop.c +++ b/src/pcm/pcm_dsnoop.c @@ -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; -- 2.47.1