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.
This commit is contained in:
Takashi Iwai 2006-04-26 18:30:44 +02:00
parent 4632e0f637
commit 6ff727bb7f
5 changed files with 25 additions and 11 deletions

View file

@ -1223,10 +1223,13 @@ int snd_pcm_direct_check_interleave(snd_pcm_direct_t *dmix, snd_pcm_t *pcm)
* id == client channel * id == client channel
* value == slave's 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; snd_config_iterator_t i, next;
unsigned int chn, chn1, count = 0; unsigned int chn, chn1, count = 0;
unsigned int *bindings;
int err; int err;
dmix->channels = UINT_MAX; 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"); SNDERR("client channel out of range");
return -EINVAL; return -EINVAL;
} }
dmix->bindings = malloc(count * sizeof(unsigned int)); bindings = malloc(count * sizeof(unsigned int));
if (dmix->bindings == NULL) if (bindings == NULL)
return -ENOMEM; return -ENOMEM;
for (chn = 0; chn < count; chn++) 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_for_each(i, next, cfg) {
snd_config_t *n = snd_config_iterator_entry(i); snd_config_t *n = snd_config_iterator_entry(i);
const char *id; 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); safe_strtol(id, &cchannel);
if (snd_config_get_integer(n, &schannel) < 0) { if (snd_config_get_integer(n, &schannel) < 0) {
SNDERR("unable to get slave channel (should be integer type) in binding: %s\n", id); SNDERR("unable to get slave channel (should be integer type) in binding: %s\n", id);
free(bindings);
return -EINVAL; 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) if (dmix->type == SND_PCM_TYPE_DSNOOP)
goto __skip_same_dst; 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++) { for (chn1 = 0; chn1 < count; chn1++) {
if (chn == chn1) if (chn == chn1)
continue; continue;
if (dmix->bindings[chn] == dmix->bindings[chn1]) { if (bindings[chn] == dmix->bindings[chn1]) {
SNDERR("unable to route channels %d,%d to same destination %d", chn, chn1, dmix->bindings[chn]); SNDERR("unable to route channels %d,%d to same destination %d", chn, chn1, bindings[chn]);
free(bindings);
return -EINVAL; return -EINVAL;
} }
} }
} }
__skip_same_dst: __skip_same_dst:
dmix->bindings = bindings;
dmix->channels = count; dmix->channels = count;
return 0; return 0;
} }

View 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_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_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_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_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_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); int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);

View file

@ -808,7 +808,7 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
goto _err_nosem; 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) if (ret < 0)
goto _err_nosem; goto _err_nosem;

View file

@ -614,7 +614,7 @@ int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name,
goto _err_nosem; 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) if (ret < 0)
goto _err_nosem; goto _err_nosem;

View file

@ -502,7 +502,7 @@ int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
goto _err_nosem; 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) if (ret < 0)
goto _err_nosem; goto _err_nosem;