
alsa-project/alsa-lib issue #477 was opened from midzishi:
While fuzzing snd_config_load() a reproducible segmentation fault inside snd_config_delete() was discovered.
The root cause is incorrect cleanup logic in the configuration parser functions (parse_array_def() and parse_def()).
In multiple branches, existing configuration nodes are replaced incorrectly:
- The parser sometimes calls snd_config_delete(n) where n is NULL or a newly allocated node, instead of deleting the existing node returned by _snd_config_search() (variable g). - In other cases, a newly created node is added to the parent before its contents are successfully parsed. If parsing fails, the rollback path deletes this node explicitly, and later the parent deletes it again during recursive cleanup, so it causes double-free or corrupted linked list.
This results in corrupted parent–child relationships and eventually SEGV when snd_config_delete() tries to read config->refcount of an already freed node.
In both parse_array_def() and parse_def(), _snd_config_make_add() is called too early (before parsing child contents). On error, the parser deletes the child manually, but the parent will later delete it again during recursive cleanup.
Proposed fix: ``` diff --git a/src/conf.c b/src/conf.c index 905c8f4d..7e403192 100644 --- a/src/conf.c +++ b/src/conf.c @@ -1274,7 +1274,8 @@ static int parse_array_def(snd_config_t *parent, input_t *input, int *idx, int s snprintf(static_id, sizeof(static_id), "%i", *idx); if (_snd_config_search(parent, static_id, -1, &g) == 0) { if (override) { - snd_config_delete(n); + snd_config_delete(g); + g = NULL; } else { /* merge */ (*idx)++; @@ -1305,7 +1306,7 @@ static int parse_array_def(snd_config_t *parent, input_t *input, int *idx, int s goto __end; } } else { - err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, parent); + err = _snd_config_make(&n, &id, SND_CONFIG_TYPE_COMPOUND); if (err < 0) goto __end; } @@ -1328,6 +1329,10 @@ static int parse_array_def(snd_config_t *parent, input_t *input, int *idx, int s err = LOCAL_UNEXPECTED_CHAR; goto __end; } + if (!skip && n && !n->parent) { + err = snd_config_add(parent, n); + if (err < 0) { snd_config_delete(n); goto __end; } + } break; } default: @@ -1422,7 +1427,7 @@ static int parse_def(snd_config_t *parent, input_t *input, int skip, int overrid err = -ENOENT; goto __end; } - err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, parent); + err = _snd_config_make(&n, &id, SND_CONFIG_TYPE_COMPOUND); if (err < 0) goto __end; n->u.compound.join = true; @@ -1464,7 +1469,7 @@ static int parse_def(snd_config_t *parent, input_t *input, int skip, int overrid goto __end; } } else { - err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, parent); + err = _snd_config_make(&n, &id, SND_CONFIG_TYPE_COMPOUND); if (err < 0) goto __end; } @@ -1483,6 +1488,10 @@ static int parse_def(snd_config_t *parent, input_t *input, int skip, int overrid err = LOCAL_UNEXPECTED_CHAR; goto __end; } + if (!skip && n && !n->parent) { + err = snd_config_add(parent, n); + if (err < 0) { snd_config_delete(n); goto __end; } + } break; } default:
```
Issue URL : https://github.com/alsa-project/alsa-lib/issues/477 Repository URL: https://github.com/alsa-project/alsa-lib