[alsa-devel] [PATCH lib 0/5] alsa-lib namehint fixes
Hi,
here is a series of fixes for alsa-lib namehint stuff. Currently snd_device_name_hint() doesn't return proper lists except for PCM. Also it may do bogus free() or segfault for wrong operations. This patchset addresses such issues and also adds the missing hint descriptions to ctl, seq, hwdep, etc.
Takashi
===
Takashi Iwai (5): namehint: Fix invalid list access in snd_device_name_hint() namehint: Fix the listing without device number namehint: Fix bad free with invalid iface name Allow hint for ctl, hwdep, timer and seq conf: Add hint descriptions to ctl, hwdep, seq and timer devices
include/local.h | 2 ++ src/conf/alsa.conf | 15 ++++++++++++++- src/confmisc.c | 13 +++++++++++++ src/control/control_hw.c | 4 +--- src/control/control_shm.c | 7 ++----- src/control/namehint.c | 26 ++++++++++++-------------- src/hwdep/hwdep_hw.c | 4 +--- src/pcm/pcm.c | 12 ------------ src/pcm/pcm_local.h | 5 ++--- src/rawmidi/rawmidi.c | 18 ------------------ src/rawmidi/rawmidi_local.h | 2 +- src/seq/seq_hw.c | 4 +--- src/timer/timer_hw.c | 4 +--- src/timer/timer_query_hw.c | 4 +--- 14 files changed, 51 insertions(+), 69 deletions(-)
snd_device_name_hint() tries to free the allocated list at the error path via snd_device_name_free_hint(). But snd_device_name_free_hint() expects a list terminated by NULL while snd_device_name_hint() doesn't add it. Adding it may again result in an error and thus isn't guaranteed to work. Hence we can't add NULL at the error path.
Instead, now the code always allocates one entry more, and zero-clears the newly allocated beforehand to guarantee the NULL termination.
Signed-off-by: Takashi Iwai tiwai@suse.de --- src/control/namehint.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-)
diff --git a/src/control/namehint.c b/src/control/namehint.c index 28975a400b75..66de634d3550 100644 --- a/src/control/namehint.c +++ b/src/control/namehint.c @@ -52,10 +52,11 @@ static int hint_list_add(struct hint_list *list, { char *x;
- if (list->count == list->allocated) { + if (list->count + 1 >= list->allocated) { char **n = realloc(list->list, (list->allocated + 10) * sizeof(char *)); if (n == NULL) return -ENOMEM; + memset(n + list->allocated, 0, 10 * sizeof(*n)); list->allocated += 10; list->list = n; } @@ -620,18 +621,16 @@ int snd_device_name_hint(int card, const char *iface, void ***hints) } err = 0; __error: - if (err < 0) { + /* add an empty entry if nothing has been added yet; the caller + * expects non-NULL return + */ + if (!err && !list.list) + err = hint_list_add(&list, NULL, NULL); + if (err < 0) snd_device_name_free_hint((void **)list.list); - if (list.cardname) - free(list.cardname); - } else { - err = hint_list_add(&list, NULL, NULL); - if (err < 0) - goto __error; + else *hints = (void **)list.list; - if (list.cardname) - free(list.cardname); - } + free(list.cardname); if (local_config_rw) snd_config_delete(local_config_rw); if (local_config)
The current code of snd_device_name_hint() has a bug when listing up devices without the device index (e.g. ctl). Because it assigns the default device index 0 unconditionally and it has a check at the later point to filter entries with dev >= 0, it ended up with empty outputs.
The fix is simply to remove the bogus assignment of dev = 0.
Signed-off-by: Takashi Iwai tiwai@suse.de --- src/control/namehint.c | 1 - 1 file changed, 1 deletion(-)
diff --git a/src/control/namehint.c b/src/control/namehint.c index 66de634d3550..6c04143a185c 100644 --- a/src/control/namehint.c +++ b/src/control/namehint.c @@ -272,7 +272,6 @@ static int try_config(snd_config_t *config, if (snd_config_search(cfg1, "type", &cfg) >= 0 && snd_config_get_string(cfg, &str) >= 0 && strcmp(str, "hw") == 0) { - dev = 0; list->device_input = -1; list->device_output = -1; if (snd_config_search(cfg1, "device", &cfg) >= 0) {
Due to the uninitialized field before the error path, passing an invalid iface argument may result in a bad free() call. Initialize the fields properly beforehand.
Signed-off-by: Takashi Iwai tiwai@suse.de --- src/control/namehint.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/control/namehint.c b/src/control/namehint.c index 6c04143a185c..b3e646eb10af 100644 --- a/src/control/namehint.c +++ b/src/control/namehint.c @@ -562,6 +562,8 @@ int snd_device_name_hint(int card, const char *iface, void ***hints) list.list = NULL; list.count = list.allocated = 0; list.siface = iface; + list.show_all = 0; + list.cardname = NULL; if (strcmp(iface, "card") == 0) list.iface = SND_CTL_ELEM_IFACE_CARD; else if (strcmp(iface, "pcm") == 0) @@ -581,8 +583,6 @@ int snd_device_name_hint(int card, const char *iface, void ***hints) goto __error; }
- list.show_all = 0; - list.cardname = NULL; if (snd_config_search(local_config, "defaults.namehint.showall", &conf) >= 0) list.show_all = snd_config_get_bool(conf) > 0; if (card >= 0) {
Like pcm and rawmidi, each object parser needs to accept the hint component. Now a new local function _snd_conf_generic_id() was introduced to replace each call of "comment" and "type" field checks.
Also, the two existing identical functions for pcm and rawmidi are removed and the new function is used commonly.
Signed-off-by: Takashi Iwai tiwai@suse.de --- include/local.h | 2 ++ src/confmisc.c | 13 +++++++++++++ src/control/control_hw.c | 4 +--- src/control/control_shm.c | 7 ++----- src/hwdep/hwdep_hw.c | 4 +--- src/pcm/pcm.c | 12 ------------ src/pcm/pcm_local.h | 5 ++--- src/rawmidi/rawmidi.c | 18 ------------------ src/rawmidi/rawmidi_local.h | 2 +- src/seq/seq_hw.c | 4 +--- src/timer/timer_hw.c | 4 +--- src/timer/timer_query_hw.c | 4 +--- 12 files changed, 25 insertions(+), 54 deletions(-)
diff --git a/include/local.h b/include/local.h index 2fe9a273f0b0..660081638a1c 100644 --- a/include/local.h +++ b/include/local.h @@ -348,4 +348,6 @@ int snd_config_search_alias_hooks(snd_config_t *config, const char *base, const char *key, snd_config_t **result);
+int _snd_conf_generic_id(const char *id); + #endif diff --git a/src/confmisc.c b/src/confmisc.c index af686bea323c..1fb4f282217e 100644 --- a/src/confmisc.c +++ b/src/confmisc.c @@ -1302,3 +1302,16 @@ int snd_func_refer(snd_config_t **dst, snd_config_t *root, snd_config_t *src, #ifndef DOC_HIDDEN SND_DLSYM_BUILD_VERSION(snd_func_refer, SND_CONFIG_DLSYM_VERSION_EVALUATE); #endif + +#ifndef DOC_HIDDEN +int _snd_conf_generic_id(const char *id) +{ + static const char ids[3][8] = { "comment", "type", "hint" }; + unsigned int k; + for (k = 0; k < sizeof(ids) / sizeof(ids[0]); ++k) { + if (strcmp(id, ids[k]) == 0) + return 1; + } + return 0; +} +#endif diff --git a/src/control/control_hw.c b/src/control/control_hw.c index dfc9dcd51e20..7d23151c7d75 100644 --- a/src/control/control_hw.c +++ b/src/control/control_hw.c @@ -446,9 +446,7 @@ int _snd_ctl_hw_open(snd_ctl_t **handlep, char *name, snd_config_t *root ATTRIBU const char *id; if (snd_config_get_id(n, &id) < 0) continue; - if (strcmp(id, "comment") == 0) - continue; - if (strcmp(id, "type") == 0) + if (_snd_conf_generic_id(id)) continue; if (strcmp(id, "card") == 0) { err = snd_config_get_integer(n, &card); diff --git a/src/control/control_shm.c b/src/control/control_shm.c index 40bc705d8036..bd07d4af503a 100644 --- a/src/control/control_shm.c +++ b/src/control/control_shm.c @@ -551,10 +551,7 @@ int _snd_ctl_shm_open(snd_ctl_t **handlep, char *name, snd_config_t *root, snd_c const char *id; if (snd_config_get_id(n, &id) < 0) continue; - if (strcmp(id, "comment") == 0) - continue; - if (strcmp(id, "type") == 0) - continue; + if (_snd_conf_generic_id(id)) if (strcmp(id, "server") == 0) { err = snd_config_get_string(n, &server); if (err < 0) { @@ -597,7 +594,7 @@ int _snd_ctl_shm_open(snd_ctl_t **handlep, char *name, snd_config_t *root, snd_c const char *id; if (snd_config_get_id(n, &id) < 0) continue; - if (strcmp(id, "comment") == 0) + if (_snd_conf_generic_id(id)) continue; if (strcmp(id, "host") == 0) continue; diff --git a/src/hwdep/hwdep_hw.c b/src/hwdep/hwdep_hw.c index 4314e32bade6..12528c55bac7 100644 --- a/src/hwdep/hwdep_hw.c +++ b/src/hwdep/hwdep_hw.c @@ -158,9 +158,7 @@ int _snd_hwdep_hw_open(snd_hwdep_t **hwdep, char *name, const char *id; if (snd_config_get_id(n, &id) < 0) continue; - if (strcmp(id, "comment") == 0) - continue; - if (strcmp(id, "type") == 0) + if (_snd_conf_generic_id(id)) continue; if (strcmp(id, "card") == 0) { err = snd_config_get_integer(n, &card); diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index e74e02fc568f..bc18954b92da 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -7059,18 +7059,6 @@ int snd_pcm_slave_conf(snd_config_t *root, snd_config_t *conf, return err; } - -int snd_pcm_conf_generic_id(const char *id) -{ - static const char ids[3][8] = { "comment", "type", "hint" }; - unsigned int k; - for (k = 0; k < sizeof(ids) / sizeof(ids[0]); ++k) { - if (strcmp(id, ids[k]) == 0) - return 1; - } - return 0; -} - static void snd_pcm_set_ptr(snd_pcm_t *pcm, snd_pcm_rbptr_t *rbptr, volatile snd_pcm_uframes_t *hw_ptr, int fd, off_t offset) { diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h index 394505f978ac..326618ecd0c0 100644 --- a/src/pcm/pcm_local.h +++ b/src/pcm/pcm_local.h @@ -262,8 +262,6 @@ struct _snd_pcm { snd1_pcm_areas_from_bufs #define snd_pcm_open_named_slave \ snd1_pcm_open_named_slave -#define snd_pcm_conf_generic_id \ - snd1_pcm_conf_generic_id #define snd_pcm_hw_open_fd \ snd1_pcm_hw_open_fd #define snd_pcm_wait_nocheck \ @@ -882,7 +880,8 @@ snd_pcm_open_slave(snd_pcm_t **pcmp, snd_config_t *root, return snd_pcm_open_named_slave(pcmp, NULL, root, conf, stream, mode, parent_conf); } -int snd_pcm_conf_generic_id(const char *id); + +#define snd_pcm_conf_generic_id(id) _snd_conf_generic_id(id)
int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, int fd, int mmap_emulation, int sync_ptr_ioctl); int __snd_pcm_mmap_emul_open(snd_pcm_t **pcmp, const char *name, diff --git a/src/rawmidi/rawmidi.c b/src/rawmidi/rawmidi.c index ac699b439b11..0c89b8b984b9 100644 --- a/src/rawmidi/rawmidi.c +++ b/src/rawmidi/rawmidi.c @@ -990,21 +990,3 @@ ssize_t snd_rawmidi_read(snd_rawmidi_t *rawmidi, void *buffer, size_t size) assert(buffer || size == 0); return (rawmidi->ops->read)(rawmidi, buffer, size); } - -#ifndef DOC_HIDDEN -int snd_rawmidi_conf_generic_id(const char *id) -{ - static const char ids[][8] = { - "comment", - "type", - "hint", - }; - unsigned int k; - - for (k = 0; k < sizeof ids / sizeof *ids; ++k) { - if (strcmp(id, ids[k]) == 0) - return 1; - } - return 0; -} -#endif diff --git a/src/rawmidi/rawmidi_local.h b/src/rawmidi/rawmidi_local.h index 3388502cece0..8992771eb5d3 100644 --- a/src/rawmidi/rawmidi_local.h +++ b/src/rawmidi/rawmidi_local.h @@ -58,4 +58,4 @@ int snd_rawmidi_virtual_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, const char *name, snd_seq_t *seq_handle, int port, int merge, int mode);
-int snd_rawmidi_conf_generic_id(const char *id); +#define snd_rawmidi_conf_generic_id(id) _snd_conf_generic_id(id) diff --git a/src/seq/seq_hw.c b/src/seq/seq_hw.c index 6cb31d6f4c25..d03336738944 100644 --- a/src/seq/seq_hw.c +++ b/src/seq/seq_hw.c @@ -546,9 +546,7 @@ int _snd_seq_hw_open(snd_seq_t **handlep, char *name, const char *id; if (snd_config_get_id(n, &id) < 0) continue; - if (strcmp(id, "comment") == 0) - continue; - if (strcmp(id, "type") == 0) + if (_snd_conf_generic_id(id)) continue; return -EINVAL; } diff --git a/src/timer/timer_hw.c b/src/timer/timer_hw.c index aa6a0b1b42f1..e833fc8cbb41 100644 --- a/src/timer/timer_hw.c +++ b/src/timer/timer_hw.c @@ -299,9 +299,7 @@ int _snd_timer_hw_open(snd_timer_t **timer, char *name, const char *id; if (snd_config_get_id(n, &id) < 0) continue; - if (strcmp(id, "comment") == 0) - continue; - if (strcmp(id, "type") == 0) + if (_snd_conf_generic_id(id)) continue; if (strcmp(id, "class") == 0) { err = snd_config_get_integer(n, &dev_class); diff --git a/src/timer/timer_query_hw.c b/src/timer/timer_query_hw.c index 9f62b78aeb2e..289ca52f2afa 100644 --- a/src/timer/timer_query_hw.c +++ b/src/timer/timer_query_hw.c @@ -134,9 +134,7 @@ int _snd_timer_query_hw_open(snd_timer_query_t **timer, char *name, const char *id; if (snd_config_get_id(n, &id) < 0) continue; - if (strcmp(id, "comment") == 0) - continue; - if (strcmp(id, "type") == 0) + if (_snd_conf_generic_id(id)) continue; SNDERR("Unexpected field %s", id); return -EINVAL;
Signed-off-by: Takashi Iwai tiwai@suse.de --- src/conf/alsa.conf | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/src/conf/alsa.conf b/src/conf/alsa.conf index 5c928e8afbcd..f22918fbbf83 100644 --- a/src/conf/alsa.conf +++ b/src/conf/alsa.conf @@ -345,6 +345,7 @@ ctl.sysdefault { name defaults.ctl.card } } + hint.description "Default control device" } ctl.default ctl.sysdefault
@@ -366,6 +367,7 @@ ctl.hw { } type hw card $CARD + hint.description "Direct control device" }
ctl.shm { @@ -408,6 +410,7 @@ rawmidi.default { name defaults.rawmidi.device } } + hint.description "Default raw MIDI device" }
rawmidi.hw { @@ -469,6 +472,7 @@ rawmidi.virtual {
seq.default { type hw + hint.description "Default sequencer device" }
seq.hw { @@ -502,6 +506,7 @@ hwdep.default { name defaults.hwdep.device } } + hint.description "Default hardware dependent device" }
hwdep.hw { @@ -536,6 +541,10 @@ hwdep.hw { type hw card $CARD device $DEV + hint { + description "Direct hardware dependent device" + device $DEV + } }
# @@ -572,7 +581,7 @@ timer.default { @func refer name defaults.timer.subdevice } - hint.description "Default direct hardware timer device" + hint.description "Default timer device" }
timer.hw { @@ -618,4 +627,8 @@ timer.hw { card $CARD device $DEV subdevice $SUBDEV + hint { + description "Direct timer device" + device $DEV + } }
participants (1)
-
Takashi Iwai